@cortexkit/pi-magic-context 0.30.2 → 0.30.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/index.js +242 -42
- package/dist/subagent-entry.js +183 -2
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -147,7 +147,7 @@ This package is part of the [magic-context monorepo](https://github.com/cortexki
|
|
|
147
147
|
| Pi-specific module | Responsibility |
|
|
148
148
|
|---|---|
|
|
149
149
|
| `context-handler.ts` | Pi `pi.on("context", ...)` adapter — tags, drops, runs nudges and auto-search |
|
|
150
|
-
| `subagent-runner.ts` | Spawns `pi --print --mode json --no-
|
|
150
|
+
| `subagent-runner.ts` | Spawns `pi --print --mode json --no-session ...` for historian/sidekick/dreamer subagents, keeps extension discovery on for provider/AFT extensions, sets `MAGIC_CONTEXT_PI_SUBAGENT=1` so the full Magic Context entry no-ops, and applies a per-agent `--tools`/`--no-tools` allow-list plus a 2-second terminal drain |
|
|
151
151
|
| `tools/` | Pi `pi.registerTool` wrappers around the shared tool implementations |
|
|
152
152
|
| `commands/` | Pi `pi.registerCommand` wrappers for the five `/ctx-*` slash commands |
|
|
153
153
|
| `dreamer/` | Pi-side adapter for the shared dreamer scheduler |
|
package/dist/index.js
CHANGED
|
@@ -70,6 +70,9 @@ function getMagicContextTempDir(harness = getHarness()) {
|
|
|
70
70
|
return path2.join(os.tmpdir(), harness, "magic-context");
|
|
71
71
|
}
|
|
72
72
|
function getMagicContextLogPath(harness = getHarness()) {
|
|
73
|
+
const envPath = process.env.MAGIC_CONTEXT_LOG_PATH?.trim();
|
|
74
|
+
if (envPath)
|
|
75
|
+
return envPath;
|
|
73
76
|
return path2.join(getMagicContextTempDir(harness), "magic-context.log");
|
|
74
77
|
}
|
|
75
78
|
function getProjectMagicContextDir(directory) {
|
|
@@ -156484,9 +156487,11 @@ function compareSemverCore(a, b) {
|
|
|
156484
156487
|
|
|
156485
156488
|
// ../plugin/src/shared/announcement.ts
|
|
156486
156489
|
init_data_path();
|
|
156487
|
-
var ANNOUNCEMENT_VERSION = "0.30.
|
|
156490
|
+
var ANNOUNCEMENT_VERSION = "0.30.4";
|
|
156488
156491
|
var ANNOUNCEMENT_FEATURES = [
|
|
156489
|
-
"
|
|
156492
|
+
"Pi: fixed historian and dreamer failing when your model comes from a provider extension (Antigravity, Anthropic OAuth, etc.). Subagents now load your extensions.",
|
|
156493
|
+
"Pi: fixed the retrospective and refresh-primers dreamer tasks reading sessions through the wrong API.",
|
|
156494
|
+
"OpenCode: the plugin no longer re-adds its TUI sidebar entry on startup, so removing it from tui.jsonc now sticks."
|
|
156490
156495
|
];
|
|
156491
156496
|
var ANNOUNCEMENT_FOOTER = "Join us on Discord: https://discord.gg/F2uWxjGnU";
|
|
156492
156497
|
var STATE_FILENAME = "last_announced_version";
|
|
@@ -156830,6 +156835,10 @@ function resolveSubagentEntryPath() {
|
|
|
156830
156835
|
}
|
|
156831
156836
|
var SUBAGENT_ENTRY_PATH = resolveSubagentEntryPath();
|
|
156832
156837
|
var TERMINAL_DRAIN_GRACE_MS = 2000;
|
|
156838
|
+
var MAGIC_CONTEXT_PI_SUBAGENT_ENV = "MAGIC_CONTEXT_PI_SUBAGENT";
|
|
156839
|
+
var PI_READ_ONLY_BUILTINS = ["read", "grep", "find", "ls"];
|
|
156840
|
+
var PI_AFT_READ_TOOLS = ["aft_outline", "aft_zoom", "aft_search"];
|
|
156841
|
+
var PI_HISTORIAN_TOOLS = [...PI_READ_ONLY_BUILTINS, "aft_search"];
|
|
156833
156842
|
var DREAMER_ACTION_AGENTS = new Set([
|
|
156834
156843
|
"dreamer",
|
|
156835
156844
|
"magic-context-dreamer"
|
|
@@ -156839,17 +156848,29 @@ var SEARCH_ONLY_SUBAGENT_TOOL_AGENTS = new Set([
|
|
|
156839
156848
|
"dreamer-retrospective",
|
|
156840
156849
|
"dreamer-primer-investigator"
|
|
156841
156850
|
]);
|
|
156842
|
-
var
|
|
156851
|
+
var STRICT_TOOL_ALLOWLIST_ENTRIES = [
|
|
156843
156852
|
["dreamer-retrospective", ["ctx_search"]],
|
|
156844
156853
|
["smart-note-compiler", []],
|
|
156854
|
+
["magic-context-historian", PI_HISTORIAN_TOOLS],
|
|
156855
|
+
["historian", PI_HISTORIAN_TOOLS],
|
|
156856
|
+
["historian-recomp", PI_HISTORIAN_TOOLS],
|
|
156857
|
+
["historian-editor", PI_HISTORIAN_TOOLS],
|
|
156858
|
+
["sidekick", [...PI_READ_ONLY_BUILTINS, "ctx_search"]],
|
|
156845
156859
|
["dreamer-classifier", []],
|
|
156846
156860
|
["dreamer-reviewer", []],
|
|
156847
|
-
[
|
|
156848
|
-
|
|
156849
|
-
|
|
156861
|
+
[
|
|
156862
|
+
"dreamer-primer-investigator",
|
|
156863
|
+
[...PI_READ_ONLY_BUILTINS, ...PI_AFT_READ_TOOLS, "ctx_search"]
|
|
156864
|
+
],
|
|
156865
|
+
["dreamer-memory-mapper", [...PI_READ_ONLY_BUILTINS, ...PI_AFT_READ_TOOLS]],
|
|
156866
|
+
[
|
|
156867
|
+
"dreamer-docs",
|
|
156868
|
+
[...PI_READ_ONLY_BUILTINS, "bash", "write", "edit", ...PI_AFT_READ_TOOLS]
|
|
156869
|
+
],
|
|
156850
156870
|
["dreamer", ["ctx_memory"]],
|
|
156851
156871
|
["magic-context-dreamer", ["ctx_memory"]]
|
|
156852
|
-
]
|
|
156872
|
+
];
|
|
156873
|
+
var STRICT_TOOL_ALLOWLIST = new Map(STRICT_TOOL_ALLOWLIST_ENTRIES);
|
|
156853
156874
|
function inferAccountingSubagent(agent) {
|
|
156854
156875
|
if (agent.includes("sidekick"))
|
|
156855
156876
|
return "sidekick";
|
|
@@ -156959,7 +156980,10 @@ class PiSubagentRunner {
|
|
|
156959
156980
|
try {
|
|
156960
156981
|
child = this.spawnImpl(this.invocation.command, [...this.invocation.prefixArgs, ...args], {
|
|
156961
156982
|
cwd: options.cwd,
|
|
156962
|
-
env:
|
|
156983
|
+
env: {
|
|
156984
|
+
...process.env,
|
|
156985
|
+
[MAGIC_CONTEXT_PI_SUBAGENT_ENV]: "1"
|
|
156986
|
+
},
|
|
156963
156987
|
stdio: [deliverViaStdin ? "pipe" : "ignore", "pipe", "pipe"]
|
|
156964
156988
|
});
|
|
156965
156989
|
} catch (error) {
|
|
@@ -157255,7 +157279,6 @@ function buildArgs(options, opts) {
|
|
|
157255
157279
|
"--mode",
|
|
157256
157280
|
"json",
|
|
157257
157281
|
"--no-session",
|
|
157258
|
-
"--no-extensions",
|
|
157259
157282
|
"--no-skills",
|
|
157260
157283
|
"--no-prompt-templates"
|
|
157261
157284
|
];
|
|
@@ -157267,7 +157290,10 @@ function buildArgs(options, opts) {
|
|
|
157267
157290
|
}
|
|
157268
157291
|
}
|
|
157269
157292
|
const strictTools = STRICT_TOOL_ALLOWLIST.get(options.agent);
|
|
157270
|
-
if (strictTools) {
|
|
157293
|
+
if (strictTools === undefined) {
|
|
157294
|
+
sessionLog(options.accountingSessionId ?? "pi-subagent", `Pi subagent agent "${options.agent}" has no strict tool allow-list; forcing --no-tools`);
|
|
157295
|
+
args.push("--no-tools");
|
|
157296
|
+
} else {
|
|
157271
157297
|
if (strictTools.length > 0) {
|
|
157272
157298
|
args.push("--tools", strictTools.join(","));
|
|
157273
157299
|
} else {
|
|
@@ -172658,6 +172684,94 @@ init_logger();
|
|
|
172658
172684
|
|
|
172659
172685
|
// ../plugin/src/features/magic-context/compartment-chunk-embedding.ts
|
|
172660
172686
|
import { createHash as createHash6 } from "node:crypto";
|
|
172687
|
+
init_logger();
|
|
172688
|
+
|
|
172689
|
+
// ../plugin/src/features/magic-context/recursive-text-splitter.ts
|
|
172690
|
+
var DEFAULT_SEPARATORS = [`
|
|
172691
|
+
|
|
172692
|
+
`, `
|
|
172693
|
+
`, " ", ""];
|
|
172694
|
+
function splitOnSeparator(text, separator) {
|
|
172695
|
+
const splits = separator ? text.split(separator) : text.split("");
|
|
172696
|
+
return splits.filter((s) => s !== "");
|
|
172697
|
+
}
|
|
172698
|
+
function mergeSplits(splits, separator, chunkSize, lengthFunction) {
|
|
172699
|
+
const docs = [];
|
|
172700
|
+
const currentDoc = [];
|
|
172701
|
+
let total = 0;
|
|
172702
|
+
const joinDocs = (docsToJoin) => {
|
|
172703
|
+
const joined = docsToJoin.join(separator).trim();
|
|
172704
|
+
return joined === "" ? null : joined;
|
|
172705
|
+
};
|
|
172706
|
+
for (const d of splits) {
|
|
172707
|
+
const len = lengthFunction(d);
|
|
172708
|
+
if (total + len + currentDoc.length * separator.length > chunkSize) {
|
|
172709
|
+
if (currentDoc.length > 0) {
|
|
172710
|
+
const doc3 = joinDocs(currentDoc);
|
|
172711
|
+
if (doc3 !== null)
|
|
172712
|
+
docs.push(doc3);
|
|
172713
|
+
while (total > 0 && currentDoc.length > 0) {
|
|
172714
|
+
total -= lengthFunction(currentDoc[0]);
|
|
172715
|
+
currentDoc.shift();
|
|
172716
|
+
}
|
|
172717
|
+
}
|
|
172718
|
+
}
|
|
172719
|
+
currentDoc.push(d);
|
|
172720
|
+
total += len;
|
|
172721
|
+
}
|
|
172722
|
+
const doc2 = joinDocs(currentDoc);
|
|
172723
|
+
if (doc2 !== null)
|
|
172724
|
+
docs.push(doc2);
|
|
172725
|
+
return docs;
|
|
172726
|
+
}
|
|
172727
|
+
function splitTextRecursive(text, separators, chunkSize, lengthFunction) {
|
|
172728
|
+
const finalChunks = [];
|
|
172729
|
+
let separator = separators[separators.length - 1];
|
|
172730
|
+
let newSeparators;
|
|
172731
|
+
for (let i = 0;i < separators.length; i += 1) {
|
|
172732
|
+
const s = separators[i];
|
|
172733
|
+
if (s === "") {
|
|
172734
|
+
separator = s;
|
|
172735
|
+
break;
|
|
172736
|
+
}
|
|
172737
|
+
if (text.includes(s)) {
|
|
172738
|
+
separator = s;
|
|
172739
|
+
newSeparators = separators.slice(i + 1);
|
|
172740
|
+
break;
|
|
172741
|
+
}
|
|
172742
|
+
}
|
|
172743
|
+
const splits = splitOnSeparator(text, separator);
|
|
172744
|
+
let goodSplits = [];
|
|
172745
|
+
for (const s of splits) {
|
|
172746
|
+
if (lengthFunction(s) < chunkSize) {
|
|
172747
|
+
goodSplits.push(s);
|
|
172748
|
+
} else {
|
|
172749
|
+
if (goodSplits.length) {
|
|
172750
|
+
finalChunks.push(...mergeSplits(goodSplits, separator, chunkSize, lengthFunction));
|
|
172751
|
+
goodSplits = [];
|
|
172752
|
+
}
|
|
172753
|
+
if (!newSeparators) {
|
|
172754
|
+
finalChunks.push(s);
|
|
172755
|
+
} else {
|
|
172756
|
+
finalChunks.push(...splitTextRecursive(s, newSeparators, chunkSize, lengthFunction));
|
|
172757
|
+
}
|
|
172758
|
+
}
|
|
172759
|
+
}
|
|
172760
|
+
if (goodSplits.length) {
|
|
172761
|
+
finalChunks.push(...mergeSplits(goodSplits, separator, chunkSize, lengthFunction));
|
|
172762
|
+
}
|
|
172763
|
+
return finalChunks;
|
|
172764
|
+
}
|
|
172765
|
+
function recursiveCharacterSplit(text, options) {
|
|
172766
|
+
const chunkSize = options.chunkSize;
|
|
172767
|
+
const lengthFunction = options.lengthFunction ?? ((t) => t.length);
|
|
172768
|
+
const separators = options.separators ?? DEFAULT_SEPARATORS;
|
|
172769
|
+
if (text.length === 0)
|
|
172770
|
+
return [];
|
|
172771
|
+
return splitTextRecursive(text, separators, chunkSize, lengthFunction);
|
|
172772
|
+
}
|
|
172773
|
+
|
|
172774
|
+
// ../plugin/src/features/magic-context/compartment-chunk-embedding.ts
|
|
172661
172775
|
var DEFAULT_COMPARTMENT_CHUNK_MAX_INPUT_TOKENS = 512;
|
|
172662
172776
|
var CHUNK_WINDOW_SAFETY_RATIO = 0.9;
|
|
172663
172777
|
var loadFtsRowsStatements = new WeakMap;
|
|
@@ -172936,6 +173050,19 @@ function chunkCanonicalText(canonicalText, startOrdinal, endOrdinal, maxInputTok
|
|
|
172936
173050
|
const lineStart = range?.start ?? startOrdinal;
|
|
172937
173051
|
const lineEnd = range?.end ?? lineStart;
|
|
172938
173052
|
const lineTokens = estimateTokens(line);
|
|
173053
|
+
if (lineTokens > effectiveMax) {
|
|
173054
|
+
flush2();
|
|
173055
|
+
for (const slice of splitOversizedLine(line, effectiveMax)) {
|
|
173056
|
+
windows.push({
|
|
173057
|
+
windowIndex: windows.length + 1,
|
|
173058
|
+
startOrdinal: lineStart,
|
|
173059
|
+
endOrdinal: lineEnd,
|
|
173060
|
+
text: slice,
|
|
173061
|
+
chunkHash: hashChunkText(slice)
|
|
173062
|
+
});
|
|
173063
|
+
}
|
|
173064
|
+
continue;
|
|
173065
|
+
}
|
|
172939
173066
|
if (currentLines.length > 0 && currentTokens + lineTokens > effectiveMax) {
|
|
172940
173067
|
flush2();
|
|
172941
173068
|
}
|
|
@@ -172949,6 +173076,56 @@ function chunkCanonicalText(canonicalText, startOrdinal, endOrdinal, maxInputTok
|
|
|
172949
173076
|
flush2();
|
|
172950
173077
|
return windows;
|
|
172951
173078
|
}
|
|
173079
|
+
function splitOversizedLine(line, effectiveMax) {
|
|
173080
|
+
let slices = [];
|
|
173081
|
+
try {
|
|
173082
|
+
slices = recursiveCharacterSplit(line, {
|
|
173083
|
+
chunkSize: effectiveMax,
|
|
173084
|
+
lengthFunction: estimateTokens
|
|
173085
|
+
});
|
|
173086
|
+
} catch (error51) {
|
|
173087
|
+
log("[magic-context] recursiveCharacterSplit failed; using char-budget fallback:", error51);
|
|
173088
|
+
slices = [];
|
|
173089
|
+
}
|
|
173090
|
+
if (slices.length === 0) {
|
|
173091
|
+
slices = charBudgetSplit(line, effectiveMax);
|
|
173092
|
+
}
|
|
173093
|
+
const safe = [];
|
|
173094
|
+
const pushChecked = (slice) => {
|
|
173095
|
+
if (estimateTokens(slice) > effectiveMax && slice.length > 1) {
|
|
173096
|
+
safe.push(...charBudgetSplit(slice, effectiveMax));
|
|
173097
|
+
return;
|
|
173098
|
+
}
|
|
173099
|
+
safe.push(slice);
|
|
173100
|
+
};
|
|
173101
|
+
for (const slice of slices) {
|
|
173102
|
+
if (estimateTokens(slice) <= effectiveMax) {
|
|
173103
|
+
safe.push(slice);
|
|
173104
|
+
} else {
|
|
173105
|
+
for (const sub of charBudgetSplit(slice, effectiveMax))
|
|
173106
|
+
pushChecked(sub);
|
|
173107
|
+
}
|
|
173108
|
+
}
|
|
173109
|
+
return safe.filter((s) => s.length > 0);
|
|
173110
|
+
}
|
|
173111
|
+
function charBudgetSplit(text, effectiveMax) {
|
|
173112
|
+
const totalTokens = Math.max(1, estimateTokens(text));
|
|
173113
|
+
const charsPerToken = Math.max(1, Math.floor(text.length / totalTokens));
|
|
173114
|
+
const sliceChars = Math.max(1, effectiveMax * charsPerToken);
|
|
173115
|
+
const out = [];
|
|
173116
|
+
let pos = 0;
|
|
173117
|
+
while (pos < text.length) {
|
|
173118
|
+
let end = Math.min(text.length, pos + sliceChars);
|
|
173119
|
+
let slice = text.slice(pos, end);
|
|
173120
|
+
while (slice.length > 1 && estimateTokens(slice) > effectiveMax) {
|
|
173121
|
+
end = pos + Math.max(1, Math.floor((end - pos) / 2));
|
|
173122
|
+
slice = text.slice(pos, end);
|
|
173123
|
+
}
|
|
173124
|
+
out.push(slice);
|
|
173125
|
+
pos = end;
|
|
173126
|
+
}
|
|
173127
|
+
return out;
|
|
173128
|
+
}
|
|
172952
173129
|
function getExistingChunkHashes(db, compartmentId, modelId, projectPath) {
|
|
172953
173130
|
const scoped = typeof projectPath === "string" && projectPath.length > 0;
|
|
172954
173131
|
const rows = scoped ? getExistingHashStatement(db, true).all(compartmentId, modelId, projectPath) : getExistingHashStatement(db, false).all(compartmentId, modelId);
|
|
@@ -173681,6 +173858,7 @@ class OpenAICompatibleEmbeddingProvider {
|
|
|
173681
173858
|
if (texts.length === 0) {
|
|
173682
173859
|
return [];
|
|
173683
173860
|
}
|
|
173861
|
+
const requestTexts = texts.map((t) => t.trim().length === 0 ? " " : t);
|
|
173684
173862
|
if (!await this.initialize()) {
|
|
173685
173863
|
return Array.from({ length: texts.length }, () => null);
|
|
173686
173864
|
}
|
|
@@ -173712,7 +173890,7 @@ class OpenAICompatibleEmbeddingProvider {
|
|
|
173712
173890
|
},
|
|
173713
173891
|
body: JSON.stringify({
|
|
173714
173892
|
model: this.model,
|
|
173715
|
-
input:
|
|
173893
|
+
input: requestTexts,
|
|
173716
173894
|
...inputTypeForRequest ? { input_type: inputTypeForRequest } : {},
|
|
173717
173895
|
...this.truncate ? { truncate: this.truncate } : {}
|
|
173718
173896
|
}),
|
|
@@ -174799,6 +174977,32 @@ async function embedBatchForProject(projectIdentity, texts, signal, purpose = "p
|
|
|
174799
174977
|
}
|
|
174800
174978
|
return { vectors, modelId, generation };
|
|
174801
174979
|
}
|
|
174980
|
+
async function embedTextsWindowBounded(projectIdentity, texts, signal) {
|
|
174981
|
+
if (texts.length <= MAX_WINDOWS_PER_EMBED_CALL) {
|
|
174982
|
+
return embedBatchForProject(projectIdentity, texts, signal);
|
|
174983
|
+
}
|
|
174984
|
+
const vectors = [];
|
|
174985
|
+
let modelId = null;
|
|
174986
|
+
let generation = null;
|
|
174987
|
+
for (let start = 0;start < texts.length; start += MAX_WINDOWS_PER_EMBED_CALL) {
|
|
174988
|
+
if (signal?.aborted)
|
|
174989
|
+
return null;
|
|
174990
|
+
const sub = texts.slice(start, start + MAX_WINDOWS_PER_EMBED_CALL);
|
|
174991
|
+
const result = await embedBatchForProject(projectIdentity, sub, signal);
|
|
174992
|
+
if (!result)
|
|
174993
|
+
return null;
|
|
174994
|
+
if (modelId === null) {
|
|
174995
|
+
modelId = result.modelId;
|
|
174996
|
+
generation = result.generation;
|
|
174997
|
+
} else if (result.modelId !== modelId || result.generation !== generation) {
|
|
174998
|
+
return null;
|
|
174999
|
+
}
|
|
175000
|
+
vectors.push(...result.vectors);
|
|
175001
|
+
}
|
|
175002
|
+
if (modelId === null || generation === null)
|
|
175003
|
+
return null;
|
|
175004
|
+
return { vectors, modelId, generation };
|
|
175005
|
+
}
|
|
174802
175006
|
function isUnembeddedMemoryRow(row) {
|
|
174803
175007
|
if (row === null || typeof row !== "object")
|
|
174804
175008
|
return false;
|
|
@@ -174932,7 +175136,7 @@ async function embedCandidateChunkBatch(db, projectIdentity, modelId, candidates
|
|
|
174932
175136
|
let result = null;
|
|
174933
175137
|
const attemptStart = Date.now();
|
|
174934
175138
|
try {
|
|
174935
|
-
result = await
|
|
175139
|
+
result = await embedTextsWindowBounded(projectIdentity, texts, signal);
|
|
174936
175140
|
} catch (error51) {
|
|
174937
175141
|
log("[magic-context] failed to proactively embed compartment chunks:", error51);
|
|
174938
175142
|
}
|
|
@@ -183501,8 +183705,26 @@ function synthesizeToolResultParts(msg) {
|
|
|
183501
183705
|
];
|
|
183502
183706
|
}
|
|
183503
183707
|
|
|
183504
|
-
// src/dreamer/
|
|
183708
|
+
// src/dreamer/pi-session-api.ts
|
|
183709
|
+
import { readFileSync as readFileSync9 } from "node:fs";
|
|
183505
183710
|
var PI_CODING_AGENT_MODULE = "@earendil-works/pi-coding-agent";
|
|
183711
|
+
async function loadDefaultPiSessionApi() {
|
|
183712
|
+
const mod = await import(PI_CODING_AGENT_MODULE);
|
|
183713
|
+
const listSessions = mod.SessionManager?.listAll;
|
|
183714
|
+
if (typeof listSessions !== "function") {
|
|
183715
|
+
throw new Error("Pi session APIs unavailable: expected SessionManager.listAll on pi-coding-agent");
|
|
183716
|
+
}
|
|
183717
|
+
const loadEntriesFromFile = mod.loadEntriesFromFile ?? ((filePath) => {
|
|
183718
|
+
const content = readFileSync9(filePath, "utf8");
|
|
183719
|
+
return mod.parseSessionEntries?.(content) ?? [];
|
|
183720
|
+
});
|
|
183721
|
+
return {
|
|
183722
|
+
listSessions: listSessions.bind(mod.SessionManager),
|
|
183723
|
+
loadEntriesFromFile
|
|
183724
|
+
};
|
|
183725
|
+
}
|
|
183726
|
+
|
|
183727
|
+
// src/dreamer/primer-raw-provider-pi.ts
|
|
183506
183728
|
function createPiPrimerRawProviderFactory(deps = {}) {
|
|
183507
183729
|
let resolved = null;
|
|
183508
183730
|
const resolveDeps = async () => {
|
|
@@ -183512,7 +183734,7 @@ function createPiPrimerRawProviderFactory(deps = {}) {
|
|
|
183512
183734
|
loadEntriesFromFile: deps.loadEntriesFromFile
|
|
183513
183735
|
};
|
|
183514
183736
|
}
|
|
183515
|
-
resolved ??=
|
|
183737
|
+
resolved ??= loadDefaultPiSessionApi();
|
|
183516
183738
|
return resolved;
|
|
183517
183739
|
};
|
|
183518
183740
|
return async (sessionId) => {
|
|
@@ -183539,23 +183761,9 @@ function createPiPrimerRawProviderFactory(deps = {}) {
|
|
|
183539
183761
|
}
|
|
183540
183762
|
};
|
|
183541
183763
|
}
|
|
183542
|
-
async function loadDefaultPiSessionDeps() {
|
|
183543
|
-
const mod = await import(PI_CODING_AGENT_MODULE);
|
|
183544
|
-
const listSessions = mod.SessionManager?.listSessions;
|
|
183545
|
-
const loadEntriesFromFile = mod.loadEntriesFromFile;
|
|
183546
|
-
if (typeof listSessions !== "function" || typeof loadEntriesFromFile !== "function") {
|
|
183547
|
-
throw new Error("Pi session APIs unavailable: expected SessionManager.listSessions and loadEntriesFromFile");
|
|
183548
|
-
}
|
|
183549
|
-
return {
|
|
183550
|
-
listSessions: listSessions.bind(mod.SessionManager),
|
|
183551
|
-
loadEntriesFromFile
|
|
183552
|
-
};
|
|
183553
|
-
}
|
|
183554
183764
|
|
|
183555
183765
|
// src/dreamer/retrospective-raw-provider-pi.ts
|
|
183556
183766
|
import { resolve as resolve2 } from "node:path";
|
|
183557
|
-
var PI_CODING_AGENT_MODULE2 = "@earendil-works/pi-coding-agent";
|
|
183558
|
-
|
|
183559
183767
|
class PiRetrospectiveRawProvider {
|
|
183560
183768
|
deps;
|
|
183561
183769
|
sessionPathById = new Map;
|
|
@@ -183621,7 +183829,7 @@ class PiRetrospectiveRawProvider {
|
|
|
183621
183829
|
loadEntriesFromFile: this.deps.loadEntriesFromFile
|
|
183622
183830
|
};
|
|
183623
183831
|
}
|
|
183624
|
-
this.resolvedDefaultDeps ??=
|
|
183832
|
+
this.resolvedDefaultDeps ??= loadDefaultPiSessionApi();
|
|
183625
183833
|
return this.resolvedDefaultDeps;
|
|
183626
183834
|
}
|
|
183627
183835
|
}
|
|
@@ -183658,18 +183866,6 @@ function extractPiTextContent(content) {
|
|
|
183658
183866
|
}).join(`
|
|
183659
183867
|
`);
|
|
183660
183868
|
}
|
|
183661
|
-
async function loadDefaultPiSessionDeps2() {
|
|
183662
|
-
const mod = await import(PI_CODING_AGENT_MODULE2);
|
|
183663
|
-
const listSessions = mod.SessionManager?.listSessions;
|
|
183664
|
-
const loadEntriesFromFile = mod.loadEntriesFromFile;
|
|
183665
|
-
if (typeof listSessions !== "function" || typeof loadEntriesFromFile !== "function") {
|
|
183666
|
-
throw new Error("Pi session APIs unavailable: expected SessionManager.listSessions and loadEntriesFromFile");
|
|
183667
|
-
}
|
|
183668
|
-
return {
|
|
183669
|
-
listSessions: listSessions.bind(mod.SessionManager),
|
|
183670
|
-
loadEntriesFromFile
|
|
183671
|
-
};
|
|
183672
|
-
}
|
|
183673
183869
|
|
|
183674
183870
|
// src/dreamer/index.ts
|
|
183675
183871
|
var registeredProjects2 = new Map;
|
|
@@ -199816,7 +200012,7 @@ function formatThresholdPercent(value) {
|
|
|
199816
200012
|
// package.json
|
|
199817
200013
|
var package_default = {
|
|
199818
200014
|
name: "@cortexkit/pi-magic-context",
|
|
199819
|
-
version: "0.30.
|
|
200015
|
+
version: "0.30.4",
|
|
199820
200016
|
type: "module",
|
|
199821
200017
|
description: "Pi coding agent extension for Magic Context — cross-session memory and context management",
|
|
199822
200018
|
main: "dist/index.js",
|
|
@@ -206165,6 +206361,10 @@ function resolveDreamerFromConfig(config2) {
|
|
|
206165
206361
|
return config2.dreamer?.disable === true ? undefined : config2.dreamer;
|
|
206166
206362
|
}
|
|
206167
206363
|
async function src_default2(pi) {
|
|
206364
|
+
if (process.env[MAGIC_CONTEXT_PI_SUBAGENT_ENV] === "1") {
|
|
206365
|
+
log(`${PREFIX} subagent child detected (${MAGIC_CONTEXT_PI_SUBAGENT_ENV}=1); skipping full extension registration`);
|
|
206366
|
+
return;
|
|
206367
|
+
}
|
|
206168
206368
|
const storageDir = getMagicContextStorageDir();
|
|
206169
206369
|
const dbPath = join13(storageDir, "context.db");
|
|
206170
206370
|
let db;
|
package/dist/subagent-entry.js
CHANGED
|
@@ -70,6 +70,9 @@ function getMagicContextTempDir(harness = getHarness()) {
|
|
|
70
70
|
return path.join(os.tmpdir(), harness, "magic-context");
|
|
71
71
|
}
|
|
72
72
|
function getMagicContextLogPath(harness = getHarness()) {
|
|
73
|
+
const envPath = process.env.MAGIC_CONTEXT_LOG_PATH?.trim();
|
|
74
|
+
if (envPath)
|
|
75
|
+
return envPath;
|
|
73
76
|
return path.join(getMagicContextTempDir(harness), "magic-context.log");
|
|
74
77
|
}
|
|
75
78
|
function getProjectMagicContextDir(directory) {
|
|
@@ -160282,6 +160285,94 @@ init_logger();
|
|
|
160282
160285
|
|
|
160283
160286
|
// ../plugin/src/features/magic-context/compartment-chunk-embedding.ts
|
|
160284
160287
|
import { createHash as createHash3 } from "node:crypto";
|
|
160288
|
+
init_logger();
|
|
160289
|
+
|
|
160290
|
+
// ../plugin/src/features/magic-context/recursive-text-splitter.ts
|
|
160291
|
+
var DEFAULT_SEPARATORS = [`
|
|
160292
|
+
|
|
160293
|
+
`, `
|
|
160294
|
+
`, " ", ""];
|
|
160295
|
+
function splitOnSeparator(text, separator) {
|
|
160296
|
+
const splits = separator ? text.split(separator) : text.split("");
|
|
160297
|
+
return splits.filter((s) => s !== "");
|
|
160298
|
+
}
|
|
160299
|
+
function mergeSplits(splits, separator, chunkSize, lengthFunction) {
|
|
160300
|
+
const docs = [];
|
|
160301
|
+
const currentDoc = [];
|
|
160302
|
+
let total = 0;
|
|
160303
|
+
const joinDocs = (docsToJoin) => {
|
|
160304
|
+
const joined = docsToJoin.join(separator).trim();
|
|
160305
|
+
return joined === "" ? null : joined;
|
|
160306
|
+
};
|
|
160307
|
+
for (const d of splits) {
|
|
160308
|
+
const len = lengthFunction(d);
|
|
160309
|
+
if (total + len + currentDoc.length * separator.length > chunkSize) {
|
|
160310
|
+
if (currentDoc.length > 0) {
|
|
160311
|
+
const doc3 = joinDocs(currentDoc);
|
|
160312
|
+
if (doc3 !== null)
|
|
160313
|
+
docs.push(doc3);
|
|
160314
|
+
while (total > 0 && currentDoc.length > 0) {
|
|
160315
|
+
total -= lengthFunction(currentDoc[0]);
|
|
160316
|
+
currentDoc.shift();
|
|
160317
|
+
}
|
|
160318
|
+
}
|
|
160319
|
+
}
|
|
160320
|
+
currentDoc.push(d);
|
|
160321
|
+
total += len;
|
|
160322
|
+
}
|
|
160323
|
+
const doc2 = joinDocs(currentDoc);
|
|
160324
|
+
if (doc2 !== null)
|
|
160325
|
+
docs.push(doc2);
|
|
160326
|
+
return docs;
|
|
160327
|
+
}
|
|
160328
|
+
function splitTextRecursive(text, separators, chunkSize, lengthFunction) {
|
|
160329
|
+
const finalChunks = [];
|
|
160330
|
+
let separator = separators[separators.length - 1];
|
|
160331
|
+
let newSeparators;
|
|
160332
|
+
for (let i = 0;i < separators.length; i += 1) {
|
|
160333
|
+
const s = separators[i];
|
|
160334
|
+
if (s === "") {
|
|
160335
|
+
separator = s;
|
|
160336
|
+
break;
|
|
160337
|
+
}
|
|
160338
|
+
if (text.includes(s)) {
|
|
160339
|
+
separator = s;
|
|
160340
|
+
newSeparators = separators.slice(i + 1);
|
|
160341
|
+
break;
|
|
160342
|
+
}
|
|
160343
|
+
}
|
|
160344
|
+
const splits = splitOnSeparator(text, separator);
|
|
160345
|
+
let goodSplits = [];
|
|
160346
|
+
for (const s of splits) {
|
|
160347
|
+
if (lengthFunction(s) < chunkSize) {
|
|
160348
|
+
goodSplits.push(s);
|
|
160349
|
+
} else {
|
|
160350
|
+
if (goodSplits.length) {
|
|
160351
|
+
finalChunks.push(...mergeSplits(goodSplits, separator, chunkSize, lengthFunction));
|
|
160352
|
+
goodSplits = [];
|
|
160353
|
+
}
|
|
160354
|
+
if (!newSeparators) {
|
|
160355
|
+
finalChunks.push(s);
|
|
160356
|
+
} else {
|
|
160357
|
+
finalChunks.push(...splitTextRecursive(s, newSeparators, chunkSize, lengthFunction));
|
|
160358
|
+
}
|
|
160359
|
+
}
|
|
160360
|
+
}
|
|
160361
|
+
if (goodSplits.length) {
|
|
160362
|
+
finalChunks.push(...mergeSplits(goodSplits, separator, chunkSize, lengthFunction));
|
|
160363
|
+
}
|
|
160364
|
+
return finalChunks;
|
|
160365
|
+
}
|
|
160366
|
+
function recursiveCharacterSplit(text, options) {
|
|
160367
|
+
const chunkSize = options.chunkSize;
|
|
160368
|
+
const lengthFunction = options.lengthFunction ?? ((t) => t.length);
|
|
160369
|
+
const separators = options.separators ?? DEFAULT_SEPARATORS;
|
|
160370
|
+
if (text.length === 0)
|
|
160371
|
+
return [];
|
|
160372
|
+
return splitTextRecursive(text, separators, chunkSize, lengthFunction);
|
|
160373
|
+
}
|
|
160374
|
+
|
|
160375
|
+
// ../plugin/src/features/magic-context/compartment-chunk-embedding.ts
|
|
160285
160376
|
var DEFAULT_COMPARTMENT_CHUNK_MAX_INPUT_TOKENS = 512;
|
|
160286
160377
|
var CHUNK_WINDOW_SAFETY_RATIO = 0.9;
|
|
160287
160378
|
var loadFtsRowsStatements = new WeakMap;
|
|
@@ -160560,6 +160651,19 @@ function chunkCanonicalText(canonicalText, startOrdinal, endOrdinal, maxInputTok
|
|
|
160560
160651
|
const lineStart = range?.start ?? startOrdinal;
|
|
160561
160652
|
const lineEnd = range?.end ?? lineStart;
|
|
160562
160653
|
const lineTokens = estimateTokens(line);
|
|
160654
|
+
if (lineTokens > effectiveMax) {
|
|
160655
|
+
flush2();
|
|
160656
|
+
for (const slice of splitOversizedLine(line, effectiveMax)) {
|
|
160657
|
+
windows.push({
|
|
160658
|
+
windowIndex: windows.length + 1,
|
|
160659
|
+
startOrdinal: lineStart,
|
|
160660
|
+
endOrdinal: lineEnd,
|
|
160661
|
+
text: slice,
|
|
160662
|
+
chunkHash: hashChunkText(slice)
|
|
160663
|
+
});
|
|
160664
|
+
}
|
|
160665
|
+
continue;
|
|
160666
|
+
}
|
|
160563
160667
|
if (currentLines.length > 0 && currentTokens + lineTokens > effectiveMax) {
|
|
160564
160668
|
flush2();
|
|
160565
160669
|
}
|
|
@@ -160573,6 +160677,56 @@ function chunkCanonicalText(canonicalText, startOrdinal, endOrdinal, maxInputTok
|
|
|
160573
160677
|
flush2();
|
|
160574
160678
|
return windows;
|
|
160575
160679
|
}
|
|
160680
|
+
function splitOversizedLine(line, effectiveMax) {
|
|
160681
|
+
let slices = [];
|
|
160682
|
+
try {
|
|
160683
|
+
slices = recursiveCharacterSplit(line, {
|
|
160684
|
+
chunkSize: effectiveMax,
|
|
160685
|
+
lengthFunction: estimateTokens
|
|
160686
|
+
});
|
|
160687
|
+
} catch (error51) {
|
|
160688
|
+
log("[magic-context] recursiveCharacterSplit failed; using char-budget fallback:", error51);
|
|
160689
|
+
slices = [];
|
|
160690
|
+
}
|
|
160691
|
+
if (slices.length === 0) {
|
|
160692
|
+
slices = charBudgetSplit(line, effectiveMax);
|
|
160693
|
+
}
|
|
160694
|
+
const safe = [];
|
|
160695
|
+
const pushChecked = (slice) => {
|
|
160696
|
+
if (estimateTokens(slice) > effectiveMax && slice.length > 1) {
|
|
160697
|
+
safe.push(...charBudgetSplit(slice, effectiveMax));
|
|
160698
|
+
return;
|
|
160699
|
+
}
|
|
160700
|
+
safe.push(slice);
|
|
160701
|
+
};
|
|
160702
|
+
for (const slice of slices) {
|
|
160703
|
+
if (estimateTokens(slice) <= effectiveMax) {
|
|
160704
|
+
safe.push(slice);
|
|
160705
|
+
} else {
|
|
160706
|
+
for (const sub of charBudgetSplit(slice, effectiveMax))
|
|
160707
|
+
pushChecked(sub);
|
|
160708
|
+
}
|
|
160709
|
+
}
|
|
160710
|
+
return safe.filter((s) => s.length > 0);
|
|
160711
|
+
}
|
|
160712
|
+
function charBudgetSplit(text, effectiveMax) {
|
|
160713
|
+
const totalTokens = Math.max(1, estimateTokens(text));
|
|
160714
|
+
const charsPerToken = Math.max(1, Math.floor(text.length / totalTokens));
|
|
160715
|
+
const sliceChars = Math.max(1, effectiveMax * charsPerToken);
|
|
160716
|
+
const out = [];
|
|
160717
|
+
let pos = 0;
|
|
160718
|
+
while (pos < text.length) {
|
|
160719
|
+
let end = Math.min(text.length, pos + sliceChars);
|
|
160720
|
+
let slice = text.slice(pos, end);
|
|
160721
|
+
while (slice.length > 1 && estimateTokens(slice) > effectiveMax) {
|
|
160722
|
+
end = pos + Math.max(1, Math.floor((end - pos) / 2));
|
|
160723
|
+
slice = text.slice(pos, end);
|
|
160724
|
+
}
|
|
160725
|
+
out.push(slice);
|
|
160726
|
+
pos = end;
|
|
160727
|
+
}
|
|
160728
|
+
return out;
|
|
160729
|
+
}
|
|
160576
160730
|
function getExistingChunkHashes(db, compartmentId, modelId, projectPath) {
|
|
160577
160731
|
const scoped = typeof projectPath === "string" && projectPath.length > 0;
|
|
160578
160732
|
const rows = scoped ? getExistingHashStatement(db, true).all(compartmentId, modelId, projectPath) : getExistingHashStatement(db, false).all(compartmentId, modelId);
|
|
@@ -161305,6 +161459,7 @@ class OpenAICompatibleEmbeddingProvider {
|
|
|
161305
161459
|
if (texts.length === 0) {
|
|
161306
161460
|
return [];
|
|
161307
161461
|
}
|
|
161462
|
+
const requestTexts = texts.map((t) => t.trim().length === 0 ? " " : t);
|
|
161308
161463
|
if (!await this.initialize()) {
|
|
161309
161464
|
return Array.from({ length: texts.length }, () => null);
|
|
161310
161465
|
}
|
|
@@ -161336,7 +161491,7 @@ class OpenAICompatibleEmbeddingProvider {
|
|
|
161336
161491
|
},
|
|
161337
161492
|
body: JSON.stringify({
|
|
161338
161493
|
model: this.model,
|
|
161339
|
-
input:
|
|
161494
|
+
input: requestTexts,
|
|
161340
161495
|
...inputTypeForRequest ? { input_type: inputTypeForRequest } : {},
|
|
161341
161496
|
...this.truncate ? { truncate: this.truncate } : {}
|
|
161342
161497
|
}),
|
|
@@ -162423,6 +162578,32 @@ async function embedBatchForProject(projectIdentity, texts, signal, purpose = "p
|
|
|
162423
162578
|
}
|
|
162424
162579
|
return { vectors, modelId, generation };
|
|
162425
162580
|
}
|
|
162581
|
+
async function embedTextsWindowBounded(projectIdentity, texts, signal) {
|
|
162582
|
+
if (texts.length <= MAX_WINDOWS_PER_EMBED_CALL) {
|
|
162583
|
+
return embedBatchForProject(projectIdentity, texts, signal);
|
|
162584
|
+
}
|
|
162585
|
+
const vectors = [];
|
|
162586
|
+
let modelId = null;
|
|
162587
|
+
let generation = null;
|
|
162588
|
+
for (let start = 0;start < texts.length; start += MAX_WINDOWS_PER_EMBED_CALL) {
|
|
162589
|
+
if (signal?.aborted)
|
|
162590
|
+
return null;
|
|
162591
|
+
const sub = texts.slice(start, start + MAX_WINDOWS_PER_EMBED_CALL);
|
|
162592
|
+
const result = await embedBatchForProject(projectIdentity, sub, signal);
|
|
162593
|
+
if (!result)
|
|
162594
|
+
return null;
|
|
162595
|
+
if (modelId === null) {
|
|
162596
|
+
modelId = result.modelId;
|
|
162597
|
+
generation = result.generation;
|
|
162598
|
+
} else if (result.modelId !== modelId || result.generation !== generation) {
|
|
162599
|
+
return null;
|
|
162600
|
+
}
|
|
162601
|
+
vectors.push(...result.vectors);
|
|
162602
|
+
}
|
|
162603
|
+
if (modelId === null || generation === null)
|
|
162604
|
+
return null;
|
|
162605
|
+
return { vectors, modelId, generation };
|
|
162606
|
+
}
|
|
162426
162607
|
function isUnembeddedMemoryRow(row) {
|
|
162427
162608
|
if (row === null || typeof row !== "object")
|
|
162428
162609
|
return false;
|
|
@@ -162556,7 +162737,7 @@ async function embedCandidateChunkBatch(db, projectIdentity, modelId, candidates
|
|
|
162556
162737
|
let result = null;
|
|
162557
162738
|
const attemptStart = Date.now();
|
|
162558
162739
|
try {
|
|
162559
|
-
result = await
|
|
162740
|
+
result = await embedTextsWindowBounded(projectIdentity, texts, signal);
|
|
162560
162741
|
} catch (error51) {
|
|
162561
162742
|
log("[magic-context] failed to proactively embed compartment chunks:", error51);
|
|
162562
162743
|
}
|
package/package.json
CHANGED