@cortexkit/pi-magic-context 0.30.1 → 0.30.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +223 -21
- package/dist/subagent-entry.js +183 -2
- package/package.json +1 -1
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) {
|
|
@@ -14945,12 +14948,30 @@ var require_src2 = __commonJS((exports, module) => {
|
|
|
14945
14948
|
// ../plugin/src/shared/rpc-notifications.ts
|
|
14946
14949
|
var exports_rpc_notifications = {};
|
|
14947
14950
|
__export(exports_rpc_notifications, {
|
|
14951
|
+
registerNotificationSink: () => registerNotificationSink,
|
|
14948
14952
|
pushNotification: () => pushNotification,
|
|
14949
14953
|
isTuiConnected: () => isTuiConnected,
|
|
14950
14954
|
drainNotifications: () => drainNotifications
|
|
14951
14955
|
});
|
|
14956
|
+
function registerNotificationSink(sink) {
|
|
14957
|
+
sinks.add(sink);
|
|
14958
|
+
return () => {
|
|
14959
|
+
sinks.delete(sink);
|
|
14960
|
+
};
|
|
14961
|
+
}
|
|
14962
|
+
function notificationMatchesSink(notification, sink) {
|
|
14963
|
+
return notification.sessionId === undefined || sink.sessionId === undefined || notification.sessionId === sink.sessionId;
|
|
14964
|
+
}
|
|
14952
14965
|
function pushNotification(type, payload, sessionId) {
|
|
14953
|
-
|
|
14966
|
+
const notification = { id: nextNotificationId++, type, payload, sessionId };
|
|
14967
|
+
queue.push(notification);
|
|
14968
|
+
for (const sink of sinks) {
|
|
14969
|
+
if (!notificationMatchesSink(notification, sink))
|
|
14970
|
+
continue;
|
|
14971
|
+
try {
|
|
14972
|
+
sink.send(notification);
|
|
14973
|
+
} catch {}
|
|
14974
|
+
}
|
|
14954
14975
|
if (queue.length > 100) {
|
|
14955
14976
|
const newestPerSession = new Map;
|
|
14956
14977
|
for (const n of queue) {
|
|
@@ -14970,10 +14991,6 @@ function pushNotification(type, payload, sessionId) {
|
|
|
14970
14991
|
}
|
|
14971
14992
|
}
|
|
14972
14993
|
function drainNotifications(lastReceivedId = 0, sessionId) {
|
|
14973
|
-
const now = Date.now();
|
|
14974
|
-
lastDrainAtAny = now;
|
|
14975
|
-
if (sessionId !== undefined)
|
|
14976
|
-
lastDrainAtBySession.set(sessionId, now);
|
|
14977
14994
|
const matchesClient = (notification) => sessionId === undefined || notification.sessionId === undefined || notification.sessionId === sessionId;
|
|
14978
14995
|
if (lastReceivedId > 0) {
|
|
14979
14996
|
queue = queue.filter((notification) => !(notification.id <= lastReceivedId && matchesClient(notification)));
|
|
@@ -14981,17 +14998,20 @@ function drainNotifications(lastReceivedId = 0, sessionId) {
|
|
|
14981
14998
|
return queue.filter((notification) => notification.id > lastReceivedId && matchesClient(notification));
|
|
14982
14999
|
}
|
|
14983
15000
|
function isTuiConnected(sessionId) {
|
|
14984
|
-
|
|
14985
|
-
|
|
14986
|
-
|
|
14987
|
-
return
|
|
15001
|
+
if (sinks.size === 0)
|
|
15002
|
+
return false;
|
|
15003
|
+
if (sessionId === undefined)
|
|
15004
|
+
return true;
|
|
15005
|
+
for (const sink of sinks) {
|
|
15006
|
+
if (sink.sessionId === undefined || sink.sessionId === sessionId)
|
|
15007
|
+
return true;
|
|
14988
15008
|
}
|
|
14989
|
-
return
|
|
15009
|
+
return false;
|
|
14990
15010
|
}
|
|
14991
|
-
var queue, nextNotificationId = 1,
|
|
15011
|
+
var queue, nextNotificationId = 1, sinks;
|
|
14992
15012
|
var init_rpc_notifications = __esm(() => {
|
|
14993
15013
|
queue = [];
|
|
14994
|
-
|
|
15014
|
+
sinks = new Set;
|
|
14995
15015
|
});
|
|
14996
15016
|
|
|
14997
15017
|
// ../plugin/src/shared/safe-notification-target.ts
|
|
@@ -156467,9 +156487,9 @@ function compareSemverCore(a, b) {
|
|
|
156467
156487
|
|
|
156468
156488
|
// ../plugin/src/shared/announcement.ts
|
|
156469
156489
|
init_data_path();
|
|
156470
|
-
var ANNOUNCEMENT_VERSION = "0.30.
|
|
156490
|
+
var ANNOUNCEMENT_VERSION = "0.30.2";
|
|
156471
156491
|
var ANNOUNCEMENT_FEATURES = [
|
|
156472
|
-
"
|
|
156492
|
+
"Fixed high idle CPU from the TUI sidebar (#200): it now uses a single persistent connection to the plugin instead of polling, so an idle session no longer burns CPU."
|
|
156473
156493
|
];
|
|
156474
156494
|
var ANNOUNCEMENT_FOOTER = "Join us on Discord: https://discord.gg/F2uWxjGnU";
|
|
156475
156495
|
var STATE_FILENAME = "last_announced_version";
|
|
@@ -172641,6 +172661,94 @@ init_logger();
|
|
|
172641
172661
|
|
|
172642
172662
|
// ../plugin/src/features/magic-context/compartment-chunk-embedding.ts
|
|
172643
172663
|
import { createHash as createHash6 } from "node:crypto";
|
|
172664
|
+
init_logger();
|
|
172665
|
+
|
|
172666
|
+
// ../plugin/src/features/magic-context/recursive-text-splitter.ts
|
|
172667
|
+
var DEFAULT_SEPARATORS = [`
|
|
172668
|
+
|
|
172669
|
+
`, `
|
|
172670
|
+
`, " ", ""];
|
|
172671
|
+
function splitOnSeparator(text, separator) {
|
|
172672
|
+
const splits = separator ? text.split(separator) : text.split("");
|
|
172673
|
+
return splits.filter((s) => s !== "");
|
|
172674
|
+
}
|
|
172675
|
+
function mergeSplits(splits, separator, chunkSize, lengthFunction) {
|
|
172676
|
+
const docs = [];
|
|
172677
|
+
const currentDoc = [];
|
|
172678
|
+
let total = 0;
|
|
172679
|
+
const joinDocs = (docsToJoin) => {
|
|
172680
|
+
const joined = docsToJoin.join(separator).trim();
|
|
172681
|
+
return joined === "" ? null : joined;
|
|
172682
|
+
};
|
|
172683
|
+
for (const d of splits) {
|
|
172684
|
+
const len = lengthFunction(d);
|
|
172685
|
+
if (total + len + currentDoc.length * separator.length > chunkSize) {
|
|
172686
|
+
if (currentDoc.length > 0) {
|
|
172687
|
+
const doc3 = joinDocs(currentDoc);
|
|
172688
|
+
if (doc3 !== null)
|
|
172689
|
+
docs.push(doc3);
|
|
172690
|
+
while (total > 0 && currentDoc.length > 0) {
|
|
172691
|
+
total -= lengthFunction(currentDoc[0]);
|
|
172692
|
+
currentDoc.shift();
|
|
172693
|
+
}
|
|
172694
|
+
}
|
|
172695
|
+
}
|
|
172696
|
+
currentDoc.push(d);
|
|
172697
|
+
total += len;
|
|
172698
|
+
}
|
|
172699
|
+
const doc2 = joinDocs(currentDoc);
|
|
172700
|
+
if (doc2 !== null)
|
|
172701
|
+
docs.push(doc2);
|
|
172702
|
+
return docs;
|
|
172703
|
+
}
|
|
172704
|
+
function splitTextRecursive(text, separators, chunkSize, lengthFunction) {
|
|
172705
|
+
const finalChunks = [];
|
|
172706
|
+
let separator = separators[separators.length - 1];
|
|
172707
|
+
let newSeparators;
|
|
172708
|
+
for (let i = 0;i < separators.length; i += 1) {
|
|
172709
|
+
const s = separators[i];
|
|
172710
|
+
if (s === "") {
|
|
172711
|
+
separator = s;
|
|
172712
|
+
break;
|
|
172713
|
+
}
|
|
172714
|
+
if (text.includes(s)) {
|
|
172715
|
+
separator = s;
|
|
172716
|
+
newSeparators = separators.slice(i + 1);
|
|
172717
|
+
break;
|
|
172718
|
+
}
|
|
172719
|
+
}
|
|
172720
|
+
const splits = splitOnSeparator(text, separator);
|
|
172721
|
+
let goodSplits = [];
|
|
172722
|
+
for (const s of splits) {
|
|
172723
|
+
if (lengthFunction(s) < chunkSize) {
|
|
172724
|
+
goodSplits.push(s);
|
|
172725
|
+
} else {
|
|
172726
|
+
if (goodSplits.length) {
|
|
172727
|
+
finalChunks.push(...mergeSplits(goodSplits, separator, chunkSize, lengthFunction));
|
|
172728
|
+
goodSplits = [];
|
|
172729
|
+
}
|
|
172730
|
+
if (!newSeparators) {
|
|
172731
|
+
finalChunks.push(s);
|
|
172732
|
+
} else {
|
|
172733
|
+
finalChunks.push(...splitTextRecursive(s, newSeparators, chunkSize, lengthFunction));
|
|
172734
|
+
}
|
|
172735
|
+
}
|
|
172736
|
+
}
|
|
172737
|
+
if (goodSplits.length) {
|
|
172738
|
+
finalChunks.push(...mergeSplits(goodSplits, separator, chunkSize, lengthFunction));
|
|
172739
|
+
}
|
|
172740
|
+
return finalChunks;
|
|
172741
|
+
}
|
|
172742
|
+
function recursiveCharacterSplit(text, options) {
|
|
172743
|
+
const chunkSize = options.chunkSize;
|
|
172744
|
+
const lengthFunction = options.lengthFunction ?? ((t) => t.length);
|
|
172745
|
+
const separators = options.separators ?? DEFAULT_SEPARATORS;
|
|
172746
|
+
if (text.length === 0)
|
|
172747
|
+
return [];
|
|
172748
|
+
return splitTextRecursive(text, separators, chunkSize, lengthFunction);
|
|
172749
|
+
}
|
|
172750
|
+
|
|
172751
|
+
// ../plugin/src/features/magic-context/compartment-chunk-embedding.ts
|
|
172644
172752
|
var DEFAULT_COMPARTMENT_CHUNK_MAX_INPUT_TOKENS = 512;
|
|
172645
172753
|
var CHUNK_WINDOW_SAFETY_RATIO = 0.9;
|
|
172646
172754
|
var loadFtsRowsStatements = new WeakMap;
|
|
@@ -172919,6 +173027,19 @@ function chunkCanonicalText(canonicalText, startOrdinal, endOrdinal, maxInputTok
|
|
|
172919
173027
|
const lineStart = range?.start ?? startOrdinal;
|
|
172920
173028
|
const lineEnd = range?.end ?? lineStart;
|
|
172921
173029
|
const lineTokens = estimateTokens(line);
|
|
173030
|
+
if (lineTokens > effectiveMax) {
|
|
173031
|
+
flush2();
|
|
173032
|
+
for (const slice of splitOversizedLine(line, effectiveMax)) {
|
|
173033
|
+
windows.push({
|
|
173034
|
+
windowIndex: windows.length + 1,
|
|
173035
|
+
startOrdinal: lineStart,
|
|
173036
|
+
endOrdinal: lineEnd,
|
|
173037
|
+
text: slice,
|
|
173038
|
+
chunkHash: hashChunkText(slice)
|
|
173039
|
+
});
|
|
173040
|
+
}
|
|
173041
|
+
continue;
|
|
173042
|
+
}
|
|
172922
173043
|
if (currentLines.length > 0 && currentTokens + lineTokens > effectiveMax) {
|
|
172923
173044
|
flush2();
|
|
172924
173045
|
}
|
|
@@ -172932,6 +173053,56 @@ function chunkCanonicalText(canonicalText, startOrdinal, endOrdinal, maxInputTok
|
|
|
172932
173053
|
flush2();
|
|
172933
173054
|
return windows;
|
|
172934
173055
|
}
|
|
173056
|
+
function splitOversizedLine(line, effectiveMax) {
|
|
173057
|
+
let slices = [];
|
|
173058
|
+
try {
|
|
173059
|
+
slices = recursiveCharacterSplit(line, {
|
|
173060
|
+
chunkSize: effectiveMax,
|
|
173061
|
+
lengthFunction: estimateTokens
|
|
173062
|
+
});
|
|
173063
|
+
} catch (error51) {
|
|
173064
|
+
log("[magic-context] recursiveCharacterSplit failed; using char-budget fallback:", error51);
|
|
173065
|
+
slices = [];
|
|
173066
|
+
}
|
|
173067
|
+
if (slices.length === 0) {
|
|
173068
|
+
slices = charBudgetSplit(line, effectiveMax);
|
|
173069
|
+
}
|
|
173070
|
+
const safe = [];
|
|
173071
|
+
const pushChecked = (slice) => {
|
|
173072
|
+
if (estimateTokens(slice) > effectiveMax && slice.length > 1) {
|
|
173073
|
+
safe.push(...charBudgetSplit(slice, effectiveMax));
|
|
173074
|
+
return;
|
|
173075
|
+
}
|
|
173076
|
+
safe.push(slice);
|
|
173077
|
+
};
|
|
173078
|
+
for (const slice of slices) {
|
|
173079
|
+
if (estimateTokens(slice) <= effectiveMax) {
|
|
173080
|
+
safe.push(slice);
|
|
173081
|
+
} else {
|
|
173082
|
+
for (const sub of charBudgetSplit(slice, effectiveMax))
|
|
173083
|
+
pushChecked(sub);
|
|
173084
|
+
}
|
|
173085
|
+
}
|
|
173086
|
+
return safe.filter((s) => s.length > 0);
|
|
173087
|
+
}
|
|
173088
|
+
function charBudgetSplit(text, effectiveMax) {
|
|
173089
|
+
const totalTokens = Math.max(1, estimateTokens(text));
|
|
173090
|
+
const charsPerToken = Math.max(1, Math.floor(text.length / totalTokens));
|
|
173091
|
+
const sliceChars = Math.max(1, effectiveMax * charsPerToken);
|
|
173092
|
+
const out = [];
|
|
173093
|
+
let pos = 0;
|
|
173094
|
+
while (pos < text.length) {
|
|
173095
|
+
let end = Math.min(text.length, pos + sliceChars);
|
|
173096
|
+
let slice = text.slice(pos, end);
|
|
173097
|
+
while (slice.length > 1 && estimateTokens(slice) > effectiveMax) {
|
|
173098
|
+
end = pos + Math.max(1, Math.floor((end - pos) / 2));
|
|
173099
|
+
slice = text.slice(pos, end);
|
|
173100
|
+
}
|
|
173101
|
+
out.push(slice);
|
|
173102
|
+
pos = end;
|
|
173103
|
+
}
|
|
173104
|
+
return out;
|
|
173105
|
+
}
|
|
172935
173106
|
function getExistingChunkHashes(db, compartmentId, modelId, projectPath) {
|
|
172936
173107
|
const scoped = typeof projectPath === "string" && projectPath.length > 0;
|
|
172937
173108
|
const rows = scoped ? getExistingHashStatement(db, true).all(compartmentId, modelId, projectPath) : getExistingHashStatement(db, false).all(compartmentId, modelId);
|
|
@@ -173664,6 +173835,7 @@ class OpenAICompatibleEmbeddingProvider {
|
|
|
173664
173835
|
if (texts.length === 0) {
|
|
173665
173836
|
return [];
|
|
173666
173837
|
}
|
|
173838
|
+
const requestTexts = texts.map((t) => t.trim().length === 0 ? " " : t);
|
|
173667
173839
|
if (!await this.initialize()) {
|
|
173668
173840
|
return Array.from({ length: texts.length }, () => null);
|
|
173669
173841
|
}
|
|
@@ -173695,7 +173867,7 @@ class OpenAICompatibleEmbeddingProvider {
|
|
|
173695
173867
|
},
|
|
173696
173868
|
body: JSON.stringify({
|
|
173697
173869
|
model: this.model,
|
|
173698
|
-
input:
|
|
173870
|
+
input: requestTexts,
|
|
173699
173871
|
...inputTypeForRequest ? { input_type: inputTypeForRequest } : {},
|
|
173700
173872
|
...this.truncate ? { truncate: this.truncate } : {}
|
|
173701
173873
|
}),
|
|
@@ -174782,6 +174954,32 @@ async function embedBatchForProject(projectIdentity, texts, signal, purpose = "p
|
|
|
174782
174954
|
}
|
|
174783
174955
|
return { vectors, modelId, generation };
|
|
174784
174956
|
}
|
|
174957
|
+
async function embedTextsWindowBounded(projectIdentity, texts, signal) {
|
|
174958
|
+
if (texts.length <= MAX_WINDOWS_PER_EMBED_CALL) {
|
|
174959
|
+
return embedBatchForProject(projectIdentity, texts, signal);
|
|
174960
|
+
}
|
|
174961
|
+
const vectors = [];
|
|
174962
|
+
let modelId = null;
|
|
174963
|
+
let generation = null;
|
|
174964
|
+
for (let start = 0;start < texts.length; start += MAX_WINDOWS_PER_EMBED_CALL) {
|
|
174965
|
+
if (signal?.aborted)
|
|
174966
|
+
return null;
|
|
174967
|
+
const sub = texts.slice(start, start + MAX_WINDOWS_PER_EMBED_CALL);
|
|
174968
|
+
const result = await embedBatchForProject(projectIdentity, sub, signal);
|
|
174969
|
+
if (!result)
|
|
174970
|
+
return null;
|
|
174971
|
+
if (modelId === null) {
|
|
174972
|
+
modelId = result.modelId;
|
|
174973
|
+
generation = result.generation;
|
|
174974
|
+
} else if (result.modelId !== modelId || result.generation !== generation) {
|
|
174975
|
+
return null;
|
|
174976
|
+
}
|
|
174977
|
+
vectors.push(...result.vectors);
|
|
174978
|
+
}
|
|
174979
|
+
if (modelId === null || generation === null)
|
|
174980
|
+
return null;
|
|
174981
|
+
return { vectors, modelId, generation };
|
|
174982
|
+
}
|
|
174785
174983
|
function isUnembeddedMemoryRow(row) {
|
|
174786
174984
|
if (row === null || typeof row !== "object")
|
|
174787
174985
|
return false;
|
|
@@ -174915,7 +175113,7 @@ async function embedCandidateChunkBatch(db, projectIdentity, modelId, candidates
|
|
|
174915
175113
|
let result = null;
|
|
174916
175114
|
const attemptStart = Date.now();
|
|
174917
175115
|
try {
|
|
174918
|
-
result = await
|
|
175116
|
+
result = await embedTextsWindowBounded(projectIdentity, texts, signal);
|
|
174919
175117
|
} catch (error51) {
|
|
174920
175118
|
log("[magic-context] failed to proactively embed compartment chunks:", error51);
|
|
174921
175119
|
}
|
|
@@ -183536,6 +183734,7 @@ async function loadDefaultPiSessionDeps() {
|
|
|
183536
183734
|
}
|
|
183537
183735
|
|
|
183538
183736
|
// src/dreamer/retrospective-raw-provider-pi.ts
|
|
183737
|
+
import { readFileSync as readFileSync9 } from "node:fs";
|
|
183539
183738
|
import { resolve as resolve2 } from "node:path";
|
|
183540
183739
|
var PI_CODING_AGENT_MODULE2 = "@earendil-works/pi-coding-agent";
|
|
183541
183740
|
|
|
@@ -183643,11 +183842,14 @@ function extractPiTextContent(content) {
|
|
|
183643
183842
|
}
|
|
183644
183843
|
async function loadDefaultPiSessionDeps2() {
|
|
183645
183844
|
const mod = await import(PI_CODING_AGENT_MODULE2);
|
|
183646
|
-
const listSessions = mod.SessionManager?.
|
|
183647
|
-
|
|
183648
|
-
|
|
183649
|
-
throw new Error("Pi session APIs unavailable: expected SessionManager.listSessions and loadEntriesFromFile");
|
|
183845
|
+
const listSessions = mod.SessionManager?.listAll;
|
|
183846
|
+
if (typeof listSessions !== "function") {
|
|
183847
|
+
throw new Error("Pi session APIs unavailable: expected SessionManager.listAll on pi-coding-agent");
|
|
183650
183848
|
}
|
|
183849
|
+
const loadEntriesFromFile = mod.loadEntriesFromFile ?? ((filePath) => {
|
|
183850
|
+
const content = readFileSync9(filePath, "utf8");
|
|
183851
|
+
return mod.parseSessionEntries?.(content) ?? [];
|
|
183852
|
+
});
|
|
183651
183853
|
return {
|
|
183652
183854
|
listSessions: listSessions.bind(mod.SessionManager),
|
|
183653
183855
|
loadEntriesFromFile
|
|
@@ -199799,7 +200001,7 @@ function formatThresholdPercent(value) {
|
|
|
199799
200001
|
// package.json
|
|
199800
200002
|
var package_default = {
|
|
199801
200003
|
name: "@cortexkit/pi-magic-context",
|
|
199802
|
-
version: "0.30.
|
|
200004
|
+
version: "0.30.3",
|
|
199803
200005
|
type: "module",
|
|
199804
200006
|
description: "Pi coding agent extension for Magic Context — cross-session memory and context management",
|
|
199805
200007
|
main: "dist/index.js",
|
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