@remnic/plugin-pi 9.3.638 → 9.3.640
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/dist/index.js +145 -68
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -462,26 +462,30 @@ function createRemnicPiExtension(options = {}) {
|
|
|
462
462
|
const sessionStates = /* @__PURE__ */ new Map();
|
|
463
463
|
return async function remnicPiExtension2(pi) {
|
|
464
464
|
pi.on("session_start", async (_event, ctx) => {
|
|
465
|
-
const
|
|
466
|
-
|
|
465
|
+
const session = snapshotPiContext(ctx, { includeSessionHistory: true });
|
|
466
|
+
if (!session) return;
|
|
467
|
+
const { state } = getSessionState(session.sessionKey, sessionStates);
|
|
468
|
+
restoreObservedState(session, state.observedHashes);
|
|
467
469
|
if (!config.statusEnabled) return;
|
|
468
|
-
await setStatus(
|
|
470
|
+
await setStatus(session, client, config);
|
|
469
471
|
});
|
|
470
472
|
pi.on("context", async (event, ctx) => {
|
|
473
|
+
const session = snapshotPiContext(ctx);
|
|
474
|
+
if (!session) return;
|
|
471
475
|
if (!config.recallEnabled || !config.authToken) return;
|
|
472
476
|
const recallTarget = latestUserRecallTarget(Array.isArray(event.messages) ? event.messages : []);
|
|
473
477
|
if (!recallTarget) return;
|
|
474
478
|
const { query } = recallTarget;
|
|
475
|
-
const
|
|
476
|
-
const { state } = getSessionState(ctx, sessionStates);
|
|
479
|
+
const { state } = getSessionState(session.sessionKey, sessionStates);
|
|
477
480
|
if (recallTarget.dedupeKey === state.lastInjectedRecallKey) return;
|
|
478
481
|
try {
|
|
479
|
-
const recalled = await client.recall(query, sessionKey,
|
|
482
|
+
const recalled = await client.recall(query, session.sessionKey, session.cwd);
|
|
480
483
|
const context = trimContext(recalled.context ?? "", config.recallBudgetChars);
|
|
481
484
|
if (!context) return;
|
|
482
485
|
state.lastInjectedRecallKey = recallTarget.dedupeKey;
|
|
483
486
|
return {
|
|
484
487
|
messages: [
|
|
488
|
+
...event.messages,
|
|
485
489
|
{
|
|
486
490
|
role: "user",
|
|
487
491
|
content: [{ type: "text", text: `Remnic recalled context for this turn:
|
|
@@ -489,61 +493,68 @@ function createRemnicPiExtension(options = {}) {
|
|
|
489
493
|
${context}` }],
|
|
490
494
|
remnicInjected: true,
|
|
491
495
|
timestamp: Date.now()
|
|
492
|
-
}
|
|
493
|
-
...event.messages
|
|
496
|
+
}
|
|
494
497
|
]
|
|
495
498
|
};
|
|
496
499
|
} catch (err) {
|
|
497
|
-
notify(
|
|
500
|
+
session.notify(`Remnic recall unavailable: ${errorMessage(err)}`, "warning");
|
|
498
501
|
}
|
|
499
502
|
});
|
|
500
503
|
pi.on("message_end", async (event, ctx) => {
|
|
504
|
+
const session = snapshotPiContext(ctx);
|
|
505
|
+
if (!session) return;
|
|
501
506
|
if (!config.observeEnabled || !isUserMessage(event.message)) return;
|
|
502
|
-
const { state } = getSessionState(
|
|
503
|
-
await
|
|
507
|
+
const { state } = getSessionState(session.sessionKey, sessionStates);
|
|
508
|
+
await observeMessagesForSession(session, client, [event.message], state.observedHashes, state.liveObservedReplayKeys);
|
|
504
509
|
});
|
|
505
510
|
pi.on("turn_end", async (event, ctx) => {
|
|
511
|
+
const session = snapshotPiContext(ctx);
|
|
512
|
+
if (!session) return;
|
|
506
513
|
if (!config.observeEnabled) return;
|
|
507
514
|
const messages = [event.message, ...Array.isArray(event.toolResults) ? event.toolResults : []];
|
|
508
|
-
const { state } = getSessionState(
|
|
509
|
-
await
|
|
515
|
+
const { state } = getSessionState(session.sessionKey, sessionStates);
|
|
516
|
+
await observeMessagesForSession(session, client, messages, state.observedHashes, state.liveObservedReplayKeys);
|
|
510
517
|
});
|
|
511
518
|
pi.on("session_shutdown", async (_event, ctx) => {
|
|
512
|
-
const
|
|
519
|
+
const session = snapshotPiContext(ctx, { includeSessionHistory: true });
|
|
520
|
+
if (!session) return;
|
|
521
|
+
const { sessionKey, state } = getSessionState(session.sessionKey, sessionStates);
|
|
513
522
|
if (config.observeEnabled) {
|
|
514
|
-
const
|
|
515
|
-
const
|
|
516
|
-
|
|
517
|
-
|
|
523
|
+
const branchMessages = branchMessagesWithEntryIdentity(session.branch);
|
|
524
|
+
const unobservedBranchMessages = skipLiveObservedReplayMessages(session.sessionKey, branchMessages, state.liveObservedReplayKeys);
|
|
525
|
+
if (unobservedBranchMessages.length > 0) {
|
|
526
|
+
await observeMessagesForSession(session, client, unobservedBranchMessages, state.observedHashes);
|
|
527
|
+
}
|
|
518
528
|
}
|
|
519
529
|
persistObservedState(pi, state.observedHashes);
|
|
520
530
|
sessionStates.delete(sessionKey);
|
|
521
531
|
});
|
|
522
532
|
pi.on("session_before_compact", async (event, ctx) => {
|
|
533
|
+
const session = snapshotPiContext(ctx);
|
|
534
|
+
if (!session) return;
|
|
523
535
|
if (!config.compactionEnabled || !config.authToken) return;
|
|
524
|
-
const sessionKey = sessionKeyFromContext(ctx);
|
|
525
536
|
const preparation = event.preparation ?? {};
|
|
526
537
|
try {
|
|
527
|
-
await client.lcmCompactionFlush(sessionKey);
|
|
538
|
+
await client.lcmCompactionFlush(session.sessionKey);
|
|
528
539
|
} catch (err) {
|
|
529
|
-
notify(
|
|
540
|
+
session.notify(`Remnic LCM flush failed: ${errorMessage(err)}`, "warning");
|
|
530
541
|
return;
|
|
531
542
|
}
|
|
532
543
|
const tokensBefore = finiteTokenCount(preparation.tokensBefore);
|
|
533
544
|
const tokensAfter = finiteTokenCount(preparation.tokensAfter);
|
|
534
545
|
if (tokensBefore !== null && tokensAfter !== null) {
|
|
535
546
|
try {
|
|
536
|
-
await client.lcmCompactionRecord(sessionKey, tokensBefore, tokensAfter);
|
|
547
|
+
await client.lcmCompactionRecord(session.sessionKey, tokensBefore, tokensAfter);
|
|
537
548
|
} catch (err) {
|
|
538
|
-
notify(
|
|
549
|
+
session.notify(`Remnic LCM compaction token record failed: ${errorMessage(err)}`, "warning");
|
|
539
550
|
}
|
|
540
551
|
}
|
|
541
552
|
const summary = buildCompactionSummary(preparation);
|
|
542
553
|
if (!summary.trim()) return;
|
|
543
554
|
try {
|
|
544
|
-
await client.contextCheckpoint(sessionKey, summary);
|
|
555
|
+
await client.contextCheckpoint(session.sessionKey, summary);
|
|
545
556
|
} catch (err) {
|
|
546
|
-
notify(
|
|
557
|
+
session.notify(`Remnic context checkpoint failed: ${errorMessage(err)}`, "warning");
|
|
547
558
|
}
|
|
548
559
|
const details = fileDetailsFromPreparation(preparation);
|
|
549
560
|
return {
|
|
@@ -570,68 +581,70 @@ async function remnicPiExtension(pi) {
|
|
|
570
581
|
function registerCommands(pi, client, config) {
|
|
571
582
|
pi.registerCommand("remnic-status", {
|
|
572
583
|
description: "Check Remnic daemon status",
|
|
573
|
-
handler: commandHandler(async (_args,
|
|
584
|
+
handler: commandHandler(async (_args, _ctx, session) => {
|
|
574
585
|
const health = await client.health();
|
|
575
|
-
notify(
|
|
586
|
+
session.notify(`Remnic ${health.ok ? "healthy" : "unhealthy"} at ${config.remnicDaemonUrl}`, health.ok ? "success" : "warning");
|
|
576
587
|
})
|
|
577
588
|
});
|
|
578
589
|
pi.registerCommand("remnic-recall", {
|
|
579
590
|
description: "Recall Remnic context for a query",
|
|
580
|
-
handler: commandHandler(async (args,
|
|
591
|
+
handler: commandHandler(async (args, _ctx, session) => {
|
|
581
592
|
const query = args.trim();
|
|
582
593
|
if (!query) {
|
|
583
|
-
notify(
|
|
594
|
+
session.notify("Usage: /remnic-recall <query>", "warning");
|
|
584
595
|
return;
|
|
585
596
|
}
|
|
586
|
-
const result = await client.recall(query,
|
|
587
|
-
notify(
|
|
597
|
+
const result = await client.recall(query, session.sessionKey, session.cwd);
|
|
598
|
+
session.notify(trimContext(result.context ?? "(no Remnic context)", MAX_CONTEXT_CHARS), "info");
|
|
588
599
|
})
|
|
589
600
|
});
|
|
590
601
|
pi.registerCommand("remnic-remember", {
|
|
591
602
|
description: "Store a Remnic memory",
|
|
592
|
-
handler: commandHandler(async (args,
|
|
603
|
+
handler: commandHandler(async (args, _ctx, session) => {
|
|
593
604
|
const content = args.trim();
|
|
594
605
|
if (!content) {
|
|
595
|
-
notify(
|
|
606
|
+
session.notify("Usage: /remnic-remember <memory>", "warning");
|
|
596
607
|
return;
|
|
597
608
|
}
|
|
598
|
-
await client.storeMemory(content,
|
|
599
|
-
notify(
|
|
609
|
+
await client.storeMemory(content, session.sessionKey);
|
|
610
|
+
session.notify("Stored Remnic memory", "success");
|
|
600
611
|
})
|
|
601
612
|
});
|
|
602
613
|
pi.registerCommand("remnic-lcm-search", {
|
|
603
614
|
description: "Search Remnic LCM archived Pi context",
|
|
604
|
-
handler: commandHandler(async (args,
|
|
615
|
+
handler: commandHandler(async (args, _ctx, session) => {
|
|
605
616
|
const query = args.trim();
|
|
606
617
|
if (!query) {
|
|
607
|
-
notify(
|
|
618
|
+
session.notify("Usage: /remnic-lcm-search <query>", "warning");
|
|
608
619
|
return;
|
|
609
620
|
}
|
|
610
|
-
const result = await client.lcmSearch(query,
|
|
611
|
-
notify(
|
|
621
|
+
const result = await client.lcmSearch(query, session.sessionKey);
|
|
622
|
+
session.notify(JSON.stringify(result, null, 2), "info");
|
|
612
623
|
})
|
|
613
624
|
});
|
|
614
625
|
pi.registerCommand("remnic-why", {
|
|
615
626
|
description: "Explain the last Remnic recall",
|
|
616
|
-
handler: commandHandler(async (_args,
|
|
617
|
-
const result = await client.recallExplain(
|
|
618
|
-
notify(
|
|
627
|
+
handler: commandHandler(async (_args, _ctx, session) => {
|
|
628
|
+
const result = await client.recallExplain(session.sessionKey);
|
|
629
|
+
session.notify(JSON.stringify(result, null, 2), "info");
|
|
619
630
|
})
|
|
620
631
|
});
|
|
621
632
|
pi.registerCommand("remnic-compact", {
|
|
622
633
|
description: "Trigger Pi compaction with Remnic LCM coordination",
|
|
623
|
-
handler: commandHandler(async (_args,
|
|
624
|
-
|
|
625
|
-
notify(
|
|
634
|
+
handler: commandHandler(async (_args, _ctx, session) => {
|
|
635
|
+
session.compact?.();
|
|
636
|
+
session.notify("Compaction requested", "info");
|
|
626
637
|
})
|
|
627
638
|
});
|
|
628
639
|
}
|
|
629
640
|
function commandHandler(handler) {
|
|
630
641
|
return async (args, ctx) => {
|
|
642
|
+
const session = snapshotPiContext(ctx);
|
|
643
|
+
if (!session) return;
|
|
631
644
|
try {
|
|
632
|
-
await handler(args, ctx);
|
|
645
|
+
await handler(args, ctx, session);
|
|
633
646
|
} catch (err) {
|
|
634
|
-
notify(
|
|
647
|
+
session.notify(`Remnic command failed: ${errorMessage(err)}`, "warning");
|
|
635
648
|
}
|
|
636
649
|
};
|
|
637
650
|
}
|
|
@@ -651,13 +664,19 @@ async function registerMcpTools(pi, client, config) {
|
|
|
651
664
|
description: tool.description ?? `Call ${tool.name}`,
|
|
652
665
|
parameters: toPiToolParametersSchema(tool.inputSchema),
|
|
653
666
|
async execute(_toolCallId, params, _signal, _onUpdate, ctx) {
|
|
654
|
-
const
|
|
667
|
+
const session = snapshotPiContext(ctx);
|
|
668
|
+
if (!session) {
|
|
669
|
+
return {
|
|
670
|
+
content: [{ type: "text", text: "Remnic tool skipped because the Pi context is no longer active." }],
|
|
671
|
+
details: { skipped: true, reason: "stale_context" }
|
|
672
|
+
};
|
|
673
|
+
}
|
|
655
674
|
const safeParams = stripSessionOwnedRuntimeFields(params ?? {});
|
|
656
675
|
const result = await client.mcpTool(tool.name, {
|
|
657
676
|
...safeParams,
|
|
658
|
-
sessionKey,
|
|
677
|
+
sessionKey: session.sessionKey,
|
|
659
678
|
namespace: config.namespace,
|
|
660
|
-
cwd:
|
|
679
|
+
cwd: session.cwd
|
|
661
680
|
});
|
|
662
681
|
return {
|
|
663
682
|
content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
|
|
@@ -729,8 +748,7 @@ function isRecord(value) {
|
|
|
729
748
|
function isUserMessage(message) {
|
|
730
749
|
return isRecord(message) && message.role === "user";
|
|
731
750
|
}
|
|
732
|
-
function getSessionState(
|
|
733
|
-
const sessionKey = sessionKeyFromContext(ctx);
|
|
751
|
+
function getSessionState(sessionKey, states) {
|
|
734
752
|
let state = states.get(sessionKey);
|
|
735
753
|
if (!state) {
|
|
736
754
|
state = {
|
|
@@ -751,28 +769,32 @@ function pruneSessionStates(states) {
|
|
|
751
769
|
}
|
|
752
770
|
}
|
|
753
771
|
async function observeMessages(ctx, client, rawMessages, observedHashes, liveObservedReplayKeys) {
|
|
754
|
-
const
|
|
772
|
+
const session = snapshotPiContext(ctx);
|
|
773
|
+
if (!session) return;
|
|
774
|
+
await observeMessagesForSession(session, client, rawMessages, observedHashes, liveObservedReplayKeys);
|
|
775
|
+
}
|
|
776
|
+
async function observeMessagesForSession(session, client, rawMessages, observedHashes, liveObservedReplayKeys) {
|
|
755
777
|
const messages = [];
|
|
756
778
|
const pendingHashes = /* @__PURE__ */ new Set();
|
|
757
779
|
for (const raw of rawMessages) {
|
|
758
780
|
const message = toObserveMessage(raw);
|
|
759
781
|
if (!message) continue;
|
|
760
|
-
const hash = observedMessageDedupeKey(message, sessionKey);
|
|
782
|
+
const hash = observedMessageDedupeKey(message, session.sessionKey);
|
|
761
783
|
if (hash && (observedHashes.has(hash) || pendingHashes.has(hash))) continue;
|
|
762
784
|
if (hash) pendingHashes.add(hash);
|
|
763
785
|
messages.push(message);
|
|
764
786
|
}
|
|
765
787
|
if (messages.length === 0) return;
|
|
766
788
|
try {
|
|
767
|
-
await client.observe(sessionKey,
|
|
789
|
+
await client.observe(session.sessionKey, session.cwd, messages);
|
|
768
790
|
for (const hash of pendingHashes) rememberObservedHash(observedHashes, hash);
|
|
769
791
|
if (liveObservedReplayKeys) {
|
|
770
792
|
for (const message of messages) {
|
|
771
|
-
rememberLiveObservedReplayKey(liveObservedReplayKeys, liveReplayKey(message, sessionKey));
|
|
793
|
+
rememberLiveObservedReplayKey(liveObservedReplayKeys, liveReplayKey(message, session.sessionKey));
|
|
772
794
|
}
|
|
773
795
|
}
|
|
774
796
|
} catch (err) {
|
|
775
|
-
notify(
|
|
797
|
+
session.notify(`Remnic observe failed: ${errorMessage(err)}`, "warning");
|
|
776
798
|
}
|
|
777
799
|
}
|
|
778
800
|
function buildCompactionSummary(preparation) {
|
|
@@ -808,8 +830,8 @@ function fileDetailsFromPreparation(preparation) {
|
|
|
808
830
|
modifiedFiles: Array.from(modified).sort()
|
|
809
831
|
};
|
|
810
832
|
}
|
|
811
|
-
function restoreObservedState(
|
|
812
|
-
for (const entry of
|
|
833
|
+
function restoreObservedState(session, observedHashes) {
|
|
834
|
+
for (const entry of session.entries) {
|
|
813
835
|
if (entry?.type !== "custom" || entry.customType !== STATE_CUSTOM_TYPE) continue;
|
|
814
836
|
const hashes = entry.data?.observedHashes;
|
|
815
837
|
if (Array.isArray(hashes)) {
|
|
@@ -838,9 +860,8 @@ function consumeLiveObservedReplayKey(liveObservedReplayKeys, key) {
|
|
|
838
860
|
else liveObservedReplayKeys.set(key, count - 1);
|
|
839
861
|
return true;
|
|
840
862
|
}
|
|
841
|
-
function skipLiveObservedReplayMessages(
|
|
863
|
+
function skipLiveObservedReplayMessages(sessionKey, rawMessages, liveObservedReplayKeys) {
|
|
842
864
|
if (liveObservedReplayKeys.size === 0) return rawMessages;
|
|
843
|
-
const sessionKey = sessionKeyFromContext(ctx);
|
|
844
865
|
const unobserved = [];
|
|
845
866
|
for (const raw of rawMessages) {
|
|
846
867
|
const message = toObserveMessage(raw);
|
|
@@ -861,14 +882,74 @@ function persistObservedState(pi, observedHashes) {
|
|
|
861
882
|
recordedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
862
883
|
});
|
|
863
884
|
}
|
|
864
|
-
async function setStatus(
|
|
885
|
+
async function setStatus(session, client, config) {
|
|
865
886
|
try {
|
|
866
887
|
await client.health({ timeoutMs: config.startupRequestTimeoutMs });
|
|
867
|
-
|
|
888
|
+
session.setStatus("remnic", `Remnic ${config.namespace ? `(${config.namespace})` : "ready"}`);
|
|
889
|
+
} catch {
|
|
890
|
+
session.setStatus("remnic", "Remnic offline");
|
|
891
|
+
}
|
|
892
|
+
}
|
|
893
|
+
function snapshotPiContext(ctx, options = {}) {
|
|
894
|
+
const sessionKey = safeSessionKeyFromContext(ctx);
|
|
895
|
+
if (!sessionKey) return null;
|
|
896
|
+
const cwd = safeStringRead(() => ctx?.cwd, "");
|
|
897
|
+
const hasUI = safeRead(() => ctx?.hasUI, void 0) === false;
|
|
898
|
+
const ui = hasUI ? void 0 : safeRead(() => ctx?.ui, void 0);
|
|
899
|
+
const compact = safeRead(() => ctx?.compact, void 0);
|
|
900
|
+
const includeSessionHistory = options.includeSessionHistory === true;
|
|
901
|
+
return {
|
|
902
|
+
sessionKey,
|
|
903
|
+
cwd,
|
|
904
|
+
entries: includeSessionHistory ? safeEntries(ctx) : [],
|
|
905
|
+
branch: includeSessionHistory ? safeBranch(ctx) : [],
|
|
906
|
+
notify: makeNotifier(ui, hasUI),
|
|
907
|
+
setStatus: makeStatusSetter(ui, hasUI),
|
|
908
|
+
compact: typeof compact === "function" ? () => compact.call(ctx) : void 0
|
|
909
|
+
};
|
|
910
|
+
}
|
|
911
|
+
function safeSessionKeyFromContext(ctx) {
|
|
912
|
+
try {
|
|
913
|
+
return sessionKeyFromContext(ctx);
|
|
914
|
+
} catch {
|
|
915
|
+
return null;
|
|
916
|
+
}
|
|
917
|
+
}
|
|
918
|
+
function makeNotifier(ui, hasUI) {
|
|
919
|
+
if (hasUI || !isRecord(ui) || typeof ui.notify !== "function") {
|
|
920
|
+
return () => void 0;
|
|
921
|
+
}
|
|
922
|
+
const notifyFn = ui.notify;
|
|
923
|
+
return (message, level) => {
|
|
924
|
+
try {
|
|
925
|
+
notifyFn.call(ui, message, level);
|
|
926
|
+
} catch {
|
|
927
|
+
}
|
|
928
|
+
};
|
|
929
|
+
}
|
|
930
|
+
function makeStatusSetter(ui, hasUI) {
|
|
931
|
+
if (hasUI || !isRecord(ui) || typeof ui.setStatus !== "function") {
|
|
932
|
+
return () => void 0;
|
|
933
|
+
}
|
|
934
|
+
const setStatusFn = ui.setStatus;
|
|
935
|
+
return (key, value) => {
|
|
936
|
+
try {
|
|
937
|
+
setStatusFn.call(ui, key, value);
|
|
938
|
+
} catch {
|
|
939
|
+
}
|
|
940
|
+
};
|
|
941
|
+
}
|
|
942
|
+
function safeRead(read, fallback) {
|
|
943
|
+
try {
|
|
944
|
+
return read();
|
|
868
945
|
} catch {
|
|
869
|
-
|
|
946
|
+
return fallback;
|
|
870
947
|
}
|
|
871
948
|
}
|
|
949
|
+
function safeStringRead(read, fallback) {
|
|
950
|
+
const value = safeRead(read, fallback);
|
|
951
|
+
return typeof value === "string" ? value : fallback;
|
|
952
|
+
}
|
|
872
953
|
function safeEntries(ctx) {
|
|
873
954
|
try {
|
|
874
955
|
const entries = ctx.sessionManager?.getEntries?.();
|
|
@@ -918,10 +999,6 @@ function trimContext(value, budget) {
|
|
|
918
999
|
if (budget <= TRUNCATION_NOTICE.length) return TRUNCATION_NOTICE.slice(0, budget);
|
|
919
1000
|
return `${value.slice(0, budget - TRUNCATION_NOTICE.length)}${TRUNCATION_NOTICE}`;
|
|
920
1001
|
}
|
|
921
|
-
function notify(ctx, message, level) {
|
|
922
|
-
if (ctx?.hasUI === false) return;
|
|
923
|
-
ctx?.ui?.notify?.(message, level);
|
|
924
|
-
}
|
|
925
1002
|
function errorMessage(err) {
|
|
926
1003
|
return err instanceof Error ? err.message : String(err);
|
|
927
1004
|
}
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/config.ts","../src/client.ts","../src/messages.ts"],"sourcesContent":["import { Type, type TSchema } from \"@sinclair/typebox\";\n\nimport { loadConfig, type LoadConfigOptions, type RemnicPiConfig } from \"./config.js\";\nimport { RemnicClient, type McpTool, type ObserveMessage } from \"./client.js\";\nimport {\n hashObservedMessage,\n latestUserRecallTarget,\n observedMessageDedupeKey,\n sessionKeyFromContext,\n summarizeMessages,\n textFromMessage,\n toObserveMessage,\n} from \"./messages.js\";\n\ntype PiApi = {\n on(event: string, handler: (event: any, ctx: any) => unknown | Promise<unknown>): void;\n registerCommand(name: string, options: { description?: string; handler: (args: string, ctx: any) => Promise<void> }): void;\n registerTool(tool: Record<string, unknown>): void;\n appendEntry<T = unknown>(customType: string, data?: T): void;\n};\n\nexport interface RemnicPiExtensionOptions extends LoadConfigOptions {\n config?: RemnicPiConfig;\n}\n\nconst STATE_CUSTOM_TYPE = \"remnic_state\";\nconst MAX_OBSERVED_HASHES = 2000;\nconst MAX_SESSION_STATES = 50;\nconst MAX_CONTEXT_CHARS = 12000;\nconst TRUNCATION_NOTICE = \"\\n\\n[Remnic context truncated]\";\nconst SESSION_OWNED_FIELDS = new Set([\"sessionKey\", \"namespace\", \"cwd\"]);\n\ntype PiSessionState = {\n observedHashes: Set<string>;\n liveObservedReplayKeys: Map<string, number>;\n lastInjectedRecallKey: string;\n};\n\nexport function createRemnicPiExtension(options: RemnicPiExtensionOptions = {}) {\n const config = options.config ?? loadConfig(options);\n const client = new RemnicClient(config);\n const sessionStates = new Map<string, PiSessionState>();\n\n return async function remnicPiExtension(pi: PiApi): Promise<void> {\n pi.on(\"session_start\", async (_event, ctx) => {\n const { state } = getSessionState(ctx, sessionStates);\n restoreObservedState(ctx, state.observedHashes);\n if (!config.statusEnabled) return;\n await setStatus(ctx, client, config);\n });\n\n pi.on(\"context\", async (event, ctx) => {\n if (!config.recallEnabled || !config.authToken) return;\n const recallTarget = latestUserRecallTarget(Array.isArray(event.messages) ? event.messages : []);\n if (!recallTarget) return;\n const { query } = recallTarget;\n const sessionKey = sessionKeyFromContext(ctx);\n const { state } = getSessionState(ctx, sessionStates);\n if (recallTarget.dedupeKey === state.lastInjectedRecallKey) return;\n\n try {\n const recalled = await client.recall(query, sessionKey, ctx.cwd);\n const context = trimContext(recalled.context ?? \"\", config.recallBudgetChars);\n if (!context) return;\n state.lastInjectedRecallKey = recallTarget.dedupeKey;\n return {\n messages: [\n {\n role: \"user\",\n content: [{ type: \"text\", text: `Remnic recalled context for this turn:\\n\\n${context}` }],\n remnicInjected: true,\n timestamp: Date.now(),\n },\n ...event.messages,\n ],\n };\n } catch (err) {\n notify(ctx, `Remnic recall unavailable: ${errorMessage(err)}`, \"warning\");\n }\n });\n\n pi.on(\"message_end\", async (event, ctx) => {\n if (!config.observeEnabled || !isUserMessage(event.message)) return;\n const { state } = getSessionState(ctx, sessionStates);\n await observeMessages(ctx, client, [event.message], state.observedHashes, state.liveObservedReplayKeys);\n });\n\n pi.on(\"turn_end\", async (event, ctx) => {\n if (!config.observeEnabled) return;\n const messages = [event.message, ...(Array.isArray(event.toolResults) ? event.toolResults : [])];\n const { state } = getSessionState(ctx, sessionStates);\n await observeMessages(ctx, client, messages, state.observedHashes, state.liveObservedReplayKeys);\n });\n\n pi.on(\"session_shutdown\", async (_event, ctx) => {\n const { sessionKey, state } = getSessionState(ctx, sessionStates);\n if (config.observeEnabled) {\n const branch = safeBranch(ctx);\n const branchMessages = branchMessagesWithEntryIdentity(branch);\n const unobservedBranchMessages = skipLiveObservedReplayMessages(ctx, branchMessages, state.liveObservedReplayKeys);\n if (unobservedBranchMessages.length > 0) await observeMessages(ctx, client, unobservedBranchMessages, state.observedHashes);\n }\n persistObservedState(pi, state.observedHashes);\n sessionStates.delete(sessionKey);\n });\n\n pi.on(\"session_before_compact\", async (event, ctx) => {\n if (!config.compactionEnabled || !config.authToken) return;\n const sessionKey = sessionKeyFromContext(ctx);\n const preparation = event.preparation ?? {};\n try {\n await client.lcmCompactionFlush(sessionKey);\n } catch (err) {\n notify(ctx, `Remnic LCM flush failed: ${errorMessage(err)}`, \"warning\");\n return;\n }\n\n const tokensBefore = finiteTokenCount(preparation.tokensBefore);\n const tokensAfter = finiteTokenCount(preparation.tokensAfter);\n if (tokensBefore !== null && tokensAfter !== null) {\n try {\n await client.lcmCompactionRecord(sessionKey, tokensBefore, tokensAfter);\n } catch (err) {\n notify(ctx, `Remnic LCM compaction token record failed: ${errorMessage(err)}`, \"warning\");\n }\n }\n\n const summary = buildCompactionSummary(preparation);\n if (!summary.trim()) return;\n try {\n await client.contextCheckpoint(sessionKey, summary);\n } catch (err) {\n notify(ctx, `Remnic context checkpoint failed: ${errorMessage(err)}`, \"warning\");\n }\n const details = fileDetailsFromPreparation(preparation);\n return {\n compaction: {\n summary,\n firstKeptEntryId: preparation.firstKeptEntryId,\n tokensBefore: preparation.tokensBefore,\n details: {\n ...details,\n remnic: { version: 1, source: \"pi\" },\n },\n },\n };\n });\n\n registerCommands(pi, client, config);\n if (config.mcpToolsEnabled && config.authToken) {\n await registerMcpTools(pi, client, config);\n }\n };\n}\n\nexport default async function remnicPiExtension(pi: PiApi): Promise<void> {\n await createRemnicPiExtension()(pi);\n}\n\nfunction registerCommands(pi: PiApi, client: RemnicClient, config: RemnicPiConfig): void {\n pi.registerCommand(\"remnic-status\", {\n description: \"Check Remnic daemon status\",\n handler: commandHandler(async (_args, ctx) => {\n const health = await client.health();\n notify(ctx, `Remnic ${health.ok ? \"healthy\" : \"unhealthy\"} at ${config.remnicDaemonUrl}`, health.ok ? \"success\" : \"warning\");\n }),\n });\n\n pi.registerCommand(\"remnic-recall\", {\n description: \"Recall Remnic context for a query\",\n handler: commandHandler(async (args, ctx) => {\n const query = args.trim();\n if (!query) {\n notify(ctx, \"Usage: /remnic-recall <query>\", \"warning\");\n return;\n }\n const result = await client.recall(query, sessionKeyFromContext(ctx), ctx.cwd);\n notify(ctx, trimContext(result.context ?? \"(no Remnic context)\", MAX_CONTEXT_CHARS), \"info\");\n }),\n });\n\n pi.registerCommand(\"remnic-remember\", {\n description: \"Store a Remnic memory\",\n handler: commandHandler(async (args, ctx) => {\n const content = args.trim();\n if (!content) {\n notify(ctx, \"Usage: /remnic-remember <memory>\", \"warning\");\n return;\n }\n await client.storeMemory(content, sessionKeyFromContext(ctx));\n notify(ctx, \"Stored Remnic memory\", \"success\");\n }),\n });\n\n pi.registerCommand(\"remnic-lcm-search\", {\n description: \"Search Remnic LCM archived Pi context\",\n handler: commandHandler(async (args, ctx) => {\n const query = args.trim();\n if (!query) {\n notify(ctx, \"Usage: /remnic-lcm-search <query>\", \"warning\");\n return;\n }\n const result = await client.lcmSearch(query, sessionKeyFromContext(ctx));\n notify(ctx, JSON.stringify(result, null, 2), \"info\");\n }),\n });\n\n pi.registerCommand(\"remnic-why\", {\n description: \"Explain the last Remnic recall\",\n handler: commandHandler(async (_args, ctx) => {\n const result = await client.recallExplain(sessionKeyFromContext(ctx));\n notify(ctx, JSON.stringify(result, null, 2), \"info\");\n }),\n });\n\n pi.registerCommand(\"remnic-compact\", {\n description: \"Trigger Pi compaction with Remnic LCM coordination\",\n handler: commandHandler(async (_args, ctx) => {\n ctx.compact?.();\n notify(ctx, \"Compaction requested\", \"info\");\n }),\n });\n}\n\nfunction commandHandler(handler: (args: string, ctx: any) => Promise<void>): (args: string, ctx: any) => Promise<void> {\n return async (args, ctx) => {\n try {\n await handler(args, ctx);\n } catch (err) {\n notify(ctx, `Remnic command failed: ${errorMessage(err)}`, \"warning\");\n }\n };\n}\n\nasync function registerMcpTools(pi: PiApi, client: RemnicClient, config: RemnicPiConfig): Promise<void> {\n let tools: McpTool[] = [];\n try {\n tools = await client.mcpListTools({ timeoutMs: config.startupRequestTimeoutMs });\n } catch {\n return;\n }\n for (const tool of tools) {\n if (!tool.name.startsWith(\"remnic.\")) continue;\n const piToolName = tool.name.replace(/^remnic\\./, \"remnic_\").replace(/[^a-zA-Z0-9_]/g, \"_\");\n pi.registerTool({\n name: piToolName,\n label: tool.name,\n description: tool.description ?? `Call ${tool.name}`,\n parameters: toPiToolParametersSchema(tool.inputSchema),\n async execute(_toolCallId: string, params: Record<string, unknown>, _signal: AbortSignal | undefined, _onUpdate: unknown, ctx: any) {\n const sessionKey = sessionKeyFromContext(ctx);\n const safeParams = stripSessionOwnedRuntimeFields(params ?? {}) as Record<string, unknown>;\n const result = await client.mcpTool(tool.name, {\n ...safeParams,\n sessionKey,\n namespace: config.namespace,\n cwd: ctx.cwd,\n });\n return {\n content: [{ type: \"text\", text: JSON.stringify(result, null, 2) }],\n details: result,\n };\n },\n });\n }\n}\n\nexport function toPiToolParametersSchema(inputSchema: unknown): TSchema {\n return Type.Unsafe(stripSessionOwnedSchemaFields(inputSchema));\n}\n\nexport function stripSessionOwnedSchemaFields(inputSchema: unknown): Record<string, unknown> {\n if (!isRecord(inputSchema)) {\n return { type: \"object\", properties: {}, additionalProperties: true };\n }\n return stripSessionOwnedSchemaNode(inputSchema) as Record<string, unknown>;\n}\n\nfunction stripSessionOwnedSchemaNode(value: unknown): unknown {\n if (Array.isArray(value)) {\n return value.map((entry) => stripSessionOwnedSchemaNode(entry));\n }\n if (!isRecord(value)) {\n return value;\n }\n const schema: Record<string, unknown> = { ...value };\n if (isRecord(value.properties)) {\n const properties: Record<string, unknown> = {};\n for (const [key, property] of Object.entries(value.properties)) {\n if (SESSION_OWNED_FIELDS.has(key)) continue;\n properties[key] = stripSessionOwnedSchemaNode(property);\n }\n schema.properties = properties;\n }\n if (Array.isArray(value.required)) {\n schema.required = value.required.filter(\n (field) => typeof field !== \"string\" || !SESSION_OWNED_FIELDS.has(field),\n );\n }\n for (const key of [\"items\", \"additionalProperties\", \"not\"] as const) {\n if (isRecord(value[key])) {\n schema[key] = stripSessionOwnedSchemaNode(value[key]);\n }\n }\n for (const key of [\"oneOf\", \"anyOf\", \"allOf\"] as const) {\n if (Array.isArray(value[key])) {\n schema[key] = value[key].map((entry) => stripSessionOwnedSchemaNode(entry));\n }\n }\n return schema;\n}\n\nexport function stripSessionOwnedRuntimeFields(value: unknown): unknown {\n if (Array.isArray(value)) {\n return value.map((entry) => stripSessionOwnedRuntimeFields(entry));\n }\n if (!isRecord(value)) {\n return value;\n }\n const sanitized: Record<string, unknown> = {};\n for (const [key, child] of Object.entries(value)) {\n if (SESSION_OWNED_FIELDS.has(key)) continue;\n sanitized[key] = stripSessionOwnedRuntimeFields(child);\n }\n return sanitized;\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return !!value && typeof value === \"object\" && !Array.isArray(value);\n}\n\nfunction isUserMessage(message: unknown): boolean {\n return isRecord(message) && message.role === \"user\";\n}\n\nfunction getSessionState(ctx: any, states: Map<string, PiSessionState>): { sessionKey: string; state: PiSessionState } {\n const sessionKey = sessionKeyFromContext(ctx);\n let state = states.get(sessionKey);\n if (!state) {\n state = {\n observedHashes: new Set<string>(),\n liveObservedReplayKeys: new Map<string, number>(),\n lastInjectedRecallKey: \"\",\n };\n states.set(sessionKey, state);\n pruneSessionStates(states);\n }\n return { sessionKey, state };\n}\n\nfunction pruneSessionStates(states: Map<string, PiSessionState>): void {\n while (states.size > MAX_SESSION_STATES) {\n const oldest = states.keys().next().value;\n if (typeof oldest !== \"string\") return;\n states.delete(oldest);\n }\n}\n\nexport async function observeMessages(\n ctx: any,\n client: RemnicClient,\n rawMessages: unknown[],\n observedHashes: Set<string>,\n liveObservedReplayKeys?: Map<string, number>,\n): Promise<void> {\n const sessionKey = sessionKeyFromContext(ctx);\n const messages: ObserveMessage[] = [];\n const pendingHashes = new Set<string>();\n for (const raw of rawMessages) {\n const message = toObserveMessage(raw);\n if (!message) continue;\n const hash = observedMessageDedupeKey(message, sessionKey);\n if (hash && (observedHashes.has(hash) || pendingHashes.has(hash))) continue;\n if (hash) pendingHashes.add(hash);\n messages.push(message);\n }\n if (messages.length === 0) return;\n try {\n await client.observe(sessionKey, ctx.cwd, messages);\n for (const hash of pendingHashes) rememberObservedHash(observedHashes, hash);\n if (liveObservedReplayKeys) {\n for (const message of messages) {\n rememberLiveObservedReplayKey(liveObservedReplayKeys, liveReplayKey(message, sessionKey));\n }\n }\n } catch (err) {\n notify(ctx, `Remnic observe failed: ${errorMessage(err)}`, \"warning\");\n }\n}\n\nexport function buildCompactionSummary(preparation: any): string {\n const previousSummary = typeof preparation.previousSummary === \"string\"\n ? preparation.previousSummary.trim()\n : \"\";\n const messages = [\n ...(Array.isArray(preparation.messagesToSummarize) ? preparation.messagesToSummarize : []),\n ...(Array.isArray(preparation.turnPrefixMessages) ? preparation.turnPrefixMessages : []),\n ];\n const transcript = summarizeMessages(messages, 24000);\n const details = fileDetailsFromPreparation(preparation);\n\n if (\n !previousSummary &&\n !transcript &&\n details.readFiles.length === 0 &&\n details.modifiedFiles.length === 0\n ) {\n return \"\";\n }\n\n const sections: string[] = [\n \"## Remnic Pi Context Checkpoint\",\n \"\",\n \"This checkpoint was created by Remnic during Pi context compaction.\",\n ];\n if (previousSummary) sections.push(\"\", \"## Previous Summary\", previousSummary);\n if (transcript) sections.push(\"\", \"## Conversation Excerpt\", transcript);\n if (details.readFiles.length > 0) sections.push(\"\", \"<read-files>\", ...details.readFiles, \"</read-files>\");\n if (details.modifiedFiles.length > 0) sections.push(\"\", \"<modified-files>\", ...details.modifiedFiles, \"</modified-files>\");\n return sections.join(\"\\n\");\n}\n\nfunction fileDetailsFromPreparation(preparation: any): { readFiles: string[]; modifiedFiles: string[] } {\n const fileOps = preparation?.fileOps;\n const read = fileOps?.read instanceof Set ? Array.from(fileOps.read).filter(isString) : [];\n const edited = fileOps?.edited instanceof Set ? Array.from(fileOps.edited).filter(isString) : [];\n const written = fileOps?.written instanceof Set ? Array.from(fileOps.written).filter(isString) : [];\n const modified = new Set([...edited, ...written]);\n return {\n readFiles: read.filter((file) => !modified.has(file)).sort(),\n modifiedFiles: Array.from(modified).sort(),\n };\n}\n\nfunction restoreObservedState(ctx: any, observedHashes: Set<string>): void {\n for (const entry of safeEntries(ctx)) {\n if (entry?.type !== \"custom\" || entry.customType !== STATE_CUSTOM_TYPE) continue;\n const hashes = entry.data?.observedHashes;\n if (Array.isArray(hashes)) {\n for (const hash of hashes) {\n if (typeof hash === \"string\") rememberObservedHash(observedHashes, hash);\n }\n }\n }\n}\n\nfunction rememberObservedHash(observedHashes: Set<string>, hash: string): void {\n if (observedHashes.has(hash)) return;\n while (observedHashes.size >= MAX_OBSERVED_HASHES) {\n const oldest = observedHashes.keys().next().value;\n if (typeof oldest !== \"string\") break;\n observedHashes.delete(oldest);\n }\n observedHashes.add(hash);\n}\n\nfunction rememberLiveObservedReplayKey(liveObservedReplayKeys: Map<string, number>, key: string): void {\n liveObservedReplayKeys.set(key, (liveObservedReplayKeys.get(key) ?? 0) + 1);\n}\n\nfunction consumeLiveObservedReplayKey(liveObservedReplayKeys: Map<string, number>, key: string): boolean {\n const count = liveObservedReplayKeys.get(key) ?? 0;\n if (count <= 0) return false;\n if (count === 1) liveObservedReplayKeys.delete(key);\n else liveObservedReplayKeys.set(key, count - 1);\n return true;\n}\n\nfunction skipLiveObservedReplayMessages(\n ctx: any,\n rawMessages: unknown[],\n liveObservedReplayKeys: Map<string, number>,\n): unknown[] {\n if (liveObservedReplayKeys.size === 0) return rawMessages;\n const sessionKey = sessionKeyFromContext(ctx);\n const unobserved: unknown[] = [];\n for (const raw of rawMessages) {\n const message = toObserveMessage(raw);\n if (message && consumeLiveObservedReplayKey(liveObservedReplayKeys, liveReplayKey(message, sessionKey))) {\n continue;\n }\n unobserved.push(raw);\n }\n return unobserved;\n}\n\nfunction liveReplayKey(message: ObserveMessage, sessionKey: string): string {\n return hashObservedMessage(message, sessionKey, \"live-replay\");\n}\n\nfunction persistObservedState(pi: PiApi, observedHashes: Set<string>): void {\n const observed = Array.from(observedHashes).slice(-MAX_OBSERVED_HASHES);\n pi.appendEntry(STATE_CUSTOM_TYPE, {\n observedHashes: observed,\n recordedAt: new Date().toISOString(),\n });\n}\n\nasync function setStatus(ctx: any, client: RemnicClient, config: RemnicPiConfig): Promise<void> {\n try {\n await client.health({ timeoutMs: config.startupRequestTimeoutMs });\n ctx.ui?.setStatus?.(\"remnic\", `Remnic ${config.namespace ? `(${config.namespace})` : \"ready\"}`);\n } catch {\n ctx.ui?.setStatus?.(\"remnic\", \"Remnic offline\");\n }\n}\n\nfunction safeEntries(ctx: any): any[] {\n try {\n const entries = ctx.sessionManager?.getEntries?.();\n return Array.isArray(entries) ? entries : [];\n } catch {\n return [];\n }\n}\n\nfunction safeBranch(ctx: any): any[] {\n try {\n const branch = ctx.sessionManager?.getBranch?.();\n return Array.isArray(branch) ? branch : [];\n } catch {\n return [];\n }\n}\n\nfunction branchMessagesWithEntryIdentity(branch: any[]): unknown[] {\n const messages: unknown[] = [];\n for (const entry of branch) {\n const message = messageWithEntryIdentity(entry);\n if (message) messages.push(message);\n }\n return messages;\n}\n\nfunction messageWithEntryIdentity(entry: any): unknown | null {\n const message = entry?.message;\n if (!message || typeof message !== \"object\" || Array.isArray(message)) return message ?? null;\n\n const source = isRecord(entry) ? entry : {};\n const enriched: Record<string, unknown> = { ...(message as Record<string, unknown>) };\n assignMissingIdentity(enriched, \"entryId\", source.id ?? source.entryId ?? source.entry_id);\n assignMissingIdentity(enriched, \"timestamp\", source.timestamp);\n assignMissingIdentity(enriched, \"createdAt\", source.createdAt ?? source.created_at);\n return enriched;\n}\n\nfunction assignMissingIdentity(target: Record<string, unknown>, field: string, value: unknown): void {\n if (target[field] !== undefined) return;\n if (typeof value === \"string\" && value.length > 0) {\n target[field] = value;\n return;\n }\n if (typeof value === \"number\" && Number.isFinite(value)) {\n target[field] = value;\n }\n}\n\nfunction trimContext(value: string, budget: number): string {\n if (value.length <= budget) return value;\n if (budget <= TRUNCATION_NOTICE.length) return TRUNCATION_NOTICE.slice(0, budget);\n return `${value.slice(0, budget - TRUNCATION_NOTICE.length)}${TRUNCATION_NOTICE}`;\n}\n\nfunction notify(ctx: any, message: string, level: \"info\" | \"success\" | \"warning\" | \"error\"): void {\n if (ctx?.hasUI === false) return;\n ctx?.ui?.notify?.(message, level);\n}\n\nfunction errorMessage(err: unknown): string {\n return err instanceof Error ? err.message : String(err);\n}\n\nfunction finiteTokenCount(value: unknown): number | null {\n return typeof value === \"number\" && Number.isFinite(value) && value >= 0 ? value : null;\n}\n\nfunction isString(value: unknown): value is string {\n return typeof value === \"string\";\n}\n\nexport { textFromMessage };\n","import { existsSync, readFileSync } from \"node:fs\";\nimport path from \"node:path\";\n\nimport { expandTildePath } from \"@remnic/core\";\n\nimport { REMNIC_PI_EXTENSION_DIR_NAME, resolvePiAgentHome } from \"./paths.js\";\n\nexport interface RemnicPiConfig {\n remnicDaemonUrl: string;\n authToken?: string;\n namespace?: string;\n recallMode: \"auto\" | \"minimal\" | \"full\" | \"graph_mode\" | \"no_recall\";\n recallTopK: number;\n recallBudgetChars: number;\n recallEnabled: boolean;\n observeEnabled: boolean;\n observeSkipExtraction: boolean;\n compactionEnabled: boolean;\n mcpToolsEnabled: boolean;\n statusEnabled: boolean;\n requestTimeoutMs: number;\n startupRequestTimeoutMs: number;\n}\n\nexport interface LoadConfigOptions {\n configPath?: string;\n env?: NodeJS.ProcessEnv;\n}\n\nconst DEFAULT_CONFIG: RemnicPiConfig = {\n remnicDaemonUrl: \"http://127.0.0.1:4318\",\n recallMode: \"auto\",\n recallTopK: 8,\n recallBudgetChars: 12000,\n recallEnabled: true,\n observeEnabled: true,\n observeSkipExtraction: false,\n compactionEnabled: true,\n mcpToolsEnabled: true,\n statusEnabled: true,\n requestTimeoutMs: 60000,\n startupRequestTimeoutMs: 1000,\n};\n\nfunction defaultConfigPath(env: NodeJS.ProcessEnv): string {\n return path.join(resolvePiAgentHome(env), \"extensions\", REMNIC_PI_EXTENSION_DIR_NAME, \"remnic.config.json\");\n}\n\nfunction coerceBoolean(value: unknown, fallback: boolean, fieldName: string): boolean {\n if (value === undefined || value === null) return fallback;\n if (typeof value === \"boolean\") return value;\n if (typeof value === \"string\") {\n const normalized = value.trim().toLowerCase();\n if ([\"true\", \"1\", \"yes\", \"on\"].includes(normalized)) return true;\n if ([\"false\", \"0\", \"no\", \"off\"].includes(normalized)) return false;\n }\n throw new Error(`Invalid boolean value for Remnic Pi config field ${fieldName}`);\n}\n\nfunction coercePositiveInt(value: unknown, fallback: number, max: number, fieldName: string): number {\n if (value === undefined || value === null || value === \"\") return fallback;\n let parsed: number;\n if (typeof value === \"number\") {\n parsed = value;\n } else if (typeof value === \"string\") {\n const trimmed = value.trim();\n if (trimmed.length === 0) return fallback;\n if (!/^[+-]?\\d+$/.test(trimmed)) {\n throw new Error(`Invalid numeric value for Remnic Pi config field ${fieldName}: expected an integer from 1 to ${max}`);\n }\n parsed = Number(trimmed);\n } else {\n throw new Error(`Invalid numeric value for Remnic Pi config field ${fieldName}: expected an integer from 1 to ${max}`);\n }\n if (!Number.isInteger(parsed) || parsed <= 0 || parsed > max) {\n throw new Error(`Invalid numeric value for Remnic Pi config field ${fieldName}: expected an integer from 1 to ${max}`);\n }\n return parsed;\n}\n\nfunction coerceOptionalNonEmptyString(value: unknown, fieldName: string): string | undefined {\n if (value === undefined || value === null) return undefined;\n if (typeof value === \"string\" && value.trim().length > 0) return value.trim();\n throw new Error(`Invalid string value for Remnic Pi config field ${fieldName}`);\n}\n\nfunction coerceOptionalString(value: unknown, fieldName: string): string | undefined {\n if (value === undefined || value === null) return undefined;\n if (typeof value === \"string\") {\n const trimmed = value.trim();\n return trimmed.length > 0 ? trimmed : undefined;\n }\n throw new Error(`Invalid string value for Remnic Pi config field ${fieldName}`);\n}\n\nfunction coerceOptionalHttpUrl(value: unknown, fieldName: string): string | undefined {\n if (value === undefined || value === null) return undefined;\n if (typeof value !== \"string\") {\n throw new Error(`Invalid URL value for Remnic Pi config field ${fieldName}: expected an http or https URL`);\n }\n const trimmed = value.trim();\n if (trimmed.length === 0) return undefined;\n try {\n const parsed = new URL(trimmed);\n if (parsed.protocol === \"http:\" || parsed.protocol === \"https:\") return trimTrailingSlashes(trimmed);\n } catch {\n // Fall through to the shared error below.\n }\n throw new Error(`Invalid URL value for Remnic Pi config field ${fieldName}: expected an http or https URL`);\n}\n\nfunction coerceRecallMode(value: unknown): RemnicPiConfig[\"recallMode\"] {\n if (value === undefined || value === null || value === \"\") return DEFAULT_CONFIG.recallMode;\n if (\n value === \"minimal\" ||\n value === \"full\" ||\n value === \"graph_mode\" ||\n value === \"no_recall\" ||\n value === \"auto\"\n ) {\n return value;\n }\n throw new Error(`Invalid recallMode value for Remnic Pi config: ${JSON.stringify(value)}`);\n}\n\nfunction readConfigFile(configPath: string): Record<string, unknown> {\n if (!existsSync(configPath)) return {};\n try {\n const raw = readFileSync(configPath, \"utf-8\");\n const parsed = JSON.parse(raw);\n if (parsed && typeof parsed === \"object\" && !Array.isArray(parsed)) {\n return parsed as Record<string, unknown>;\n }\n throw new Error(\"expected a JSON object\");\n } catch (err) {\n const reason = err instanceof Error ? err.message : String(err);\n throw new Error(`Failed to load Remnic Pi config at ${configPath}: ${reason}`);\n }\n}\n\nfunction trimTrailingSlashes(value: string): string {\n let end = value.length;\n while (end > 0 && value.charCodeAt(end - 1) === 47) end -= 1;\n return value.slice(0, end);\n}\n\nexport function resolveConfigPath(options: LoadConfigOptions = {}): string {\n const env = options.env ?? process.env;\n return expandTildePath(options.configPath || env.REMNIC_PI_CONFIG || defaultConfigPath(env));\n}\n\nexport function loadConfig(options: LoadConfigOptions = {}): RemnicPiConfig {\n const env = options.env ?? process.env;\n const fileConfig = readConfigFile(resolveConfigPath(options));\n const daemonUrl =\n coerceOptionalHttpUrl(fileConfig.remnicDaemonUrl, \"remnicDaemonUrl\") ??\n coerceOptionalHttpUrl(env.REMNIC_DAEMON_URL, \"REMNIC_DAEMON_URL\") ??\n DEFAULT_CONFIG.remnicDaemonUrl;\n const authToken =\n coerceOptionalString(fileConfig.authToken, \"authToken\") ??\n coerceOptionalString(env.REMNIC_PI_AUTH_TOKEN, \"REMNIC_PI_AUTH_TOKEN\");\n const namespace = coerceOptionalNonEmptyString(fileConfig.namespace, \"namespace\");\n\n return {\n remnicDaemonUrl: daemonUrl,\n authToken,\n namespace,\n recallMode: coerceRecallMode(fileConfig.recallMode),\n recallTopK: coercePositiveInt(fileConfig.recallTopK, DEFAULT_CONFIG.recallTopK, 50, \"recallTopK\"),\n recallBudgetChars: coercePositiveInt(fileConfig.recallBudgetChars, DEFAULT_CONFIG.recallBudgetChars, 64000, \"recallBudgetChars\"),\n recallEnabled: coerceBoolean(fileConfig.recallEnabled, DEFAULT_CONFIG.recallEnabled, \"recallEnabled\"),\n observeEnabled: coerceBoolean(fileConfig.observeEnabled, DEFAULT_CONFIG.observeEnabled, \"observeEnabled\"),\n observeSkipExtraction: coerceBoolean(fileConfig.observeSkipExtraction, DEFAULT_CONFIG.observeSkipExtraction, \"observeSkipExtraction\"),\n compactionEnabled: coerceBoolean(fileConfig.compactionEnabled, DEFAULT_CONFIG.compactionEnabled, \"compactionEnabled\"),\n mcpToolsEnabled: coerceBoolean(fileConfig.mcpToolsEnabled, DEFAULT_CONFIG.mcpToolsEnabled, \"mcpToolsEnabled\"),\n statusEnabled: coerceBoolean(fileConfig.statusEnabled, DEFAULT_CONFIG.statusEnabled, \"statusEnabled\"),\n requestTimeoutMs: coercePositiveInt(fileConfig.requestTimeoutMs, DEFAULT_CONFIG.requestTimeoutMs, 60_000, \"requestTimeoutMs\"),\n startupRequestTimeoutMs: coercePositiveInt(\n fileConfig.startupRequestTimeoutMs,\n DEFAULT_CONFIG.startupRequestTimeoutMs,\n 60_000,\n \"startupRequestTimeoutMs\",\n ),\n };\n}\n","import type { RemnicPiConfig } from \"./config.js\";\n\nexport interface RecallResponse {\n context?: string;\n results?: Array<{ id?: string; content?: string; score?: number; category?: string }>;\n count?: number;\n}\n\nexport interface ObserveMessagePart {\n ordinal?: number;\n kind: \"text\" | \"tool_call\" | \"tool_result\" | \"patch\" | \"file_read\" | \"file_write\" | \"step_start\" | \"step_finish\" | \"snapshot\" | \"retry\";\n payload: Record<string, unknown>;\n toolName?: string | null;\n filePath?: string | null;\n createdAt?: string | null;\n}\n\nexport interface ObserveMessage {\n role: \"user\" | \"assistant\";\n content: string;\n sourceFormat?: \"pi\";\n rawContent?: unknown;\n parts?: ObserveMessagePart[];\n}\n\nexport interface McpTool {\n name: string;\n description?: string;\n inputSchema?: Record<string, unknown>;\n}\n\nexport class RemnicHttpError extends Error {\n constructor(\n readonly status: number,\n message: string,\n ) {\n super(message);\n }\n}\n\nexport class RemnicClient {\n private requestId = 0;\n\n constructor(private readonly config: RemnicPiConfig) {}\n\n async health(options: RequestOptions = {}): Promise<Record<string, unknown>> {\n return this.request(\"GET\", \"/engram/v1/health\", undefined, options);\n }\n\n async recall(query: string, sessionKey: string, cwd: string): Promise<RecallResponse> {\n return this.request(\"POST\", \"/engram/v1/recall\", {\n query,\n sessionKey,\n cwd,\n namespace: this.config.namespace,\n topK: this.config.recallTopK,\n mode: this.config.recallMode,\n });\n }\n\n async recallExplain(sessionKey: string): Promise<Record<string, unknown>> {\n return this.request(\"POST\", \"/engram/v1/recall/explain\", {\n sessionKey,\n namespace: this.config.namespace,\n });\n }\n\n async observe(sessionKey: string, cwd: string, messages: ObserveMessage[]): Promise<Record<string, unknown>> {\n return this.request(\"POST\", \"/engram/v1/observe\", {\n sessionKey,\n cwd,\n namespace: this.config.namespace,\n skipExtraction: this.config.observeSkipExtraction,\n messages,\n });\n }\n\n async storeMemory(content: string, sessionKey: string): Promise<Record<string, unknown>> {\n return this.request(\"POST\", \"/engram/v1/memories\", {\n content,\n category: \"fact\",\n sourceReason: \"Captured from Pi via Remnic extension\",\n sessionKey,\n namespace: this.config.namespace,\n });\n }\n\n async lcmSearch(query: string, sessionKey: string, limit = 10): Promise<Record<string, unknown>> {\n return this.request(\"POST\", \"/engram/v1/lcm/search\", {\n query,\n sessionKey,\n namespace: this.config.namespace,\n limit,\n });\n }\n\n async lcmCompactionFlush(sessionKey: string): Promise<Record<string, unknown>> {\n return this.request(\"POST\", \"/engram/v1/lcm/compaction/flush\", {\n sessionKey,\n namespace: this.config.namespace,\n });\n }\n\n async lcmCompactionRecord(sessionKey: string, tokensBefore: number, tokensAfter: number): Promise<Record<string, unknown>> {\n return this.request(\"POST\", \"/engram/v1/lcm/compaction/record\", {\n sessionKey,\n namespace: this.config.namespace,\n tokensBefore,\n tokensAfter,\n });\n }\n\n async contextCheckpoint(sessionKey: string, context: string): Promise<Record<string, unknown>> {\n return this.mcpTool(\"remnic.context_checkpoint\", {\n sessionKey,\n context,\n namespace: this.config.namespace,\n });\n }\n\n async mcpListTools(options: RequestOptions = {}): Promise<McpTool[]> {\n const result = await this.mcpRequest(\"tools/list\", {}, options);\n const tools = (result as { tools?: unknown }).tools;\n return Array.isArray(tools) ? tools.filter(isMcpTool) : [];\n }\n\n async mcpTool(name: string, args: Record<string, unknown>): Promise<Record<string, unknown>> {\n return this.mcpRequest(\"tools/call\", {\n name,\n arguments: args,\n });\n }\n\n private async request<T = Record<string, unknown>>(\n method: string,\n pathname: string,\n body?: unknown,\n options: RequestOptions = {},\n ): Promise<T> {\n const controller = new AbortController();\n // A per-request override is honored only when it is a finite positive number;\n // 0, negative, NaN, or non-finite values would make setTimeout abort\n // immediately (or behave erratically), so fall back to the general budget.\n // In practice the override is always sourced from the validated\n // `startupRequestTimeoutMs` config, but this keeps the client robust to any\n // future caller (Copilot review).\n const override = options.timeoutMs;\n const timeoutMs =\n typeof override === \"number\" && Number.isFinite(override) && override > 0\n ? override\n : this.config.requestTimeoutMs;\n const timeout = setTimeout(() => controller.abort(), timeoutMs);\n try {\n const response = await fetch(`${this.config.remnicDaemonUrl}${pathname}`, {\n method,\n headers: {\n ...(body === undefined ? {} : { \"Content-Type\": \"application/json\" }),\n ...(this.config.authToken ? { Authorization: `Bearer ${this.config.authToken}` } : {}),\n \"X-Engram-Client-Id\": \"pi\",\n },\n body: body === undefined ? undefined : JSON.stringify(body),\n signal: controller.signal,\n });\n const text = await response.text();\n let payload: unknown = {};\n let parseError: unknown;\n if (text) {\n try {\n payload = JSON.parse(text);\n } catch (err) {\n parseError = err;\n }\n }\n if (!response.ok) {\n throw new RemnicHttpError(response.status, responseErrorMessage(response, text, payload, parseError));\n }\n if (parseError) {\n const reason = parseError instanceof Error ? parseError.message : String(parseError);\n throw new Error(`Invalid JSON response from Remnic daemon (${response.status} ${response.statusText || \"OK\"}): ${reason}`);\n }\n return payload as T;\n } catch (err) {\n if (isAbortError(err)) {\n throw new Error(`Remnic request timed out after ${timeoutMs}ms`);\n }\n throw err;\n } finally {\n clearTimeout(timeout);\n }\n }\n\n private async mcpRequest(\n method: string,\n params: Record<string, unknown>,\n options: RequestOptions = {},\n ): Promise<Record<string, unknown>> {\n this.requestId += 1;\n const payload = await this.request<Record<string, unknown>>(\"POST\", \"/mcp\", {\n jsonrpc: \"2.0\",\n id: this.requestId,\n method,\n params,\n }, options);\n if (payload.error) {\n throw new Error(JSON.stringify(payload.error));\n }\n return (payload.result && typeof payload.result === \"object\" ? payload.result : payload) as Record<string, unknown>;\n }\n}\n\ninterface RequestOptions {\n timeoutMs?: number;\n}\n\nfunction isMcpTool(value: unknown): value is McpTool {\n return !!value && typeof value === \"object\" && typeof (value as { name?: unknown }).name === \"string\";\n}\n\nfunction isAbortError(err: unknown): boolean {\n return err instanceof Error && (err.name === \"AbortError\" || err.message === \"This operation was aborted\");\n}\n\nfunction responseErrorMessage(response: Response, text: string, payload: unknown, parseError: unknown): string {\n if (!parseError && payload && typeof payload === \"object\") {\n const error = (payload as { error?: unknown }).error;\n if (typeof error === \"string\" && error.trim().length > 0) {\n return error;\n }\n const message = (payload as { message?: unknown }).message;\n if (typeof message === \"string\" && message.trim().length > 0) {\n return message;\n }\n }\n\n const snippet = text.trim().replace(/\\s+/g, \" \").slice(0, 200);\n if (snippet.length > 0) {\n return response.statusText ? `${response.statusText}: ${snippet}` : snippet;\n }\n return response.statusText || `HTTP ${response.status}`;\n}\n","import { createHash } from \"node:crypto\";\n\nimport { parsePiMessageParts, type LcmMessagePartInput } from \"@remnic/core\";\n\nimport type { ObserveMessage, ObserveMessagePart } from \"./client.js\";\n\ntype PiMessage = Record<string, unknown>;\n\nexport function sessionKeyFromContext(ctx: { sessionManager?: { getSessionId?: () => string } }): string {\n const id = ctx.sessionManager?.getSessionId?.();\n return id && id.trim().length > 0 ? `pi:${id}` : \"pi:default\";\n}\n\nexport function textFromMessage(message: unknown): string {\n if (!message || typeof message !== \"object\") return \"\";\n const obj = message as PiMessage;\n const role = typeof obj.role === \"string\" ? obj.role : \"message\";\n if (role === \"bashExecution\") {\n const command = typeof obj.command === \"string\" ? obj.command : \"\";\n const output = typeof obj.output === \"string\" ? obj.output : \"\";\n return [`Ran ${command}`, output].filter(Boolean).join(\"\\n\");\n }\n return textFromContent(obj.content).trim();\n}\n\nexport function latestUserQuery(messages: unknown[]): string {\n for (let index = messages.length - 1; index >= 0; index--) {\n const message = messages[index] as PiMessage;\n if (isExcludedFromContext(message) || isRemnicInjected(message)) continue;\n if (message?.role === \"user\") {\n const text = textFromMessage(message);\n if (text.length > 0) return text;\n }\n }\n return \"\";\n}\n\nexport function latestUserRecallTarget(\n messages: unknown[],\n): { query: string; dedupeKey: string } | null {\n for (let index = messages.length - 1; index >= 0; index--) {\n const message = messages[index] as PiMessage;\n if (isExcludedFromContext(message) || isRemnicInjected(message)) continue;\n if (message?.role !== \"user\") continue;\n const query = textFromMessage(message);\n if (query.length === 0) continue;\n const identity = stableObservedMessageIdentity(message);\n return {\n query,\n dedupeKey: identity ? `message:${identity}:${query}` : `query:${query}`,\n };\n }\n return null;\n}\n\nexport function toObserveMessage(message: unknown): ObserveMessage | null {\n if (!message || typeof message !== \"object\") return null;\n const obj = message as PiMessage;\n if (isExcludedFromContext(obj) || isRemnicInjected(obj)) return null;\n const role = obj.role === \"user\" || obj.role === \"bashExecution\" ? \"user\" : \"assistant\";\n const content = textFromMessage(obj);\n if (content.length === 0) return null;\n return {\n role,\n content,\n sourceFormat: \"pi\",\n rawContent: obj,\n parts: partsFromMessage(obj, content),\n };\n}\n\nexport function hashObservedMessage(message: ObserveMessage, sessionKey = \"\", identity = \"content\"): string {\n return createHash(\"sha256\")\n .update(sessionKey)\n .update(\"\\0\")\n .update(message.role)\n .update(\"\\0\")\n .update(identity)\n .update(\"\\0\")\n .update(message.content)\n .digest(\"hex\");\n}\n\nexport function observedMessageDedupeKey(\n message: ObserveMessage,\n sessionKey = \"\",\n): string | null {\n const identity = stableObservedMessageIdentity(message.rawContent);\n return identity ? hashObservedMessage(message, sessionKey, identity) : null;\n}\n\nexport function summarizeMessages(messages: unknown[], maxChars: number): string {\n const chunks: string[] = [];\n let used = 0;\n for (const message of messages) {\n if (isExcludedFromContext(message) || isRemnicInjected(message)) continue;\n const text = textFromMessage(message);\n if (!text) continue;\n const role = typeof (message as PiMessage)?.role === \"string\" ? (message as PiMessage).role : \"message\";\n const line = `[${role}] ${text}`;\n const separatorLength = chunks.length > 0 ? 2 : 0;\n const remaining = maxChars - used - separatorLength;\n if (remaining <= 0) break;\n const clipped = line.length > remaining ? line.slice(0, remaining) : line;\n if (clipped.length > 0) chunks.push(clipped);\n used += separatorLength + clipped.length;\n if (used >= maxChars) break;\n }\n return chunks.join(\"\\n\\n\");\n}\n\nexport function isExcludedFromContext(message: unknown): boolean {\n return !!message && typeof message === \"object\" && (message as PiMessage).excludeFromContext === true;\n}\n\nexport function isRemnicInjected(message: unknown): boolean {\n return !!message && typeof message === \"object\" && (message as PiMessage).remnicInjected === true;\n}\n\nfunction textFromContent(content: unknown): string {\n if (typeof content === \"string\") return content;\n if (!Array.isArray(content)) return \"\";\n const chunks: string[] = [];\n for (const block of content) {\n if (!block || typeof block !== \"object\") continue;\n const obj = block as PiMessage;\n if (obj.type === \"text\" && typeof obj.text === \"string\") chunks.push(obj.text);\n if (obj.type === \"toolCall\" && typeof obj.name === \"string\") {\n chunks.push(`Tool ${obj.name} called with ${JSON.stringify(obj.arguments ?? {})}`);\n }\n }\n return chunks.join(\"\\n\");\n}\n\nfunction partsFromMessage(message: PiMessage, renderedContent: string): ObserveMessagePart[] {\n return parsePiMessageParts(message, {\n renderedContent,\n allowRenderedFallback: true,\n }).map(toObserveMessagePart);\n}\n\nfunction toObserveMessagePart(part: LcmMessagePartInput): ObserveMessagePart {\n return {\n ordinal: part.ordinal ?? undefined,\n kind: part.kind,\n payload: part.payload,\n toolName: part.toolName ?? part.tool_name ?? undefined,\n filePath: part.filePath ?? part.file_path ?? undefined,\n createdAt: part.createdAt ?? part.created_at ?? undefined,\n };\n}\n\nfunction stableObservedMessageIdentity(rawContent: unknown): string | null {\n if (rawContent && typeof rawContent === \"object\") {\n const obj = rawContent as PiMessage;\n const fields = [\n \"id\",\n \"entryId\",\n \"entry_id\",\n \"messageId\",\n \"message_id\",\n \"turnId\",\n \"turn_id\",\n \"timestamp\",\n \"createdAt\",\n \"created_at\",\n ];\n for (const field of fields) {\n const value = obj[field];\n if (typeof value === \"string\" && value.length > 0) return `${field}:${value}`;\n if (typeof value === \"number\" && Number.isFinite(value)) return `${field}:${value}`;\n }\n }\n return null;\n}\n"],"mappings":"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","names":["remnicPiExtension"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/config.ts","../src/client.ts","../src/messages.ts"],"sourcesContent":["import { Type, type TSchema } from \"@sinclair/typebox\";\n\nimport { loadConfig, type LoadConfigOptions, type RemnicPiConfig } from \"./config.js\";\nimport { RemnicClient, type McpTool, type ObserveMessage } from \"./client.js\";\nimport {\n hashObservedMessage,\n latestUserRecallTarget,\n observedMessageDedupeKey,\n sessionKeyFromContext,\n summarizeMessages,\n textFromMessage,\n toObserveMessage,\n} from \"./messages.js\";\n\ntype PiApi = {\n on(event: string, handler: (event: any, ctx: any) => unknown | Promise<unknown>): void;\n registerCommand(name: string, options: { description?: string; handler: (args: string, ctx: any) => Promise<void> }): void;\n registerTool(tool: Record<string, unknown>): void;\n appendEntry<T = unknown>(customType: string, data?: T): void;\n};\n\nexport interface RemnicPiExtensionOptions extends LoadConfigOptions {\n config?: RemnicPiConfig;\n}\n\nconst STATE_CUSTOM_TYPE = \"remnic_state\";\nconst MAX_OBSERVED_HASHES = 2000;\nconst MAX_SESSION_STATES = 50;\nconst MAX_CONTEXT_CHARS = 12000;\nconst TRUNCATION_NOTICE = \"\\n\\n[Remnic context truncated]\";\nconst SESSION_OWNED_FIELDS = new Set([\"sessionKey\", \"namespace\", \"cwd\"]);\n\ntype PiSessionState = {\n observedHashes: Set<string>;\n liveObservedReplayKeys: Map<string, number>;\n lastInjectedRecallKey: string;\n};\n\ntype NotifyLevel = \"info\" | \"success\" | \"warning\" | \"error\";\ntype NotifyFn = (message: string, level: NotifyLevel) => void;\n\ntype PiContextSnapshot = {\n sessionKey: string;\n cwd: string;\n entries: any[];\n branch: any[];\n notify: NotifyFn;\n setStatus: (key: string, value: string) => void;\n compact?: () => unknown;\n};\ntype PiContextSnapshotOptions = {\n includeSessionHistory?: boolean;\n};\n\nexport function createRemnicPiExtension(options: RemnicPiExtensionOptions = {}) {\n const config = options.config ?? loadConfig(options);\n const client = new RemnicClient(config);\n const sessionStates = new Map<string, PiSessionState>();\n\n return async function remnicPiExtension(pi: PiApi): Promise<void> {\n pi.on(\"session_start\", async (_event, ctx) => {\n const session = snapshotPiContext(ctx, { includeSessionHistory: true });\n if (!session) return;\n const { state } = getSessionState(session.sessionKey, sessionStates);\n restoreObservedState(session, state.observedHashes);\n if (!config.statusEnabled) return;\n await setStatus(session, client, config);\n });\n\n pi.on(\"context\", async (event, ctx) => {\n const session = snapshotPiContext(ctx);\n if (!session) return;\n if (!config.recallEnabled || !config.authToken) return;\n const recallTarget = latestUserRecallTarget(Array.isArray(event.messages) ? event.messages : []);\n if (!recallTarget) return;\n const { query } = recallTarget;\n const { state } = getSessionState(session.sessionKey, sessionStates);\n if (recallTarget.dedupeKey === state.lastInjectedRecallKey) return;\n\n try {\n const recalled = await client.recall(query, session.sessionKey, session.cwd);\n const context = trimContext(recalled.context ?? \"\", config.recallBudgetChars);\n if (!context) return;\n state.lastInjectedRecallKey = recallTarget.dedupeKey;\n return {\n messages: [\n ...event.messages,\n {\n role: \"user\",\n content: [{ type: \"text\", text: `Remnic recalled context for this turn:\\n\\n${context}` }],\n remnicInjected: true,\n timestamp: Date.now(),\n },\n ],\n };\n } catch (err) {\n session.notify(`Remnic recall unavailable: ${errorMessage(err)}`, \"warning\");\n }\n });\n\n pi.on(\"message_end\", async (event, ctx) => {\n const session = snapshotPiContext(ctx);\n if (!session) return;\n if (!config.observeEnabled || !isUserMessage(event.message)) return;\n const { state } = getSessionState(session.sessionKey, sessionStates);\n await observeMessagesForSession(session, client, [event.message], state.observedHashes, state.liveObservedReplayKeys);\n });\n\n pi.on(\"turn_end\", async (event, ctx) => {\n const session = snapshotPiContext(ctx);\n if (!session) return;\n if (!config.observeEnabled) return;\n const messages = [event.message, ...(Array.isArray(event.toolResults) ? event.toolResults : [])];\n const { state } = getSessionState(session.sessionKey, sessionStates);\n await observeMessagesForSession(session, client, messages, state.observedHashes, state.liveObservedReplayKeys);\n });\n\n pi.on(\"session_shutdown\", async (_event, ctx) => {\n const session = snapshotPiContext(ctx, { includeSessionHistory: true });\n if (!session) return;\n const { sessionKey, state } = getSessionState(session.sessionKey, sessionStates);\n if (config.observeEnabled) {\n const branchMessages = branchMessagesWithEntryIdentity(session.branch);\n const unobservedBranchMessages = skipLiveObservedReplayMessages(session.sessionKey, branchMessages, state.liveObservedReplayKeys);\n if (unobservedBranchMessages.length > 0) {\n await observeMessagesForSession(session, client, unobservedBranchMessages, state.observedHashes);\n }\n }\n persistObservedState(pi, state.observedHashes);\n sessionStates.delete(sessionKey);\n });\n\n pi.on(\"session_before_compact\", async (event, ctx) => {\n const session = snapshotPiContext(ctx);\n if (!session) return;\n if (!config.compactionEnabled || !config.authToken) return;\n const preparation = event.preparation ?? {};\n try {\n await client.lcmCompactionFlush(session.sessionKey);\n } catch (err) {\n session.notify(`Remnic LCM flush failed: ${errorMessage(err)}`, \"warning\");\n return;\n }\n\n const tokensBefore = finiteTokenCount(preparation.tokensBefore);\n const tokensAfter = finiteTokenCount(preparation.tokensAfter);\n if (tokensBefore !== null && tokensAfter !== null) {\n try {\n await client.lcmCompactionRecord(session.sessionKey, tokensBefore, tokensAfter);\n } catch (err) {\n session.notify(`Remnic LCM compaction token record failed: ${errorMessage(err)}`, \"warning\");\n }\n }\n\n const summary = buildCompactionSummary(preparation);\n if (!summary.trim()) return;\n try {\n await client.contextCheckpoint(session.sessionKey, summary);\n } catch (err) {\n session.notify(`Remnic context checkpoint failed: ${errorMessage(err)}`, \"warning\");\n }\n const details = fileDetailsFromPreparation(preparation);\n return {\n compaction: {\n summary,\n firstKeptEntryId: preparation.firstKeptEntryId,\n tokensBefore: preparation.tokensBefore,\n details: {\n ...details,\n remnic: { version: 1, source: \"pi\" },\n },\n },\n };\n });\n\n registerCommands(pi, client, config);\n if (config.mcpToolsEnabled && config.authToken) {\n await registerMcpTools(pi, client, config);\n }\n };\n}\n\nexport default async function remnicPiExtension(pi: PiApi): Promise<void> {\n await createRemnicPiExtension()(pi);\n}\n\nfunction registerCommands(pi: PiApi, client: RemnicClient, config: RemnicPiConfig): void {\n pi.registerCommand(\"remnic-status\", {\n description: \"Check Remnic daemon status\",\n handler: commandHandler(async (_args, _ctx, session) => {\n const health = await client.health();\n session.notify(`Remnic ${health.ok ? \"healthy\" : \"unhealthy\"} at ${config.remnicDaemonUrl}`, health.ok ? \"success\" : \"warning\");\n }),\n });\n\n pi.registerCommand(\"remnic-recall\", {\n description: \"Recall Remnic context for a query\",\n handler: commandHandler(async (args, _ctx, session) => {\n const query = args.trim();\n if (!query) {\n session.notify(\"Usage: /remnic-recall <query>\", \"warning\");\n return;\n }\n const result = await client.recall(query, session.sessionKey, session.cwd);\n session.notify(trimContext(result.context ?? \"(no Remnic context)\", MAX_CONTEXT_CHARS), \"info\");\n }),\n });\n\n pi.registerCommand(\"remnic-remember\", {\n description: \"Store a Remnic memory\",\n handler: commandHandler(async (args, _ctx, session) => {\n const content = args.trim();\n if (!content) {\n session.notify(\"Usage: /remnic-remember <memory>\", \"warning\");\n return;\n }\n await client.storeMemory(content, session.sessionKey);\n session.notify(\"Stored Remnic memory\", \"success\");\n }),\n });\n\n pi.registerCommand(\"remnic-lcm-search\", {\n description: \"Search Remnic LCM archived Pi context\",\n handler: commandHandler(async (args, _ctx, session) => {\n const query = args.trim();\n if (!query) {\n session.notify(\"Usage: /remnic-lcm-search <query>\", \"warning\");\n return;\n }\n const result = await client.lcmSearch(query, session.sessionKey);\n session.notify(JSON.stringify(result, null, 2), \"info\");\n }),\n });\n\n pi.registerCommand(\"remnic-why\", {\n description: \"Explain the last Remnic recall\",\n handler: commandHandler(async (_args, _ctx, session) => {\n const result = await client.recallExplain(session.sessionKey);\n session.notify(JSON.stringify(result, null, 2), \"info\");\n }),\n });\n\n pi.registerCommand(\"remnic-compact\", {\n description: \"Trigger Pi compaction with Remnic LCM coordination\",\n handler: commandHandler(async (_args, _ctx, session) => {\n session.compact?.();\n session.notify(\"Compaction requested\", \"info\");\n }),\n });\n}\n\nfunction commandHandler(\n handler: (args: string, ctx: any, session: PiContextSnapshot) => Promise<void>,\n): (args: string, ctx: any) => Promise<void> {\n return async (args, ctx) => {\n const session = snapshotPiContext(ctx);\n if (!session) return;\n try {\n await handler(args, ctx, session);\n } catch (err) {\n session.notify(`Remnic command failed: ${errorMessage(err)}`, \"warning\");\n }\n };\n}\n\nasync function registerMcpTools(pi: PiApi, client: RemnicClient, config: RemnicPiConfig): Promise<void> {\n let tools: McpTool[] = [];\n try {\n tools = await client.mcpListTools({ timeoutMs: config.startupRequestTimeoutMs });\n } catch {\n return;\n }\n for (const tool of tools) {\n if (!tool.name.startsWith(\"remnic.\")) continue;\n const piToolName = tool.name.replace(/^remnic\\./, \"remnic_\").replace(/[^a-zA-Z0-9_]/g, \"_\");\n pi.registerTool({\n name: piToolName,\n label: tool.name,\n description: tool.description ?? `Call ${tool.name}`,\n parameters: toPiToolParametersSchema(tool.inputSchema),\n async execute(_toolCallId: string, params: Record<string, unknown>, _signal: AbortSignal | undefined, _onUpdate: unknown, ctx: any) {\n const session = snapshotPiContext(ctx);\n if (!session) {\n return {\n content: [{ type: \"text\", text: \"Remnic tool skipped because the Pi context is no longer active.\" }],\n details: { skipped: true, reason: \"stale_context\" },\n };\n }\n const safeParams = stripSessionOwnedRuntimeFields(params ?? {}) as Record<string, unknown>;\n const result = await client.mcpTool(tool.name, {\n ...safeParams,\n sessionKey: session.sessionKey,\n namespace: config.namespace,\n cwd: session.cwd,\n });\n return {\n content: [{ type: \"text\", text: JSON.stringify(result, null, 2) }],\n details: result,\n };\n },\n });\n }\n}\n\nexport function toPiToolParametersSchema(inputSchema: unknown): TSchema {\n return Type.Unsafe(stripSessionOwnedSchemaFields(inputSchema));\n}\n\nexport function stripSessionOwnedSchemaFields(inputSchema: unknown): Record<string, unknown> {\n if (!isRecord(inputSchema)) {\n return { type: \"object\", properties: {}, additionalProperties: true };\n }\n return stripSessionOwnedSchemaNode(inputSchema) as Record<string, unknown>;\n}\n\nfunction stripSessionOwnedSchemaNode(value: unknown): unknown {\n if (Array.isArray(value)) {\n return value.map((entry) => stripSessionOwnedSchemaNode(entry));\n }\n if (!isRecord(value)) {\n return value;\n }\n const schema: Record<string, unknown> = { ...value };\n if (isRecord(value.properties)) {\n const properties: Record<string, unknown> = {};\n for (const [key, property] of Object.entries(value.properties)) {\n if (SESSION_OWNED_FIELDS.has(key)) continue;\n properties[key] = stripSessionOwnedSchemaNode(property);\n }\n schema.properties = properties;\n }\n if (Array.isArray(value.required)) {\n schema.required = value.required.filter(\n (field) => typeof field !== \"string\" || !SESSION_OWNED_FIELDS.has(field),\n );\n }\n for (const key of [\"items\", \"additionalProperties\", \"not\"] as const) {\n if (isRecord(value[key])) {\n schema[key] = stripSessionOwnedSchemaNode(value[key]);\n }\n }\n for (const key of [\"oneOf\", \"anyOf\", \"allOf\"] as const) {\n if (Array.isArray(value[key])) {\n schema[key] = value[key].map((entry) => stripSessionOwnedSchemaNode(entry));\n }\n }\n return schema;\n}\n\nexport function stripSessionOwnedRuntimeFields(value: unknown): unknown {\n if (Array.isArray(value)) {\n return value.map((entry) => stripSessionOwnedRuntimeFields(entry));\n }\n if (!isRecord(value)) {\n return value;\n }\n const sanitized: Record<string, unknown> = {};\n for (const [key, child] of Object.entries(value)) {\n if (SESSION_OWNED_FIELDS.has(key)) continue;\n sanitized[key] = stripSessionOwnedRuntimeFields(child);\n }\n return sanitized;\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return !!value && typeof value === \"object\" && !Array.isArray(value);\n}\n\nfunction isUserMessage(message: unknown): boolean {\n return isRecord(message) && message.role === \"user\";\n}\n\nfunction getSessionState(sessionKey: string, states: Map<string, PiSessionState>): { sessionKey: string; state: PiSessionState } {\n let state = states.get(sessionKey);\n if (!state) {\n state = {\n observedHashes: new Set<string>(),\n liveObservedReplayKeys: new Map<string, number>(),\n lastInjectedRecallKey: \"\",\n };\n states.set(sessionKey, state);\n pruneSessionStates(states);\n }\n return { sessionKey, state };\n}\n\nfunction pruneSessionStates(states: Map<string, PiSessionState>): void {\n while (states.size > MAX_SESSION_STATES) {\n const oldest = states.keys().next().value;\n if (typeof oldest !== \"string\") return;\n states.delete(oldest);\n }\n}\n\nexport async function observeMessages(\n ctx: any,\n client: RemnicClient,\n rawMessages: unknown[],\n observedHashes: Set<string>,\n liveObservedReplayKeys?: Map<string, number>,\n): Promise<void> {\n const session = snapshotPiContext(ctx);\n if (!session) return;\n await observeMessagesForSession(session, client, rawMessages, observedHashes, liveObservedReplayKeys);\n}\n\nasync function observeMessagesForSession(\n session: PiContextSnapshot,\n client: RemnicClient,\n rawMessages: unknown[],\n observedHashes: Set<string>,\n liveObservedReplayKeys?: Map<string, number>,\n): Promise<void> {\n const messages: ObserveMessage[] = [];\n const pendingHashes = new Set<string>();\n for (const raw of rawMessages) {\n const message = toObserveMessage(raw);\n if (!message) continue;\n const hash = observedMessageDedupeKey(message, session.sessionKey);\n if (hash && (observedHashes.has(hash) || pendingHashes.has(hash))) continue;\n if (hash) pendingHashes.add(hash);\n messages.push(message);\n }\n if (messages.length === 0) return;\n try {\n await client.observe(session.sessionKey, session.cwd, messages);\n for (const hash of pendingHashes) rememberObservedHash(observedHashes, hash);\n if (liveObservedReplayKeys) {\n for (const message of messages) {\n rememberLiveObservedReplayKey(liveObservedReplayKeys, liveReplayKey(message, session.sessionKey));\n }\n }\n } catch (err) {\n session.notify(`Remnic observe failed: ${errorMessage(err)}`, \"warning\");\n }\n}\n\nexport function buildCompactionSummary(preparation: any): string {\n const previousSummary = typeof preparation.previousSummary === \"string\"\n ? preparation.previousSummary.trim()\n : \"\";\n const messages = [\n ...(Array.isArray(preparation.messagesToSummarize) ? preparation.messagesToSummarize : []),\n ...(Array.isArray(preparation.turnPrefixMessages) ? preparation.turnPrefixMessages : []),\n ];\n const transcript = summarizeMessages(messages, 24000);\n const details = fileDetailsFromPreparation(preparation);\n\n if (\n !previousSummary &&\n !transcript &&\n details.readFiles.length === 0 &&\n details.modifiedFiles.length === 0\n ) {\n return \"\";\n }\n\n const sections: string[] = [\n \"## Remnic Pi Context Checkpoint\",\n \"\",\n \"This checkpoint was created by Remnic during Pi context compaction.\",\n ];\n if (previousSummary) sections.push(\"\", \"## Previous Summary\", previousSummary);\n if (transcript) sections.push(\"\", \"## Conversation Excerpt\", transcript);\n if (details.readFiles.length > 0) sections.push(\"\", \"<read-files>\", ...details.readFiles, \"</read-files>\");\n if (details.modifiedFiles.length > 0) sections.push(\"\", \"<modified-files>\", ...details.modifiedFiles, \"</modified-files>\");\n return sections.join(\"\\n\");\n}\n\nfunction fileDetailsFromPreparation(preparation: any): { readFiles: string[]; modifiedFiles: string[] } {\n const fileOps = preparation?.fileOps;\n const read = fileOps?.read instanceof Set ? Array.from(fileOps.read).filter(isString) : [];\n const edited = fileOps?.edited instanceof Set ? Array.from(fileOps.edited).filter(isString) : [];\n const written = fileOps?.written instanceof Set ? Array.from(fileOps.written).filter(isString) : [];\n const modified = new Set([...edited, ...written]);\n return {\n readFiles: read.filter((file) => !modified.has(file)).sort(),\n modifiedFiles: Array.from(modified).sort(),\n };\n}\n\nfunction restoreObservedState(session: PiContextSnapshot, observedHashes: Set<string>): void {\n for (const entry of session.entries) {\n if (entry?.type !== \"custom\" || entry.customType !== STATE_CUSTOM_TYPE) continue;\n const hashes = entry.data?.observedHashes;\n if (Array.isArray(hashes)) {\n for (const hash of hashes) {\n if (typeof hash === \"string\") rememberObservedHash(observedHashes, hash);\n }\n }\n }\n}\n\nfunction rememberObservedHash(observedHashes: Set<string>, hash: string): void {\n if (observedHashes.has(hash)) return;\n while (observedHashes.size >= MAX_OBSERVED_HASHES) {\n const oldest = observedHashes.keys().next().value;\n if (typeof oldest !== \"string\") break;\n observedHashes.delete(oldest);\n }\n observedHashes.add(hash);\n}\n\nfunction rememberLiveObservedReplayKey(liveObservedReplayKeys: Map<string, number>, key: string): void {\n liveObservedReplayKeys.set(key, (liveObservedReplayKeys.get(key) ?? 0) + 1);\n}\n\nfunction consumeLiveObservedReplayKey(liveObservedReplayKeys: Map<string, number>, key: string): boolean {\n const count = liveObservedReplayKeys.get(key) ?? 0;\n if (count <= 0) return false;\n if (count === 1) liveObservedReplayKeys.delete(key);\n else liveObservedReplayKeys.set(key, count - 1);\n return true;\n}\n\nfunction skipLiveObservedReplayMessages(\n sessionKey: string,\n rawMessages: unknown[],\n liveObservedReplayKeys: Map<string, number>,\n): unknown[] {\n if (liveObservedReplayKeys.size === 0) return rawMessages;\n const unobserved: unknown[] = [];\n for (const raw of rawMessages) {\n const message = toObserveMessage(raw);\n if (message && consumeLiveObservedReplayKey(liveObservedReplayKeys, liveReplayKey(message, sessionKey))) {\n continue;\n }\n unobserved.push(raw);\n }\n return unobserved;\n}\n\nfunction liveReplayKey(message: ObserveMessage, sessionKey: string): string {\n return hashObservedMessage(message, sessionKey, \"live-replay\");\n}\n\nfunction persistObservedState(pi: PiApi, observedHashes: Set<string>): void {\n const observed = Array.from(observedHashes).slice(-MAX_OBSERVED_HASHES);\n pi.appendEntry(STATE_CUSTOM_TYPE, {\n observedHashes: observed,\n recordedAt: new Date().toISOString(),\n });\n}\n\nasync function setStatus(session: PiContextSnapshot, client: RemnicClient, config: RemnicPiConfig): Promise<void> {\n try {\n await client.health({ timeoutMs: config.startupRequestTimeoutMs });\n session.setStatus(\"remnic\", `Remnic ${config.namespace ? `(${config.namespace})` : \"ready\"}`);\n } catch {\n session.setStatus(\"remnic\", \"Remnic offline\");\n }\n}\n\nfunction snapshotPiContext(ctx: any, options: PiContextSnapshotOptions = {}): PiContextSnapshot | null {\n const sessionKey = safeSessionKeyFromContext(ctx);\n if (!sessionKey) return null;\n const cwd = safeStringRead(() => ctx?.cwd, \"\");\n const hasUI = safeRead(() => ctx?.hasUI, undefined) === false;\n const ui = hasUI ? undefined : safeRead(() => ctx?.ui, undefined);\n const compact = safeRead(() => ctx?.compact, undefined);\n const includeSessionHistory = options.includeSessionHistory === true;\n return {\n sessionKey,\n cwd,\n entries: includeSessionHistory ? safeEntries(ctx) : [],\n branch: includeSessionHistory ? safeBranch(ctx) : [],\n notify: makeNotifier(ui, hasUI),\n setStatus: makeStatusSetter(ui, hasUI),\n compact: typeof compact === \"function\" ? () => compact.call(ctx) : undefined,\n };\n}\n\nfunction safeSessionKeyFromContext(ctx: any): string | null {\n try {\n return sessionKeyFromContext(ctx);\n } catch {\n return null;\n }\n}\n\nfunction makeNotifier(ui: unknown, hasUI: boolean): NotifyFn {\n if (hasUI || !isRecord(ui) || typeof ui.notify !== \"function\") {\n return () => undefined;\n }\n const notifyFn = ui.notify;\n return (message, level) => {\n try {\n notifyFn.call(ui, message, level);\n } catch {\n // Pi invalidates session-bound UI objects during reload/replacement. A\n // notification failure must not tear down Remnic's hooks.\n }\n };\n}\n\nfunction makeStatusSetter(ui: unknown, hasUI: boolean): PiContextSnapshot[\"setStatus\"] {\n if (hasUI || !isRecord(ui) || typeof ui.setStatus !== \"function\") {\n return () => undefined;\n }\n const setStatusFn = ui.setStatus;\n return (key, value) => {\n try {\n setStatusFn.call(ui, key, value);\n } catch {\n // See makeNotifier: stale UI should not make extension startup fail.\n }\n };\n}\n\nfunction safeRead<T>(read: () => T, fallback: T): T {\n try {\n return read();\n } catch {\n return fallback;\n }\n}\n\nfunction safeStringRead(read: () => unknown, fallback: string): string {\n const value = safeRead(read, fallback);\n return typeof value === \"string\" ? value : fallback;\n}\n\nfunction safeEntries(ctx: any): any[] {\n try {\n const entries = ctx.sessionManager?.getEntries?.();\n return Array.isArray(entries) ? entries : [];\n } catch {\n return [];\n }\n}\n\nfunction safeBranch(ctx: any): any[] {\n try {\n const branch = ctx.sessionManager?.getBranch?.();\n return Array.isArray(branch) ? branch : [];\n } catch {\n return [];\n }\n}\n\nfunction branchMessagesWithEntryIdentity(branch: any[]): unknown[] {\n const messages: unknown[] = [];\n for (const entry of branch) {\n const message = messageWithEntryIdentity(entry);\n if (message) messages.push(message);\n }\n return messages;\n}\n\nfunction messageWithEntryIdentity(entry: any): unknown | null {\n const message = entry?.message;\n if (!message || typeof message !== \"object\" || Array.isArray(message)) return message ?? null;\n\n const source = isRecord(entry) ? entry : {};\n const enriched: Record<string, unknown> = { ...(message as Record<string, unknown>) };\n assignMissingIdentity(enriched, \"entryId\", source.id ?? source.entryId ?? source.entry_id);\n assignMissingIdentity(enriched, \"timestamp\", source.timestamp);\n assignMissingIdentity(enriched, \"createdAt\", source.createdAt ?? source.created_at);\n return enriched;\n}\n\nfunction assignMissingIdentity(target: Record<string, unknown>, field: string, value: unknown): void {\n if (target[field] !== undefined) return;\n if (typeof value === \"string\" && value.length > 0) {\n target[field] = value;\n return;\n }\n if (typeof value === \"number\" && Number.isFinite(value)) {\n target[field] = value;\n }\n}\n\nfunction trimContext(value: string, budget: number): string {\n if (value.length <= budget) return value;\n if (budget <= TRUNCATION_NOTICE.length) return TRUNCATION_NOTICE.slice(0, budget);\n return `${value.slice(0, budget - TRUNCATION_NOTICE.length)}${TRUNCATION_NOTICE}`;\n}\n\nfunction errorMessage(err: unknown): string {\n return err instanceof Error ? err.message : String(err);\n}\n\nfunction finiteTokenCount(value: unknown): number | null {\n return typeof value === \"number\" && Number.isFinite(value) && value >= 0 ? value : null;\n}\n\nfunction isString(value: unknown): value is string {\n return typeof value === \"string\";\n}\n\nexport { textFromMessage };\n","import { existsSync, readFileSync } from \"node:fs\";\nimport path from \"node:path\";\n\nimport { expandTildePath } from \"@remnic/core\";\n\nimport { REMNIC_PI_EXTENSION_DIR_NAME, resolvePiAgentHome } from \"./paths.js\";\n\nexport interface RemnicPiConfig {\n remnicDaemonUrl: string;\n authToken?: string;\n namespace?: string;\n recallMode: \"auto\" | \"minimal\" | \"full\" | \"graph_mode\" | \"no_recall\";\n recallTopK: number;\n recallBudgetChars: number;\n recallEnabled: boolean;\n observeEnabled: boolean;\n observeSkipExtraction: boolean;\n compactionEnabled: boolean;\n mcpToolsEnabled: boolean;\n statusEnabled: boolean;\n requestTimeoutMs: number;\n startupRequestTimeoutMs: number;\n}\n\nexport interface LoadConfigOptions {\n configPath?: string;\n env?: NodeJS.ProcessEnv;\n}\n\nconst DEFAULT_CONFIG: RemnicPiConfig = {\n remnicDaemonUrl: \"http://127.0.0.1:4318\",\n recallMode: \"auto\",\n recallTopK: 8,\n recallBudgetChars: 12000,\n recallEnabled: true,\n observeEnabled: true,\n observeSkipExtraction: false,\n compactionEnabled: true,\n mcpToolsEnabled: true,\n statusEnabled: true,\n requestTimeoutMs: 60000,\n startupRequestTimeoutMs: 1000,\n};\n\nfunction defaultConfigPath(env: NodeJS.ProcessEnv): string {\n return path.join(resolvePiAgentHome(env), \"extensions\", REMNIC_PI_EXTENSION_DIR_NAME, \"remnic.config.json\");\n}\n\nfunction coerceBoolean(value: unknown, fallback: boolean, fieldName: string): boolean {\n if (value === undefined || value === null) return fallback;\n if (typeof value === \"boolean\") return value;\n if (typeof value === \"string\") {\n const normalized = value.trim().toLowerCase();\n if ([\"true\", \"1\", \"yes\", \"on\"].includes(normalized)) return true;\n if ([\"false\", \"0\", \"no\", \"off\"].includes(normalized)) return false;\n }\n throw new Error(`Invalid boolean value for Remnic Pi config field ${fieldName}`);\n}\n\nfunction coercePositiveInt(value: unknown, fallback: number, max: number, fieldName: string): number {\n if (value === undefined || value === null || value === \"\") return fallback;\n let parsed: number;\n if (typeof value === \"number\") {\n parsed = value;\n } else if (typeof value === \"string\") {\n const trimmed = value.trim();\n if (trimmed.length === 0) return fallback;\n if (!/^[+-]?\\d+$/.test(trimmed)) {\n throw new Error(`Invalid numeric value for Remnic Pi config field ${fieldName}: expected an integer from 1 to ${max}`);\n }\n parsed = Number(trimmed);\n } else {\n throw new Error(`Invalid numeric value for Remnic Pi config field ${fieldName}: expected an integer from 1 to ${max}`);\n }\n if (!Number.isInteger(parsed) || parsed <= 0 || parsed > max) {\n throw new Error(`Invalid numeric value for Remnic Pi config field ${fieldName}: expected an integer from 1 to ${max}`);\n }\n return parsed;\n}\n\nfunction coerceOptionalNonEmptyString(value: unknown, fieldName: string): string | undefined {\n if (value === undefined || value === null) return undefined;\n if (typeof value === \"string\" && value.trim().length > 0) return value.trim();\n throw new Error(`Invalid string value for Remnic Pi config field ${fieldName}`);\n}\n\nfunction coerceOptionalString(value: unknown, fieldName: string): string | undefined {\n if (value === undefined || value === null) return undefined;\n if (typeof value === \"string\") {\n const trimmed = value.trim();\n return trimmed.length > 0 ? trimmed : undefined;\n }\n throw new Error(`Invalid string value for Remnic Pi config field ${fieldName}`);\n}\n\nfunction coerceOptionalHttpUrl(value: unknown, fieldName: string): string | undefined {\n if (value === undefined || value === null) return undefined;\n if (typeof value !== \"string\") {\n throw new Error(`Invalid URL value for Remnic Pi config field ${fieldName}: expected an http or https URL`);\n }\n const trimmed = value.trim();\n if (trimmed.length === 0) return undefined;\n try {\n const parsed = new URL(trimmed);\n if (parsed.protocol === \"http:\" || parsed.protocol === \"https:\") return trimTrailingSlashes(trimmed);\n } catch {\n // Fall through to the shared error below.\n }\n throw new Error(`Invalid URL value for Remnic Pi config field ${fieldName}: expected an http or https URL`);\n}\n\nfunction coerceRecallMode(value: unknown): RemnicPiConfig[\"recallMode\"] {\n if (value === undefined || value === null || value === \"\") return DEFAULT_CONFIG.recallMode;\n if (\n value === \"minimal\" ||\n value === \"full\" ||\n value === \"graph_mode\" ||\n value === \"no_recall\" ||\n value === \"auto\"\n ) {\n return value;\n }\n throw new Error(`Invalid recallMode value for Remnic Pi config: ${JSON.stringify(value)}`);\n}\n\nfunction readConfigFile(configPath: string): Record<string, unknown> {\n if (!existsSync(configPath)) return {};\n try {\n const raw = readFileSync(configPath, \"utf-8\");\n const parsed = JSON.parse(raw);\n if (parsed && typeof parsed === \"object\" && !Array.isArray(parsed)) {\n return parsed as Record<string, unknown>;\n }\n throw new Error(\"expected a JSON object\");\n } catch (err) {\n const reason = err instanceof Error ? err.message : String(err);\n throw new Error(`Failed to load Remnic Pi config at ${configPath}: ${reason}`);\n }\n}\n\nfunction trimTrailingSlashes(value: string): string {\n let end = value.length;\n while (end > 0 && value.charCodeAt(end - 1) === 47) end -= 1;\n return value.slice(0, end);\n}\n\nexport function resolveConfigPath(options: LoadConfigOptions = {}): string {\n const env = options.env ?? process.env;\n return expandTildePath(options.configPath || env.REMNIC_PI_CONFIG || defaultConfigPath(env));\n}\n\nexport function loadConfig(options: LoadConfigOptions = {}): RemnicPiConfig {\n const env = options.env ?? process.env;\n const fileConfig = readConfigFile(resolveConfigPath(options));\n const daemonUrl =\n coerceOptionalHttpUrl(fileConfig.remnicDaemonUrl, \"remnicDaemonUrl\") ??\n coerceOptionalHttpUrl(env.REMNIC_DAEMON_URL, \"REMNIC_DAEMON_URL\") ??\n DEFAULT_CONFIG.remnicDaemonUrl;\n const authToken =\n coerceOptionalString(fileConfig.authToken, \"authToken\") ??\n coerceOptionalString(env.REMNIC_PI_AUTH_TOKEN, \"REMNIC_PI_AUTH_TOKEN\");\n const namespace = coerceOptionalNonEmptyString(fileConfig.namespace, \"namespace\");\n\n return {\n remnicDaemonUrl: daemonUrl,\n authToken,\n namespace,\n recallMode: coerceRecallMode(fileConfig.recallMode),\n recallTopK: coercePositiveInt(fileConfig.recallTopK, DEFAULT_CONFIG.recallTopK, 50, \"recallTopK\"),\n recallBudgetChars: coercePositiveInt(fileConfig.recallBudgetChars, DEFAULT_CONFIG.recallBudgetChars, 64000, \"recallBudgetChars\"),\n recallEnabled: coerceBoolean(fileConfig.recallEnabled, DEFAULT_CONFIG.recallEnabled, \"recallEnabled\"),\n observeEnabled: coerceBoolean(fileConfig.observeEnabled, DEFAULT_CONFIG.observeEnabled, \"observeEnabled\"),\n observeSkipExtraction: coerceBoolean(fileConfig.observeSkipExtraction, DEFAULT_CONFIG.observeSkipExtraction, \"observeSkipExtraction\"),\n compactionEnabled: coerceBoolean(fileConfig.compactionEnabled, DEFAULT_CONFIG.compactionEnabled, \"compactionEnabled\"),\n mcpToolsEnabled: coerceBoolean(fileConfig.mcpToolsEnabled, DEFAULT_CONFIG.mcpToolsEnabled, \"mcpToolsEnabled\"),\n statusEnabled: coerceBoolean(fileConfig.statusEnabled, DEFAULT_CONFIG.statusEnabled, \"statusEnabled\"),\n requestTimeoutMs: coercePositiveInt(fileConfig.requestTimeoutMs, DEFAULT_CONFIG.requestTimeoutMs, 60_000, \"requestTimeoutMs\"),\n startupRequestTimeoutMs: coercePositiveInt(\n fileConfig.startupRequestTimeoutMs,\n DEFAULT_CONFIG.startupRequestTimeoutMs,\n 60_000,\n \"startupRequestTimeoutMs\",\n ),\n };\n}\n","import type { RemnicPiConfig } from \"./config.js\";\n\nexport interface RecallResponse {\n context?: string;\n results?: Array<{ id?: string; content?: string; score?: number; category?: string }>;\n count?: number;\n}\n\nexport interface ObserveMessagePart {\n ordinal?: number;\n kind: \"text\" | \"tool_call\" | \"tool_result\" | \"patch\" | \"file_read\" | \"file_write\" | \"step_start\" | \"step_finish\" | \"snapshot\" | \"retry\";\n payload: Record<string, unknown>;\n toolName?: string | null;\n filePath?: string | null;\n createdAt?: string | null;\n}\n\nexport interface ObserveMessage {\n role: \"user\" | \"assistant\";\n content: string;\n sourceFormat?: \"pi\";\n rawContent?: unknown;\n parts?: ObserveMessagePart[];\n}\n\nexport interface McpTool {\n name: string;\n description?: string;\n inputSchema?: Record<string, unknown>;\n}\n\nexport class RemnicHttpError extends Error {\n constructor(\n readonly status: number,\n message: string,\n ) {\n super(message);\n }\n}\n\nexport class RemnicClient {\n private requestId = 0;\n\n constructor(private readonly config: RemnicPiConfig) {}\n\n async health(options: RequestOptions = {}): Promise<Record<string, unknown>> {\n return this.request(\"GET\", \"/engram/v1/health\", undefined, options);\n }\n\n async recall(query: string, sessionKey: string, cwd: string): Promise<RecallResponse> {\n return this.request(\"POST\", \"/engram/v1/recall\", {\n query,\n sessionKey,\n cwd,\n namespace: this.config.namespace,\n topK: this.config.recallTopK,\n mode: this.config.recallMode,\n });\n }\n\n async recallExplain(sessionKey: string): Promise<Record<string, unknown>> {\n return this.request(\"POST\", \"/engram/v1/recall/explain\", {\n sessionKey,\n namespace: this.config.namespace,\n });\n }\n\n async observe(sessionKey: string, cwd: string, messages: ObserveMessage[]): Promise<Record<string, unknown>> {\n return this.request(\"POST\", \"/engram/v1/observe\", {\n sessionKey,\n cwd,\n namespace: this.config.namespace,\n skipExtraction: this.config.observeSkipExtraction,\n messages,\n });\n }\n\n async storeMemory(content: string, sessionKey: string): Promise<Record<string, unknown>> {\n return this.request(\"POST\", \"/engram/v1/memories\", {\n content,\n category: \"fact\",\n sourceReason: \"Captured from Pi via Remnic extension\",\n sessionKey,\n namespace: this.config.namespace,\n });\n }\n\n async lcmSearch(query: string, sessionKey: string, limit = 10): Promise<Record<string, unknown>> {\n return this.request(\"POST\", \"/engram/v1/lcm/search\", {\n query,\n sessionKey,\n namespace: this.config.namespace,\n limit,\n });\n }\n\n async lcmCompactionFlush(sessionKey: string): Promise<Record<string, unknown>> {\n return this.request(\"POST\", \"/engram/v1/lcm/compaction/flush\", {\n sessionKey,\n namespace: this.config.namespace,\n });\n }\n\n async lcmCompactionRecord(sessionKey: string, tokensBefore: number, tokensAfter: number): Promise<Record<string, unknown>> {\n return this.request(\"POST\", \"/engram/v1/lcm/compaction/record\", {\n sessionKey,\n namespace: this.config.namespace,\n tokensBefore,\n tokensAfter,\n });\n }\n\n async contextCheckpoint(sessionKey: string, context: string): Promise<Record<string, unknown>> {\n return this.mcpTool(\"remnic.context_checkpoint\", {\n sessionKey,\n context,\n namespace: this.config.namespace,\n });\n }\n\n async mcpListTools(options: RequestOptions = {}): Promise<McpTool[]> {\n const result = await this.mcpRequest(\"tools/list\", {}, options);\n const tools = (result as { tools?: unknown }).tools;\n return Array.isArray(tools) ? tools.filter(isMcpTool) : [];\n }\n\n async mcpTool(name: string, args: Record<string, unknown>): Promise<Record<string, unknown>> {\n return this.mcpRequest(\"tools/call\", {\n name,\n arguments: args,\n });\n }\n\n private async request<T = Record<string, unknown>>(\n method: string,\n pathname: string,\n body?: unknown,\n options: RequestOptions = {},\n ): Promise<T> {\n const controller = new AbortController();\n // A per-request override is honored only when it is a finite positive number;\n // 0, negative, NaN, or non-finite values would make setTimeout abort\n // immediately (or behave erratically), so fall back to the general budget.\n // In practice the override is always sourced from the validated\n // `startupRequestTimeoutMs` config, but this keeps the client robust to any\n // future caller (Copilot review).\n const override = options.timeoutMs;\n const timeoutMs =\n typeof override === \"number\" && Number.isFinite(override) && override > 0\n ? override\n : this.config.requestTimeoutMs;\n const timeout = setTimeout(() => controller.abort(), timeoutMs);\n try {\n const response = await fetch(`${this.config.remnicDaemonUrl}${pathname}`, {\n method,\n headers: {\n ...(body === undefined ? {} : { \"Content-Type\": \"application/json\" }),\n ...(this.config.authToken ? { Authorization: `Bearer ${this.config.authToken}` } : {}),\n \"X-Engram-Client-Id\": \"pi\",\n },\n body: body === undefined ? undefined : JSON.stringify(body),\n signal: controller.signal,\n });\n const text = await response.text();\n let payload: unknown = {};\n let parseError: unknown;\n if (text) {\n try {\n payload = JSON.parse(text);\n } catch (err) {\n parseError = err;\n }\n }\n if (!response.ok) {\n throw new RemnicHttpError(response.status, responseErrorMessage(response, text, payload, parseError));\n }\n if (parseError) {\n const reason = parseError instanceof Error ? parseError.message : String(parseError);\n throw new Error(`Invalid JSON response from Remnic daemon (${response.status} ${response.statusText || \"OK\"}): ${reason}`);\n }\n return payload as T;\n } catch (err) {\n if (isAbortError(err)) {\n throw new Error(`Remnic request timed out after ${timeoutMs}ms`);\n }\n throw err;\n } finally {\n clearTimeout(timeout);\n }\n }\n\n private async mcpRequest(\n method: string,\n params: Record<string, unknown>,\n options: RequestOptions = {},\n ): Promise<Record<string, unknown>> {\n this.requestId += 1;\n const payload = await this.request<Record<string, unknown>>(\"POST\", \"/mcp\", {\n jsonrpc: \"2.0\",\n id: this.requestId,\n method,\n params,\n }, options);\n if (payload.error) {\n throw new Error(JSON.stringify(payload.error));\n }\n return (payload.result && typeof payload.result === \"object\" ? payload.result : payload) as Record<string, unknown>;\n }\n}\n\ninterface RequestOptions {\n timeoutMs?: number;\n}\n\nfunction isMcpTool(value: unknown): value is McpTool {\n return !!value && typeof value === \"object\" && typeof (value as { name?: unknown }).name === \"string\";\n}\n\nfunction isAbortError(err: unknown): boolean {\n return err instanceof Error && (err.name === \"AbortError\" || err.message === \"This operation was aborted\");\n}\n\nfunction responseErrorMessage(response: Response, text: string, payload: unknown, parseError: unknown): string {\n if (!parseError && payload && typeof payload === \"object\") {\n const error = (payload as { error?: unknown }).error;\n if (typeof error === \"string\" && error.trim().length > 0) {\n return error;\n }\n const message = (payload as { message?: unknown }).message;\n if (typeof message === \"string\" && message.trim().length > 0) {\n return message;\n }\n }\n\n const snippet = text.trim().replace(/\\s+/g, \" \").slice(0, 200);\n if (snippet.length > 0) {\n return response.statusText ? `${response.statusText}: ${snippet}` : snippet;\n }\n return response.statusText || `HTTP ${response.status}`;\n}\n","import { createHash } from \"node:crypto\";\n\nimport { parsePiMessageParts, type LcmMessagePartInput } from \"@remnic/core\";\n\nimport type { ObserveMessage, ObserveMessagePart } from \"./client.js\";\n\ntype PiMessage = Record<string, unknown>;\n\nexport function sessionKeyFromContext(ctx: { sessionManager?: { getSessionId?: () => string } }): string {\n const id = ctx.sessionManager?.getSessionId?.();\n return id && id.trim().length > 0 ? `pi:${id}` : \"pi:default\";\n}\n\nexport function textFromMessage(message: unknown): string {\n if (!message || typeof message !== \"object\") return \"\";\n const obj = message as PiMessage;\n const role = typeof obj.role === \"string\" ? obj.role : \"message\";\n if (role === \"bashExecution\") {\n const command = typeof obj.command === \"string\" ? obj.command : \"\";\n const output = typeof obj.output === \"string\" ? obj.output : \"\";\n return [`Ran ${command}`, output].filter(Boolean).join(\"\\n\");\n }\n return textFromContent(obj.content).trim();\n}\n\nexport function latestUserQuery(messages: unknown[]): string {\n for (let index = messages.length - 1; index >= 0; index--) {\n const message = messages[index] as PiMessage;\n if (isExcludedFromContext(message) || isRemnicInjected(message)) continue;\n if (message?.role === \"user\") {\n const text = textFromMessage(message);\n if (text.length > 0) return text;\n }\n }\n return \"\";\n}\n\nexport function latestUserRecallTarget(\n messages: unknown[],\n): { query: string; dedupeKey: string } | null {\n for (let index = messages.length - 1; index >= 0; index--) {\n const message = messages[index] as PiMessage;\n if (isExcludedFromContext(message) || isRemnicInjected(message)) continue;\n if (message?.role !== \"user\") continue;\n const query = textFromMessage(message);\n if (query.length === 0) continue;\n const identity = stableObservedMessageIdentity(message);\n return {\n query,\n dedupeKey: identity ? `message:${identity}:${query}` : `query:${query}`,\n };\n }\n return null;\n}\n\nexport function toObserveMessage(message: unknown): ObserveMessage | null {\n if (!message || typeof message !== \"object\") return null;\n const obj = message as PiMessage;\n if (isExcludedFromContext(obj) || isRemnicInjected(obj)) return null;\n const role = obj.role === \"user\" || obj.role === \"bashExecution\" ? \"user\" : \"assistant\";\n const content = textFromMessage(obj);\n if (content.length === 0) return null;\n return {\n role,\n content,\n sourceFormat: \"pi\",\n rawContent: obj,\n parts: partsFromMessage(obj, content),\n };\n}\n\nexport function hashObservedMessage(message: ObserveMessage, sessionKey = \"\", identity = \"content\"): string {\n return createHash(\"sha256\")\n .update(sessionKey)\n .update(\"\\0\")\n .update(message.role)\n .update(\"\\0\")\n .update(identity)\n .update(\"\\0\")\n .update(message.content)\n .digest(\"hex\");\n}\n\nexport function observedMessageDedupeKey(\n message: ObserveMessage,\n sessionKey = \"\",\n): string | null {\n const identity = stableObservedMessageIdentity(message.rawContent);\n return identity ? hashObservedMessage(message, sessionKey, identity) : null;\n}\n\nexport function summarizeMessages(messages: unknown[], maxChars: number): string {\n const chunks: string[] = [];\n let used = 0;\n for (const message of messages) {\n if (isExcludedFromContext(message) || isRemnicInjected(message)) continue;\n const text = textFromMessage(message);\n if (!text) continue;\n const role = typeof (message as PiMessage)?.role === \"string\" ? (message as PiMessage).role : \"message\";\n const line = `[${role}] ${text}`;\n const separatorLength = chunks.length > 0 ? 2 : 0;\n const remaining = maxChars - used - separatorLength;\n if (remaining <= 0) break;\n const clipped = line.length > remaining ? line.slice(0, remaining) : line;\n if (clipped.length > 0) chunks.push(clipped);\n used += separatorLength + clipped.length;\n if (used >= maxChars) break;\n }\n return chunks.join(\"\\n\\n\");\n}\n\nexport function isExcludedFromContext(message: unknown): boolean {\n return !!message && typeof message === \"object\" && (message as PiMessage).excludeFromContext === true;\n}\n\nexport function isRemnicInjected(message: unknown): boolean {\n return !!message && typeof message === \"object\" && (message as PiMessage).remnicInjected === true;\n}\n\nfunction textFromContent(content: unknown): string {\n if (typeof content === \"string\") return content;\n if (!Array.isArray(content)) return \"\";\n const chunks: string[] = [];\n for (const block of content) {\n if (!block || typeof block !== \"object\") continue;\n const obj = block as PiMessage;\n if (obj.type === \"text\" && typeof obj.text === \"string\") chunks.push(obj.text);\n if (obj.type === \"toolCall\" && typeof obj.name === \"string\") {\n chunks.push(`Tool ${obj.name} called with ${JSON.stringify(obj.arguments ?? {})}`);\n }\n }\n return chunks.join(\"\\n\");\n}\n\nfunction partsFromMessage(message: PiMessage, renderedContent: string): ObserveMessagePart[] {\n return parsePiMessageParts(message, {\n renderedContent,\n allowRenderedFallback: true,\n }).map(toObserveMessagePart);\n}\n\nfunction toObserveMessagePart(part: LcmMessagePartInput): ObserveMessagePart {\n return {\n ordinal: part.ordinal ?? undefined,\n kind: part.kind,\n payload: part.payload,\n toolName: part.toolName ?? part.tool_name ?? undefined,\n filePath: part.filePath ?? part.file_path ?? undefined,\n createdAt: part.createdAt ?? part.created_at ?? undefined,\n };\n}\n\nfunction stableObservedMessageIdentity(rawContent: unknown): string | null {\n if (rawContent && typeof rawContent === \"object\") {\n const obj = rawContent as PiMessage;\n const fields = [\n \"id\",\n \"entryId\",\n \"entry_id\",\n \"messageId\",\n \"message_id\",\n \"turnId\",\n \"turn_id\",\n \"timestamp\",\n \"createdAt\",\n \"created_at\",\n ];\n for (const field of fields) {\n const value = obj[field];\n if (typeof value === \"string\" && value.length > 0) return `${field}:${value}`;\n if (typeof value === \"number\" && Number.isFinite(value)) return `${field}:${value}`;\n }\n }\n return null;\n}\n"],"mappings":"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","names":["remnicPiExtension"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@remnic/plugin-pi",
|
|
3
|
-
"version": "9.3.
|
|
3
|
+
"version": "9.3.640",
|
|
4
4
|
"description": "Remnic memory extension for Pi Coding Agent",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -42,7 +42,7 @@
|
|
|
42
42
|
},
|
|
43
43
|
"dependencies": {
|
|
44
44
|
"@sinclair/typebox": "^0.34.0",
|
|
45
|
-
"@remnic/core": "^9.3.
|
|
45
|
+
"@remnic/core": "^9.3.640"
|
|
46
46
|
},
|
|
47
47
|
"peerDependencies": {
|
|
48
48
|
"@earendil-works/pi-coding-agent": "*"
|