@letta-ai/letta-code 0.19.5 → 0.19.6
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/letta.js +677 -755
- package/package.json +2 -2
- package/scripts/latency-benchmark.ts +0 -2
package/letta.js
CHANGED
|
@@ -344,7 +344,7 @@ var init_values = __esm(() => {
|
|
|
344
344
|
var sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
345
345
|
|
|
346
346
|
// node_modules/@letta-ai/letta-client/version.mjs
|
|
347
|
-
var VERSION = "1.
|
|
347
|
+
var VERSION = "1.8.0";
|
|
348
348
|
|
|
349
349
|
// node_modules/@letta-ai/letta-client/internal/detect-platform.mjs
|
|
350
350
|
function getDetectedPlatform() {
|
|
@@ -3240,7 +3240,7 @@ var package_default;
|
|
|
3240
3240
|
var init_package = __esm(() => {
|
|
3241
3241
|
package_default = {
|
|
3242
3242
|
name: "@letta-ai/letta-code",
|
|
3243
|
-
version: "0.19.
|
|
3243
|
+
version: "0.19.6",
|
|
3244
3244
|
description: "Letta Code is a CLI tool for interacting with stateful Letta agents from the terminal.",
|
|
3245
3245
|
type: "module",
|
|
3246
3246
|
bin: {
|
|
@@ -3273,7 +3273,7 @@ var init_package = __esm(() => {
|
|
|
3273
3273
|
access: "public"
|
|
3274
3274
|
},
|
|
3275
3275
|
dependencies: {
|
|
3276
|
-
"@letta-ai/letta-client": "
|
|
3276
|
+
"@letta-ai/letta-client": "1.8.0",
|
|
3277
3277
|
glob: "^13.0.0",
|
|
3278
3278
|
"highlight.js": "^11.11.1",
|
|
3279
3279
|
"ink-link": "^5.0.0",
|
|
@@ -6970,7 +6970,12 @@ var init_models2 = __esm(() => {
|
|
|
6970
6970
|
label: "Auto",
|
|
6971
6971
|
description: "Automatically select the best model",
|
|
6972
6972
|
isFeatured: true,
|
|
6973
|
-
free: true
|
|
6973
|
+
free: true,
|
|
6974
|
+
updateArgs: {
|
|
6975
|
+
context_window: 140000,
|
|
6976
|
+
max_output_tokens: 28000,
|
|
6977
|
+
parallel_tool_calls: true
|
|
6978
|
+
}
|
|
6974
6979
|
},
|
|
6975
6980
|
{
|
|
6976
6981
|
id: "auto-fast",
|
|
@@ -6978,7 +6983,12 @@ var init_models2 = __esm(() => {
|
|
|
6978
6983
|
label: "Auto Fast",
|
|
6979
6984
|
description: "Automatically select the best fast model",
|
|
6980
6985
|
isFeatured: true,
|
|
6981
|
-
free: true
|
|
6986
|
+
free: true,
|
|
6987
|
+
updateArgs: {
|
|
6988
|
+
context_window: 140000,
|
|
6989
|
+
max_output_tokens: 28000,
|
|
6990
|
+
parallel_tool_calls: true
|
|
6991
|
+
}
|
|
6982
6992
|
},
|
|
6983
6993
|
{
|
|
6984
6994
|
id: "sonnet",
|
|
@@ -8431,12 +8441,24 @@ var init_models2 = __esm(() => {
|
|
|
8431
8441
|
parallel_tool_calls: true
|
|
8432
8442
|
}
|
|
8433
8443
|
},
|
|
8444
|
+
{
|
|
8445
|
+
id: "minimax-m2.7",
|
|
8446
|
+
handle: "minimax/MiniMax-M2.7",
|
|
8447
|
+
label: "MiniMax 2.7",
|
|
8448
|
+
description: "MiniMax's latest coding model",
|
|
8449
|
+
isFeatured: true,
|
|
8450
|
+
free: true,
|
|
8451
|
+
updateArgs: {
|
|
8452
|
+
context_window: 160000,
|
|
8453
|
+
max_output_tokens: 64000,
|
|
8454
|
+
parallel_tool_calls: true
|
|
8455
|
+
}
|
|
8456
|
+
},
|
|
8434
8457
|
{
|
|
8435
8458
|
id: "minimax-m2.5",
|
|
8436
8459
|
handle: "minimax/MiniMax-M2.5",
|
|
8437
8460
|
label: "MiniMax 2.5",
|
|
8438
|
-
description: "MiniMax's latest coding model",
|
|
8439
|
-
isFeatured: true,
|
|
8461
|
+
description: "MiniMax's latest coding model (legacy)",
|
|
8440
8462
|
free: true,
|
|
8441
8463
|
updateArgs: {
|
|
8442
8464
|
context_window: 160000,
|
|
@@ -39806,9 +39828,483 @@ var init_build4 = __esm(async () => {
|
|
|
39806
39828
|
build_default2 = Spinner;
|
|
39807
39829
|
});
|
|
39808
39830
|
|
|
39809
|
-
// src/cli/helpers/
|
|
39831
|
+
// src/cli/helpers/fileIndex.ts
|
|
39832
|
+
import { createHash as createHash2 } from "node:crypto";
|
|
39833
|
+
import {
|
|
39834
|
+
existsSync as existsSync9,
|
|
39835
|
+
mkdirSync as mkdirSync7,
|
|
39836
|
+
readdirSync as readdirSync4,
|
|
39837
|
+
readFileSync as readFileSync6,
|
|
39838
|
+
statSync as statSync2,
|
|
39839
|
+
writeFileSync as writeFileSync4
|
|
39840
|
+
} from "node:fs";
|
|
39810
39841
|
import { homedir as homedir7 } from "node:os";
|
|
39811
|
-
import { join as join8 } from "node:path";
|
|
39842
|
+
import { join as join8, normalize as normalize2, relative as relative2, sep as sep2 } from "node:path";
|
|
39843
|
+
function normalizeParent2(relativePath) {
|
|
39844
|
+
if (relativePath.length === 0) {
|
|
39845
|
+
return "";
|
|
39846
|
+
}
|
|
39847
|
+
const lastSepIndex = relativePath.lastIndexOf(sep2);
|
|
39848
|
+
return lastSepIndex === -1 ? "" : relativePath.slice(0, lastSepIndex);
|
|
39849
|
+
}
|
|
39850
|
+
function hashValue2(input) {
|
|
39851
|
+
return createHash2("sha256").update(input).digest("hex");
|
|
39852
|
+
}
|
|
39853
|
+
function lowerBound2(sorted, target) {
|
|
39854
|
+
let low = 0;
|
|
39855
|
+
let high = sorted.length;
|
|
39856
|
+
while (low < high) {
|
|
39857
|
+
const mid = low + high >> 1;
|
|
39858
|
+
if ((sorted[mid] ?? "") < target) {
|
|
39859
|
+
low = mid + 1;
|
|
39860
|
+
} else {
|
|
39861
|
+
high = mid;
|
|
39862
|
+
}
|
|
39863
|
+
}
|
|
39864
|
+
return low;
|
|
39865
|
+
}
|
|
39866
|
+
function findPrefixRange2(sorted, prefix) {
|
|
39867
|
+
const start = lowerBound2(sorted, prefix);
|
|
39868
|
+
let end = start;
|
|
39869
|
+
while (end < sorted.length) {
|
|
39870
|
+
const candidate = sorted[end];
|
|
39871
|
+
if (!candidate?.startsWith(prefix)) {
|
|
39872
|
+
break;
|
|
39873
|
+
}
|
|
39874
|
+
end++;
|
|
39875
|
+
}
|
|
39876
|
+
return [start, end];
|
|
39877
|
+
}
|
|
39878
|
+
function preparePreviousIndexData2(cache5) {
|
|
39879
|
+
const entryPaths = cache5.entries.map((entry) => entry.path);
|
|
39880
|
+
const merkleKeys = Object.keys(cache5.merkle).sort();
|
|
39881
|
+
const stats = { ...cache5.stats };
|
|
39882
|
+
const statsKeys = Object.keys(stats).sort();
|
|
39883
|
+
return {
|
|
39884
|
+
entries: cache5.entries,
|
|
39885
|
+
entryPaths,
|
|
39886
|
+
merkle: cache5.merkle,
|
|
39887
|
+
merkleKeys,
|
|
39888
|
+
stats,
|
|
39889
|
+
statsKeys
|
|
39890
|
+
};
|
|
39891
|
+
}
|
|
39892
|
+
function appendSubtreeEntries2(targetEntries, previous, path3) {
|
|
39893
|
+
if (path3 === "") {
|
|
39894
|
+
for (const e of previous.entries)
|
|
39895
|
+
targetEntries.push(e);
|
|
39896
|
+
return;
|
|
39897
|
+
}
|
|
39898
|
+
const { entryPaths, entries: previousEntries } = previous;
|
|
39899
|
+
const prefix = `${path3}/`;
|
|
39900
|
+
const [start, end] = findPrefixRange2(entryPaths, prefix);
|
|
39901
|
+
for (let i = start;i < end; i++) {
|
|
39902
|
+
const entry = previousEntries[i];
|
|
39903
|
+
if (entry !== undefined)
|
|
39904
|
+
targetEntries.push(entry);
|
|
39905
|
+
}
|
|
39906
|
+
}
|
|
39907
|
+
function copyMerkleSubtree2(previous, path3, target) {
|
|
39908
|
+
if (path3 !== "" && previous.merkle[path3]) {
|
|
39909
|
+
target[path3] = previous.merkle[path3];
|
|
39910
|
+
}
|
|
39911
|
+
const prefix = path3 === "" ? "" : `${path3}/`;
|
|
39912
|
+
const [start, end] = prefix === "" ? [0, previous.merkleKeys.length] : findPrefixRange2(previous.merkleKeys, prefix);
|
|
39913
|
+
for (let i = start;i < end; i++) {
|
|
39914
|
+
const key = previous.merkleKeys[i];
|
|
39915
|
+
if (key === undefined)
|
|
39916
|
+
continue;
|
|
39917
|
+
target[key] = previous.merkle[key] ?? "";
|
|
39918
|
+
}
|
|
39919
|
+
}
|
|
39920
|
+
function copyStatsSubtree2(previous, path3, target) {
|
|
39921
|
+
if (path3 !== "" && previous.stats[path3]) {
|
|
39922
|
+
target[path3] = previous.stats[path3];
|
|
39923
|
+
}
|
|
39924
|
+
const prefix = path3 === "" ? "" : `${path3}/`;
|
|
39925
|
+
const [start, end] = prefix === "" ? [0, previous.statsKeys.length] : findPrefixRange2(previous.statsKeys, prefix);
|
|
39926
|
+
for (let i = start;i < end; i++) {
|
|
39927
|
+
const key = previous.statsKeys[i];
|
|
39928
|
+
if (key === undefined)
|
|
39929
|
+
continue;
|
|
39930
|
+
const val = previous.stats[key];
|
|
39931
|
+
if (val !== undefined)
|
|
39932
|
+
target[key] = val;
|
|
39933
|
+
}
|
|
39934
|
+
}
|
|
39935
|
+
function collectPreviousChildNames2(previous, path3) {
|
|
39936
|
+
const names = new Set;
|
|
39937
|
+
const prefix = path3 === "" ? "" : `${path3}/`;
|
|
39938
|
+
const [start, end] = prefix === "" ? [0, previous.statsKeys.length] : findPrefixRange2(previous.statsKeys, prefix);
|
|
39939
|
+
for (let i = start;i < end; i++) {
|
|
39940
|
+
const key = previous.statsKeys[i];
|
|
39941
|
+
if (!key) {
|
|
39942
|
+
continue;
|
|
39943
|
+
}
|
|
39944
|
+
const remainder = key.slice(prefix.length);
|
|
39945
|
+
const slashIndex = remainder.indexOf("/");
|
|
39946
|
+
const childName = slashIndex === -1 ? remainder : remainder.slice(0, slashIndex);
|
|
39947
|
+
if (childName.length > 0) {
|
|
39948
|
+
names.add(childName);
|
|
39949
|
+
}
|
|
39950
|
+
}
|
|
39951
|
+
return names;
|
|
39952
|
+
}
|
|
39953
|
+
function statsMatch2(prev, current) {
|
|
39954
|
+
if (prev.type === "dir" && !current.isDirectory()) {
|
|
39955
|
+
return false;
|
|
39956
|
+
}
|
|
39957
|
+
if (prev.type === "file" && !current.isFile()) {
|
|
39958
|
+
return false;
|
|
39959
|
+
}
|
|
39960
|
+
if (prev.mtimeMs !== current.mtimeMs || prev.ino !== (current.ino ?? 0)) {
|
|
39961
|
+
return false;
|
|
39962
|
+
}
|
|
39963
|
+
if (prev.type === "file") {
|
|
39964
|
+
return typeof prev.size === "number" ? prev.size === current.size : true;
|
|
39965
|
+
}
|
|
39966
|
+
return true;
|
|
39967
|
+
}
|
|
39968
|
+
function shouldReuseDirectory2(previous, path3, stats, childNames, childStats) {
|
|
39969
|
+
if (!previous) {
|
|
39970
|
+
return false;
|
|
39971
|
+
}
|
|
39972
|
+
const previousStats = previous.stats[path3];
|
|
39973
|
+
if (!previousStats || previousStats.type !== "dir") {
|
|
39974
|
+
return false;
|
|
39975
|
+
}
|
|
39976
|
+
if (previousStats.mtimeMs !== stats.mtimeMs || previousStats.ino !== stats.ino) {
|
|
39977
|
+
return false;
|
|
39978
|
+
}
|
|
39979
|
+
const previousChildNames = collectPreviousChildNames2(previous, path3);
|
|
39980
|
+
const seen = new Set;
|
|
39981
|
+
for (const childName of childNames) {
|
|
39982
|
+
const childPath = path3 === "" ? childName : `${path3}/${childName}`;
|
|
39983
|
+
const prevStats = previous.stats[childPath];
|
|
39984
|
+
const currentStats = childStats.get(childName);
|
|
39985
|
+
if (!prevStats || !currentStats) {
|
|
39986
|
+
return false;
|
|
39987
|
+
}
|
|
39988
|
+
if (!statsMatch2(prevStats, currentStats)) {
|
|
39989
|
+
return false;
|
|
39990
|
+
}
|
|
39991
|
+
seen.add(childName);
|
|
39992
|
+
}
|
|
39993
|
+
if (seen.size !== previousChildNames.size) {
|
|
39994
|
+
return false;
|
|
39995
|
+
}
|
|
39996
|
+
for (const name of previousChildNames) {
|
|
39997
|
+
if (!seen.has(name)) {
|
|
39998
|
+
return false;
|
|
39999
|
+
}
|
|
40000
|
+
}
|
|
40001
|
+
return true;
|
|
40002
|
+
}
|
|
40003
|
+
async function buildDirectory2(dir, relativePath, entries, merkle, statsMap, previous, depth, context2) {
|
|
40004
|
+
let dirStats;
|
|
40005
|
+
try {
|
|
40006
|
+
dirStats = statSync2(dir);
|
|
40007
|
+
} catch {
|
|
40008
|
+
const unreadableHash = hashValue2("__unreadable__");
|
|
40009
|
+
merkle[relativePath] = unreadableHash;
|
|
40010
|
+
return unreadableHash;
|
|
40011
|
+
}
|
|
40012
|
+
const currentStats = {
|
|
40013
|
+
type: "dir",
|
|
40014
|
+
mtimeMs: dirStats.mtimeMs,
|
|
40015
|
+
ino: dirStats.ino ?? 0
|
|
40016
|
+
};
|
|
40017
|
+
let dirEntries;
|
|
40018
|
+
try {
|
|
40019
|
+
dirEntries = readdirSync4(dir);
|
|
40020
|
+
} catch {
|
|
40021
|
+
const unreadableHash = hashValue2("__unreadable__");
|
|
40022
|
+
merkle[relativePath] = unreadableHash;
|
|
40023
|
+
return unreadableHash;
|
|
40024
|
+
}
|
|
40025
|
+
const childNames = [];
|
|
40026
|
+
const childStatsMap = new Map;
|
|
40027
|
+
for (const entry of dirEntries) {
|
|
40028
|
+
const entryRelPath = relativePath === "" ? entry : `${relativePath}/${entry}`;
|
|
40029
|
+
if (shouldExcludeEntry(entry, entryRelPath)) {
|
|
40030
|
+
continue;
|
|
40031
|
+
}
|
|
40032
|
+
try {
|
|
40033
|
+
const childStat = statSync2(join8(dir, entry));
|
|
40034
|
+
childNames.push(entry);
|
|
40035
|
+
childStatsMap.set(entry, childStat);
|
|
40036
|
+
} catch {}
|
|
40037
|
+
}
|
|
40038
|
+
if (previous !== undefined && shouldReuseDirectory2(previous, relativePath, currentStats, childNames, childStatsMap)) {
|
|
40039
|
+
copyStatsSubtree2(previous, relativePath, statsMap);
|
|
40040
|
+
appendSubtreeEntries2(entries, previous, relativePath);
|
|
40041
|
+
copyMerkleSubtree2(previous, relativePath, merkle);
|
|
40042
|
+
return previous.merkle[relativePath] ?? hashValue2("__reused__");
|
|
40043
|
+
}
|
|
40044
|
+
statsMap[relativePath] = currentStats;
|
|
40045
|
+
if (depth >= MAX_INDEX_DEPTH2 || context2.newEntryCount >= MAX_CACHE_ENTRIES2) {
|
|
40046
|
+
context2.truncated = true;
|
|
40047
|
+
const truncatedHash = hashValue2("__truncated__");
|
|
40048
|
+
merkle[relativePath] = truncatedHash;
|
|
40049
|
+
return truncatedHash;
|
|
40050
|
+
}
|
|
40051
|
+
const childHashes = [];
|
|
40052
|
+
for (const entry of childNames) {
|
|
40053
|
+
if (context2.newEntryCount >= MAX_CACHE_ENTRIES2) {
|
|
40054
|
+
context2.truncated = true;
|
|
40055
|
+
break;
|
|
40056
|
+
}
|
|
40057
|
+
if (context2.newEntryCount > 0 && context2.newEntryCount % 500 === 0) {
|
|
40058
|
+
await new Promise((resolve2) => setImmediate(resolve2));
|
|
40059
|
+
}
|
|
40060
|
+
const entryStat = childStatsMap.get(entry);
|
|
40061
|
+
if (!entryStat) {
|
|
40062
|
+
continue;
|
|
40063
|
+
}
|
|
40064
|
+
const fullPath = join8(dir, entry);
|
|
40065
|
+
const entryPath = relative2(process.cwd(), fullPath);
|
|
40066
|
+
if (!entryPath) {
|
|
40067
|
+
continue;
|
|
40068
|
+
}
|
|
40069
|
+
if (entryStat.isDirectory()) {
|
|
40070
|
+
entries.push({
|
|
40071
|
+
path: entryPath,
|
|
40072
|
+
type: "dir",
|
|
40073
|
+
lowerPath: entryPath.toLowerCase(),
|
|
40074
|
+
parent: normalizeParent2(entryPath)
|
|
40075
|
+
});
|
|
40076
|
+
context2.newEntryCount++;
|
|
40077
|
+
const childHash = await buildDirectory2(fullPath, entryPath, entries, merkle, statsMap, previous, depth + 1, context2);
|
|
40078
|
+
childHashes.push(`dir:${entry}:${childHash}`);
|
|
40079
|
+
} else {
|
|
40080
|
+
const fileHash = hashValue2(`${entryPath}:${entryStat.size}:${entryStat.mtimeMs}:${entryStat.ino ?? 0}`);
|
|
40081
|
+
statsMap[entryPath] = {
|
|
40082
|
+
type: "file",
|
|
40083
|
+
mtimeMs: entryStat.mtimeMs,
|
|
40084
|
+
ino: entryStat.ino ?? 0,
|
|
40085
|
+
size: entryStat.size
|
|
40086
|
+
};
|
|
40087
|
+
merkle[entryPath] = fileHash;
|
|
40088
|
+
entries.push({
|
|
40089
|
+
path: entryPath,
|
|
40090
|
+
type: "file",
|
|
40091
|
+
lowerPath: entryPath.toLowerCase(),
|
|
40092
|
+
parent: normalizeParent2(entryPath)
|
|
40093
|
+
});
|
|
40094
|
+
context2.newEntryCount++;
|
|
40095
|
+
childHashes.push(`file:${entry}:${fileHash}`);
|
|
40096
|
+
}
|
|
40097
|
+
}
|
|
40098
|
+
const dirHash = hashValue2(childHashes.sort().join("|"));
|
|
40099
|
+
merkle[relativePath] = dirHash;
|
|
40100
|
+
return dirHash;
|
|
40101
|
+
}
|
|
40102
|
+
async function buildIndex2(previous) {
|
|
40103
|
+
const entries = [];
|
|
40104
|
+
const merkle = {};
|
|
40105
|
+
const statsMap = {};
|
|
40106
|
+
const context2 = { newEntryCount: 0, truncated: false };
|
|
40107
|
+
const rootHash = await buildDirectory2(process.cwd(), "", entries, merkle, statsMap, previous, 0, context2);
|
|
40108
|
+
entries.sort((a, b) => a.path.localeCompare(b.path));
|
|
40109
|
+
const seen = new Set;
|
|
40110
|
+
const deduped = entries.filter((e) => {
|
|
40111
|
+
if (seen.has(e.path))
|
|
40112
|
+
return false;
|
|
40113
|
+
seen.add(e.path);
|
|
40114
|
+
return true;
|
|
40115
|
+
});
|
|
40116
|
+
return {
|
|
40117
|
+
entries: deduped,
|
|
40118
|
+
merkle,
|
|
40119
|
+
stats: statsMap,
|
|
40120
|
+
rootHash,
|
|
40121
|
+
truncated: context2.truncated
|
|
40122
|
+
};
|
|
40123
|
+
}
|
|
40124
|
+
function sanitizeWorkspacePath2(workspacePath) {
|
|
40125
|
+
const normalizedPath = normalize2(workspacePath);
|
|
40126
|
+
const strippedPath = normalizedPath.replace(/^[/\\]+/, "");
|
|
40127
|
+
const sanitized = strippedPath.replace(/[/\\:]/g, "_").replace(/\s+/g, "_");
|
|
40128
|
+
return sanitized.length === 0 ? "workspace" : sanitized;
|
|
40129
|
+
}
|
|
40130
|
+
function getProjectStorageDir2() {
|
|
40131
|
+
const homeDir = homedir7();
|
|
40132
|
+
const sanitizedWorkspace = sanitizeWorkspacePath2(process.cwd());
|
|
40133
|
+
return join8(homeDir, ".letta", "projects", sanitizedWorkspace);
|
|
40134
|
+
}
|
|
40135
|
+
function ensureProjectStorageDir2() {
|
|
40136
|
+
const storageDir = getProjectStorageDir2();
|
|
40137
|
+
if (!existsSync9(storageDir)) {
|
|
40138
|
+
mkdirSync7(storageDir, { recursive: true });
|
|
40139
|
+
}
|
|
40140
|
+
return storageDir;
|
|
40141
|
+
}
|
|
40142
|
+
function getProjectIndexPath2() {
|
|
40143
|
+
return join8(getProjectStorageDir2(), PROJECT_INDEX_FILENAME2);
|
|
40144
|
+
}
|
|
40145
|
+
function loadCachedIndex2() {
|
|
40146
|
+
const indexPath = getProjectIndexPath2();
|
|
40147
|
+
if (!existsSync9(indexPath)) {
|
|
40148
|
+
return null;
|
|
40149
|
+
}
|
|
40150
|
+
try {
|
|
40151
|
+
const content = readFileSync6(indexPath, "utf-8");
|
|
40152
|
+
const parsed = JSON.parse(content);
|
|
40153
|
+
if (parsed?.metadata && typeof parsed.metadata.rootHash === "string" && Array.isArray(parsed.entries) && parsed.merkle && typeof parsed.merkle === "object") {
|
|
40154
|
+
const merkle = {};
|
|
40155
|
+
for (const [key, value] of Object.entries(parsed.merkle)) {
|
|
40156
|
+
if (typeof value === "string") {
|
|
40157
|
+
merkle[key] = value;
|
|
40158
|
+
}
|
|
40159
|
+
}
|
|
40160
|
+
const stats = {};
|
|
40161
|
+
if (parsed.stats && typeof parsed.stats === "object") {
|
|
40162
|
+
for (const [path3, rawStats] of Object.entries(parsed.stats)) {
|
|
40163
|
+
const sv = rawStats;
|
|
40164
|
+
if (sv && typeof sv.mtimeMs === "number" && typeof sv.ino === "number" && (sv.type === "file" || sv.type === "dir")) {
|
|
40165
|
+
stats[path3] = {
|
|
40166
|
+
type: sv.type,
|
|
40167
|
+
mtimeMs: sv.mtimeMs,
|
|
40168
|
+
ino: sv.ino
|
|
40169
|
+
};
|
|
40170
|
+
}
|
|
40171
|
+
}
|
|
40172
|
+
}
|
|
40173
|
+
return {
|
|
40174
|
+
metadata: {
|
|
40175
|
+
rootHash: parsed.metadata.rootHash
|
|
40176
|
+
},
|
|
40177
|
+
entries: parsed.entries,
|
|
40178
|
+
merkle,
|
|
40179
|
+
stats
|
|
40180
|
+
};
|
|
40181
|
+
}
|
|
40182
|
+
} catch {}
|
|
40183
|
+
return null;
|
|
40184
|
+
}
|
|
40185
|
+
function cacheProjectIndex2(result) {
|
|
40186
|
+
try {
|
|
40187
|
+
const storageDir = ensureProjectStorageDir2();
|
|
40188
|
+
const indexPath = join8(storageDir, PROJECT_INDEX_FILENAME2);
|
|
40189
|
+
const payload = {
|
|
40190
|
+
metadata: {
|
|
40191
|
+
rootHash: result.rootHash
|
|
40192
|
+
},
|
|
40193
|
+
entries: result.entries,
|
|
40194
|
+
merkle: result.merkle,
|
|
40195
|
+
stats: result.stats
|
|
40196
|
+
};
|
|
40197
|
+
writeFileSync4(indexPath, JSON.stringify(payload, null, 2), "utf-8");
|
|
40198
|
+
} catch {}
|
|
40199
|
+
}
|
|
40200
|
+
function buildCachedEntries2(entries, stats) {
|
|
40201
|
+
const sorted = [...entries].sort((a, b) => {
|
|
40202
|
+
if (a.type === "dir" && b.type !== "dir")
|
|
40203
|
+
return -1;
|
|
40204
|
+
if (a.type !== "dir" && b.type === "dir")
|
|
40205
|
+
return 1;
|
|
40206
|
+
const aMtime = stats[a.path]?.mtimeMs ?? 0;
|
|
40207
|
+
const bMtime = stats[b.path]?.mtimeMs ?? 0;
|
|
40208
|
+
return bMtime - aMtime;
|
|
40209
|
+
}).slice(0, MAX_CACHE_ENTRIES2);
|
|
40210
|
+
return { entries: sorted, paths: new Set(sorted.map((e) => e.path)) };
|
|
40211
|
+
}
|
|
40212
|
+
function ensureFileIndex2() {
|
|
40213
|
+
if (hasCompletedBuild2)
|
|
40214
|
+
return Promise.resolve();
|
|
40215
|
+
if (!buildPromise2) {
|
|
40216
|
+
let currentPromise;
|
|
40217
|
+
currentPromise = (async () => {
|
|
40218
|
+
let succeeded = false;
|
|
40219
|
+
try {
|
|
40220
|
+
const diskIndex = loadCachedIndex2();
|
|
40221
|
+
const previousData = diskIndex ? preparePreviousIndexData2(diskIndex) : undefined;
|
|
40222
|
+
const buildResult = await buildIndex2(previousData);
|
|
40223
|
+
if (diskIndex && diskIndex.metadata.rootHash === buildResult.rootHash) {
|
|
40224
|
+
({ entries: cachedEntries2, paths: cachedEntryPaths2 } = buildCachedEntries2(buildResult.entries, buildResult.stats));
|
|
40225
|
+
succeeded = true;
|
|
40226
|
+
return;
|
|
40227
|
+
}
|
|
40228
|
+
if (buildResult.truncated) {
|
|
40229
|
+
debugLog("file-index", `Index truncated: workspace exceeds ${MAX_INDEX_DEPTH2} directory levels deep. ` + `Files beyond that depth will fall back to disk search.`);
|
|
40230
|
+
}
|
|
40231
|
+
cacheProjectIndex2(buildResult);
|
|
40232
|
+
({ entries: cachedEntries2, paths: cachedEntryPaths2 } = buildCachedEntries2(buildResult.entries, buildResult.stats));
|
|
40233
|
+
succeeded = true;
|
|
40234
|
+
} finally {
|
|
40235
|
+
if (buildPromise2 === currentPromise)
|
|
40236
|
+
buildPromise2 = null;
|
|
40237
|
+
if (succeeded)
|
|
40238
|
+
hasCompletedBuild2 = true;
|
|
40239
|
+
}
|
|
40240
|
+
})();
|
|
40241
|
+
buildPromise2 = currentPromise;
|
|
40242
|
+
}
|
|
40243
|
+
return buildPromise2;
|
|
40244
|
+
}
|
|
40245
|
+
function refreshFileIndex() {
|
|
40246
|
+
hasCompletedBuild2 = false;
|
|
40247
|
+
buildPromise2 = null;
|
|
40248
|
+
return ensureFileIndex2();
|
|
40249
|
+
}
|
|
40250
|
+
function addEntriesToCache(matches) {
|
|
40251
|
+
const available = MAX_CACHE_ENTRIES2 - cachedEntries2.length;
|
|
40252
|
+
if (available <= 0)
|
|
40253
|
+
return;
|
|
40254
|
+
let added = 0;
|
|
40255
|
+
for (const match of matches) {
|
|
40256
|
+
if (added >= available)
|
|
40257
|
+
break;
|
|
40258
|
+
if (!cachedEntryPaths2.has(match.path)) {
|
|
40259
|
+
cachedEntries2.push({
|
|
40260
|
+
path: match.path,
|
|
40261
|
+
type: match.type,
|
|
40262
|
+
lowerPath: match.path.toLowerCase(),
|
|
40263
|
+
parent: normalizeParent2(match.path)
|
|
40264
|
+
});
|
|
40265
|
+
cachedEntryPaths2.add(match.path);
|
|
40266
|
+
added++;
|
|
40267
|
+
}
|
|
40268
|
+
}
|
|
40269
|
+
}
|
|
40270
|
+
function searchFileIndex(options) {
|
|
40271
|
+
const { searchDir, pattern, deep, maxResults } = options;
|
|
40272
|
+
const normalizedDir = searchDir === "." ? "" : searchDir;
|
|
40273
|
+
const dirWithSep = normalizedDir === "" ? "" : `${normalizedDir}${sep2}`;
|
|
40274
|
+
const lowerPattern = pattern.toLowerCase();
|
|
40275
|
+
const results = [];
|
|
40276
|
+
for (const entry of cachedEntries2) {
|
|
40277
|
+
if (normalizedDir) {
|
|
40278
|
+
if (entry.path !== normalizedDir && !entry.path.startsWith(dirWithSep)) {
|
|
40279
|
+
continue;
|
|
40280
|
+
}
|
|
40281
|
+
}
|
|
40282
|
+
if (!deep && entry.parent !== normalizedDir) {
|
|
40283
|
+
continue;
|
|
40284
|
+
}
|
|
40285
|
+
if (lowerPattern && !entry.lowerPath.includes(lowerPattern)) {
|
|
40286
|
+
continue;
|
|
40287
|
+
}
|
|
40288
|
+
results.push({ path: entry.path, type: entry.type });
|
|
40289
|
+
if (results.length >= maxResults) {
|
|
40290
|
+
break;
|
|
40291
|
+
}
|
|
40292
|
+
}
|
|
40293
|
+
return results;
|
|
40294
|
+
}
|
|
40295
|
+
var MAX_INDEX_DEPTH2 = 12, PROJECT_INDEX_FILENAME2 = "file-index.json", MAX_CACHE_ENTRIES2, cachedEntries2, cachedEntryPaths2, buildPromise2 = null, hasCompletedBuild2 = false;
|
|
40296
|
+
var init_fileIndex = __esm(() => {
|
|
40297
|
+
init_debug();
|
|
40298
|
+
init_lettaSettings();
|
|
40299
|
+
init_fileSearchConfig();
|
|
40300
|
+
MAX_CACHE_ENTRIES2 = readIntSetting("MAX_ENTRIES", 50000);
|
|
40301
|
+
cachedEntries2 = [];
|
|
40302
|
+
cachedEntryPaths2 = new Set;
|
|
40303
|
+
});
|
|
40304
|
+
|
|
40305
|
+
// src/cli/helpers/planName.ts
|
|
40306
|
+
import { homedir as homedir8 } from "node:os";
|
|
40307
|
+
import { join as join9 } from "node:path";
|
|
39812
40308
|
function randomElement(arr) {
|
|
39813
40309
|
return arr[Math.floor(Math.random() * arr.length)];
|
|
39814
40310
|
}
|
|
@@ -39820,7 +40316,7 @@ function generatePlanName() {
|
|
|
39820
40316
|
}
|
|
39821
40317
|
function generatePlanFilePath() {
|
|
39822
40318
|
const name = generatePlanName();
|
|
39823
|
-
return
|
|
40319
|
+
return join9(homedir8(), ".letta", "plans", `${name}.md`);
|
|
39824
40320
|
}
|
|
39825
40321
|
var adjectives, nouns;
|
|
39826
40322
|
var init_planName = __esm(() => {
|
|
@@ -40383,480 +40879,6 @@ var init_approval_execution = __esm(async () => {
|
|
|
40383
40879
|
]);
|
|
40384
40880
|
});
|
|
40385
40881
|
|
|
40386
|
-
// src/cli/helpers/fileIndex.ts
|
|
40387
|
-
import { createHash as createHash2 } from "node:crypto";
|
|
40388
|
-
import {
|
|
40389
|
-
existsSync as existsSync9,
|
|
40390
|
-
mkdirSync as mkdirSync7,
|
|
40391
|
-
readdirSync as readdirSync4,
|
|
40392
|
-
readFileSync as readFileSync6,
|
|
40393
|
-
statSync as statSync2,
|
|
40394
|
-
writeFileSync as writeFileSync4
|
|
40395
|
-
} from "node:fs";
|
|
40396
|
-
import { homedir as homedir8 } from "node:os";
|
|
40397
|
-
import { join as join9, normalize as normalize3, relative as relative2, sep as sep2 } from "node:path";
|
|
40398
|
-
function normalizeParent2(relativePath) {
|
|
40399
|
-
if (relativePath.length === 0) {
|
|
40400
|
-
return "";
|
|
40401
|
-
}
|
|
40402
|
-
const lastSepIndex = relativePath.lastIndexOf(sep2);
|
|
40403
|
-
return lastSepIndex === -1 ? "" : relativePath.slice(0, lastSepIndex);
|
|
40404
|
-
}
|
|
40405
|
-
function hashValue2(input) {
|
|
40406
|
-
return createHash2("sha256").update(input).digest("hex");
|
|
40407
|
-
}
|
|
40408
|
-
function lowerBound2(sorted, target) {
|
|
40409
|
-
let low = 0;
|
|
40410
|
-
let high = sorted.length;
|
|
40411
|
-
while (low < high) {
|
|
40412
|
-
const mid = low + high >> 1;
|
|
40413
|
-
if ((sorted[mid] ?? "") < target) {
|
|
40414
|
-
low = mid + 1;
|
|
40415
|
-
} else {
|
|
40416
|
-
high = mid;
|
|
40417
|
-
}
|
|
40418
|
-
}
|
|
40419
|
-
return low;
|
|
40420
|
-
}
|
|
40421
|
-
function findPrefixRange2(sorted, prefix) {
|
|
40422
|
-
const start = lowerBound2(sorted, prefix);
|
|
40423
|
-
let end = start;
|
|
40424
|
-
while (end < sorted.length) {
|
|
40425
|
-
const candidate = sorted[end];
|
|
40426
|
-
if (!candidate?.startsWith(prefix)) {
|
|
40427
|
-
break;
|
|
40428
|
-
}
|
|
40429
|
-
end++;
|
|
40430
|
-
}
|
|
40431
|
-
return [start, end];
|
|
40432
|
-
}
|
|
40433
|
-
function preparePreviousIndexData2(cache5) {
|
|
40434
|
-
const entryPaths = cache5.entries.map((entry) => entry.path);
|
|
40435
|
-
const merkleKeys = Object.keys(cache5.merkle).sort();
|
|
40436
|
-
const stats = { ...cache5.stats };
|
|
40437
|
-
const statsKeys = Object.keys(stats).sort();
|
|
40438
|
-
return {
|
|
40439
|
-
entries: cache5.entries,
|
|
40440
|
-
entryPaths,
|
|
40441
|
-
merkle: cache5.merkle,
|
|
40442
|
-
merkleKeys,
|
|
40443
|
-
stats,
|
|
40444
|
-
statsKeys
|
|
40445
|
-
};
|
|
40446
|
-
}
|
|
40447
|
-
function appendSubtreeEntries2(targetEntries, previous, path4) {
|
|
40448
|
-
if (path4 === "") {
|
|
40449
|
-
for (const e of previous.entries)
|
|
40450
|
-
targetEntries.push(e);
|
|
40451
|
-
return;
|
|
40452
|
-
}
|
|
40453
|
-
const { entryPaths, entries: previousEntries } = previous;
|
|
40454
|
-
const prefix = `${path4}/`;
|
|
40455
|
-
const [start, end] = findPrefixRange2(entryPaths, prefix);
|
|
40456
|
-
for (let i = start;i < end; i++) {
|
|
40457
|
-
const entry = previousEntries[i];
|
|
40458
|
-
if (entry !== undefined)
|
|
40459
|
-
targetEntries.push(entry);
|
|
40460
|
-
}
|
|
40461
|
-
}
|
|
40462
|
-
function copyMerkleSubtree2(previous, path4, target) {
|
|
40463
|
-
if (path4 !== "" && previous.merkle[path4]) {
|
|
40464
|
-
target[path4] = previous.merkle[path4];
|
|
40465
|
-
}
|
|
40466
|
-
const prefix = path4 === "" ? "" : `${path4}/`;
|
|
40467
|
-
const [start, end] = prefix === "" ? [0, previous.merkleKeys.length] : findPrefixRange2(previous.merkleKeys, prefix);
|
|
40468
|
-
for (let i = start;i < end; i++) {
|
|
40469
|
-
const key = previous.merkleKeys[i];
|
|
40470
|
-
if (key === undefined)
|
|
40471
|
-
continue;
|
|
40472
|
-
target[key] = previous.merkle[key] ?? "";
|
|
40473
|
-
}
|
|
40474
|
-
}
|
|
40475
|
-
function copyStatsSubtree2(previous, path4, target) {
|
|
40476
|
-
if (path4 !== "" && previous.stats[path4]) {
|
|
40477
|
-
target[path4] = previous.stats[path4];
|
|
40478
|
-
}
|
|
40479
|
-
const prefix = path4 === "" ? "" : `${path4}/`;
|
|
40480
|
-
const [start, end] = prefix === "" ? [0, previous.statsKeys.length] : findPrefixRange2(previous.statsKeys, prefix);
|
|
40481
|
-
for (let i = start;i < end; i++) {
|
|
40482
|
-
const key = previous.statsKeys[i];
|
|
40483
|
-
if (key === undefined)
|
|
40484
|
-
continue;
|
|
40485
|
-
const val = previous.stats[key];
|
|
40486
|
-
if (val !== undefined)
|
|
40487
|
-
target[key] = val;
|
|
40488
|
-
}
|
|
40489
|
-
}
|
|
40490
|
-
function collectPreviousChildNames2(previous, path4) {
|
|
40491
|
-
const names = new Set;
|
|
40492
|
-
const prefix = path4 === "" ? "" : `${path4}/`;
|
|
40493
|
-
const [start, end] = prefix === "" ? [0, previous.statsKeys.length] : findPrefixRange2(previous.statsKeys, prefix);
|
|
40494
|
-
for (let i = start;i < end; i++) {
|
|
40495
|
-
const key = previous.statsKeys[i];
|
|
40496
|
-
if (!key) {
|
|
40497
|
-
continue;
|
|
40498
|
-
}
|
|
40499
|
-
const remainder = key.slice(prefix.length);
|
|
40500
|
-
const slashIndex = remainder.indexOf("/");
|
|
40501
|
-
const childName = slashIndex === -1 ? remainder : remainder.slice(0, slashIndex);
|
|
40502
|
-
if (childName.length > 0) {
|
|
40503
|
-
names.add(childName);
|
|
40504
|
-
}
|
|
40505
|
-
}
|
|
40506
|
-
return names;
|
|
40507
|
-
}
|
|
40508
|
-
function statsMatch2(prev, current) {
|
|
40509
|
-
if (prev.type === "dir" && !current.isDirectory()) {
|
|
40510
|
-
return false;
|
|
40511
|
-
}
|
|
40512
|
-
if (prev.type === "file" && !current.isFile()) {
|
|
40513
|
-
return false;
|
|
40514
|
-
}
|
|
40515
|
-
if (prev.mtimeMs !== current.mtimeMs || prev.ino !== (current.ino ?? 0)) {
|
|
40516
|
-
return false;
|
|
40517
|
-
}
|
|
40518
|
-
if (prev.type === "file") {
|
|
40519
|
-
return typeof prev.size === "number" ? prev.size === current.size : true;
|
|
40520
|
-
}
|
|
40521
|
-
return true;
|
|
40522
|
-
}
|
|
40523
|
-
function shouldReuseDirectory2(previous, path4, stats, childNames, childStats) {
|
|
40524
|
-
if (!previous) {
|
|
40525
|
-
return false;
|
|
40526
|
-
}
|
|
40527
|
-
const previousStats = previous.stats[path4];
|
|
40528
|
-
if (!previousStats || previousStats.type !== "dir") {
|
|
40529
|
-
return false;
|
|
40530
|
-
}
|
|
40531
|
-
if (previousStats.mtimeMs !== stats.mtimeMs || previousStats.ino !== stats.ino) {
|
|
40532
|
-
return false;
|
|
40533
|
-
}
|
|
40534
|
-
const previousChildNames = collectPreviousChildNames2(previous, path4);
|
|
40535
|
-
const seen = new Set;
|
|
40536
|
-
for (const childName of childNames) {
|
|
40537
|
-
const childPath = path4 === "" ? childName : `${path4}/${childName}`;
|
|
40538
|
-
const prevStats = previous.stats[childPath];
|
|
40539
|
-
const currentStats = childStats.get(childName);
|
|
40540
|
-
if (!prevStats || !currentStats) {
|
|
40541
|
-
return false;
|
|
40542
|
-
}
|
|
40543
|
-
if (!statsMatch2(prevStats, currentStats)) {
|
|
40544
|
-
return false;
|
|
40545
|
-
}
|
|
40546
|
-
seen.add(childName);
|
|
40547
|
-
}
|
|
40548
|
-
if (seen.size !== previousChildNames.size) {
|
|
40549
|
-
return false;
|
|
40550
|
-
}
|
|
40551
|
-
for (const name of previousChildNames) {
|
|
40552
|
-
if (!seen.has(name)) {
|
|
40553
|
-
return false;
|
|
40554
|
-
}
|
|
40555
|
-
}
|
|
40556
|
-
return true;
|
|
40557
|
-
}
|
|
40558
|
-
async function buildDirectory2(dir, relativePath, entries, merkle, statsMap, previous, depth, context2) {
|
|
40559
|
-
let dirStats;
|
|
40560
|
-
try {
|
|
40561
|
-
dirStats = statSync2(dir);
|
|
40562
|
-
} catch {
|
|
40563
|
-
const unreadableHash = hashValue2("__unreadable__");
|
|
40564
|
-
merkle[relativePath] = unreadableHash;
|
|
40565
|
-
return unreadableHash;
|
|
40566
|
-
}
|
|
40567
|
-
const currentStats = {
|
|
40568
|
-
type: "dir",
|
|
40569
|
-
mtimeMs: dirStats.mtimeMs,
|
|
40570
|
-
ino: dirStats.ino ?? 0
|
|
40571
|
-
};
|
|
40572
|
-
let dirEntries;
|
|
40573
|
-
try {
|
|
40574
|
-
dirEntries = readdirSync4(dir);
|
|
40575
|
-
} catch {
|
|
40576
|
-
const unreadableHash = hashValue2("__unreadable__");
|
|
40577
|
-
merkle[relativePath] = unreadableHash;
|
|
40578
|
-
return unreadableHash;
|
|
40579
|
-
}
|
|
40580
|
-
const childNames = [];
|
|
40581
|
-
const childStatsMap = new Map;
|
|
40582
|
-
for (const entry of dirEntries) {
|
|
40583
|
-
const entryRelPath = relativePath === "" ? entry : `${relativePath}/${entry}`;
|
|
40584
|
-
if (shouldExcludeEntry(entry, entryRelPath)) {
|
|
40585
|
-
continue;
|
|
40586
|
-
}
|
|
40587
|
-
try {
|
|
40588
|
-
const childStat = statSync2(join9(dir, entry));
|
|
40589
|
-
childNames.push(entry);
|
|
40590
|
-
childStatsMap.set(entry, childStat);
|
|
40591
|
-
} catch {}
|
|
40592
|
-
}
|
|
40593
|
-
if (previous !== undefined && shouldReuseDirectory2(previous, relativePath, currentStats, childNames, childStatsMap)) {
|
|
40594
|
-
copyStatsSubtree2(previous, relativePath, statsMap);
|
|
40595
|
-
appendSubtreeEntries2(entries, previous, relativePath);
|
|
40596
|
-
copyMerkleSubtree2(previous, relativePath, merkle);
|
|
40597
|
-
return previous.merkle[relativePath] ?? hashValue2("__reused__");
|
|
40598
|
-
}
|
|
40599
|
-
statsMap[relativePath] = currentStats;
|
|
40600
|
-
if (depth >= MAX_INDEX_DEPTH2 || context2.newEntryCount >= MAX_CACHE_ENTRIES2) {
|
|
40601
|
-
context2.truncated = true;
|
|
40602
|
-
const truncatedHash = hashValue2("__truncated__");
|
|
40603
|
-
merkle[relativePath] = truncatedHash;
|
|
40604
|
-
return truncatedHash;
|
|
40605
|
-
}
|
|
40606
|
-
const childHashes = [];
|
|
40607
|
-
for (const entry of childNames) {
|
|
40608
|
-
if (context2.newEntryCount >= MAX_CACHE_ENTRIES2) {
|
|
40609
|
-
context2.truncated = true;
|
|
40610
|
-
break;
|
|
40611
|
-
}
|
|
40612
|
-
if (context2.newEntryCount > 0 && context2.newEntryCount % 500 === 0) {
|
|
40613
|
-
await new Promise((resolve3) => setImmediate(resolve3));
|
|
40614
|
-
}
|
|
40615
|
-
const entryStat = childStatsMap.get(entry);
|
|
40616
|
-
if (!entryStat) {
|
|
40617
|
-
continue;
|
|
40618
|
-
}
|
|
40619
|
-
const fullPath = join9(dir, entry);
|
|
40620
|
-
const entryPath = relative2(process.cwd(), fullPath);
|
|
40621
|
-
if (!entryPath) {
|
|
40622
|
-
continue;
|
|
40623
|
-
}
|
|
40624
|
-
if (entryStat.isDirectory()) {
|
|
40625
|
-
entries.push({
|
|
40626
|
-
path: entryPath,
|
|
40627
|
-
type: "dir",
|
|
40628
|
-
lowerPath: entryPath.toLowerCase(),
|
|
40629
|
-
parent: normalizeParent2(entryPath)
|
|
40630
|
-
});
|
|
40631
|
-
context2.newEntryCount++;
|
|
40632
|
-
const childHash = await buildDirectory2(fullPath, entryPath, entries, merkle, statsMap, previous, depth + 1, context2);
|
|
40633
|
-
childHashes.push(`dir:${entry}:${childHash}`);
|
|
40634
|
-
} else {
|
|
40635
|
-
const fileHash = hashValue2(`${entryPath}:${entryStat.size}:${entryStat.mtimeMs}:${entryStat.ino ?? 0}`);
|
|
40636
|
-
statsMap[entryPath] = {
|
|
40637
|
-
type: "file",
|
|
40638
|
-
mtimeMs: entryStat.mtimeMs,
|
|
40639
|
-
ino: entryStat.ino ?? 0,
|
|
40640
|
-
size: entryStat.size
|
|
40641
|
-
};
|
|
40642
|
-
merkle[entryPath] = fileHash;
|
|
40643
|
-
entries.push({
|
|
40644
|
-
path: entryPath,
|
|
40645
|
-
type: "file",
|
|
40646
|
-
lowerPath: entryPath.toLowerCase(),
|
|
40647
|
-
parent: normalizeParent2(entryPath)
|
|
40648
|
-
});
|
|
40649
|
-
context2.newEntryCount++;
|
|
40650
|
-
childHashes.push(`file:${entry}:${fileHash}`);
|
|
40651
|
-
}
|
|
40652
|
-
}
|
|
40653
|
-
const dirHash = hashValue2(childHashes.sort().join("|"));
|
|
40654
|
-
merkle[relativePath] = dirHash;
|
|
40655
|
-
return dirHash;
|
|
40656
|
-
}
|
|
40657
|
-
async function buildIndex2(previous) {
|
|
40658
|
-
const entries = [];
|
|
40659
|
-
const merkle = {};
|
|
40660
|
-
const statsMap = {};
|
|
40661
|
-
const context2 = { newEntryCount: 0, truncated: false };
|
|
40662
|
-
const rootHash = await buildDirectory2(process.cwd(), "", entries, merkle, statsMap, previous, 0, context2);
|
|
40663
|
-
entries.sort((a, b) => a.path.localeCompare(b.path));
|
|
40664
|
-
const seen = new Set;
|
|
40665
|
-
const deduped = entries.filter((e) => {
|
|
40666
|
-
if (seen.has(e.path))
|
|
40667
|
-
return false;
|
|
40668
|
-
seen.add(e.path);
|
|
40669
|
-
return true;
|
|
40670
|
-
});
|
|
40671
|
-
return {
|
|
40672
|
-
entries: deduped,
|
|
40673
|
-
merkle,
|
|
40674
|
-
stats: statsMap,
|
|
40675
|
-
rootHash,
|
|
40676
|
-
truncated: context2.truncated
|
|
40677
|
-
};
|
|
40678
|
-
}
|
|
40679
|
-
function sanitizeWorkspacePath2(workspacePath) {
|
|
40680
|
-
const normalizedPath = normalize3(workspacePath);
|
|
40681
|
-
const strippedPath = normalizedPath.replace(/^[/\\]+/, "");
|
|
40682
|
-
const sanitized = strippedPath.replace(/[/\\:]/g, "_").replace(/\s+/g, "_");
|
|
40683
|
-
return sanitized.length === 0 ? "workspace" : sanitized;
|
|
40684
|
-
}
|
|
40685
|
-
function getProjectStorageDir2() {
|
|
40686
|
-
const homeDir = homedir8();
|
|
40687
|
-
const sanitizedWorkspace = sanitizeWorkspacePath2(process.cwd());
|
|
40688
|
-
return join9(homeDir, ".letta", "projects", sanitizedWorkspace);
|
|
40689
|
-
}
|
|
40690
|
-
function ensureProjectStorageDir2() {
|
|
40691
|
-
const storageDir = getProjectStorageDir2();
|
|
40692
|
-
if (!existsSync9(storageDir)) {
|
|
40693
|
-
mkdirSync7(storageDir, { recursive: true });
|
|
40694
|
-
}
|
|
40695
|
-
return storageDir;
|
|
40696
|
-
}
|
|
40697
|
-
function getProjectIndexPath2() {
|
|
40698
|
-
return join9(getProjectStorageDir2(), PROJECT_INDEX_FILENAME2);
|
|
40699
|
-
}
|
|
40700
|
-
function loadCachedIndex2() {
|
|
40701
|
-
const indexPath = getProjectIndexPath2();
|
|
40702
|
-
if (!existsSync9(indexPath)) {
|
|
40703
|
-
return null;
|
|
40704
|
-
}
|
|
40705
|
-
try {
|
|
40706
|
-
const content = readFileSync6(indexPath, "utf-8");
|
|
40707
|
-
const parsed = JSON.parse(content);
|
|
40708
|
-
if (parsed?.metadata && typeof parsed.metadata.rootHash === "string" && Array.isArray(parsed.entries) && parsed.merkle && typeof parsed.merkle === "object") {
|
|
40709
|
-
const merkle = {};
|
|
40710
|
-
for (const [key, value] of Object.entries(parsed.merkle)) {
|
|
40711
|
-
if (typeof value === "string") {
|
|
40712
|
-
merkle[key] = value;
|
|
40713
|
-
}
|
|
40714
|
-
}
|
|
40715
|
-
const stats = {};
|
|
40716
|
-
if (parsed.stats && typeof parsed.stats === "object") {
|
|
40717
|
-
for (const [path4, rawStats] of Object.entries(parsed.stats)) {
|
|
40718
|
-
const sv = rawStats;
|
|
40719
|
-
if (sv && typeof sv.mtimeMs === "number" && typeof sv.ino === "number" && (sv.type === "file" || sv.type === "dir")) {
|
|
40720
|
-
stats[path4] = {
|
|
40721
|
-
type: sv.type,
|
|
40722
|
-
mtimeMs: sv.mtimeMs,
|
|
40723
|
-
ino: sv.ino
|
|
40724
|
-
};
|
|
40725
|
-
}
|
|
40726
|
-
}
|
|
40727
|
-
}
|
|
40728
|
-
return {
|
|
40729
|
-
metadata: {
|
|
40730
|
-
rootHash: parsed.metadata.rootHash
|
|
40731
|
-
},
|
|
40732
|
-
entries: parsed.entries,
|
|
40733
|
-
merkle,
|
|
40734
|
-
stats
|
|
40735
|
-
};
|
|
40736
|
-
}
|
|
40737
|
-
} catch {}
|
|
40738
|
-
return null;
|
|
40739
|
-
}
|
|
40740
|
-
function cacheProjectIndex2(result) {
|
|
40741
|
-
try {
|
|
40742
|
-
const storageDir = ensureProjectStorageDir2();
|
|
40743
|
-
const indexPath = join9(storageDir, PROJECT_INDEX_FILENAME2);
|
|
40744
|
-
const payload = {
|
|
40745
|
-
metadata: {
|
|
40746
|
-
rootHash: result.rootHash
|
|
40747
|
-
},
|
|
40748
|
-
entries: result.entries,
|
|
40749
|
-
merkle: result.merkle,
|
|
40750
|
-
stats: result.stats
|
|
40751
|
-
};
|
|
40752
|
-
writeFileSync4(indexPath, JSON.stringify(payload, null, 2), "utf-8");
|
|
40753
|
-
} catch {}
|
|
40754
|
-
}
|
|
40755
|
-
function buildCachedEntries2(entries, stats) {
|
|
40756
|
-
const sorted = [...entries].sort((a, b) => {
|
|
40757
|
-
if (a.type === "dir" && b.type !== "dir")
|
|
40758
|
-
return -1;
|
|
40759
|
-
if (a.type !== "dir" && b.type === "dir")
|
|
40760
|
-
return 1;
|
|
40761
|
-
const aMtime = stats[a.path]?.mtimeMs ?? 0;
|
|
40762
|
-
const bMtime = stats[b.path]?.mtimeMs ?? 0;
|
|
40763
|
-
return bMtime - aMtime;
|
|
40764
|
-
}).slice(0, MAX_CACHE_ENTRIES2);
|
|
40765
|
-
return { entries: sorted, paths: new Set(sorted.map((e) => e.path)) };
|
|
40766
|
-
}
|
|
40767
|
-
function ensureFileIndex2() {
|
|
40768
|
-
if (hasCompletedBuild2)
|
|
40769
|
-
return Promise.resolve();
|
|
40770
|
-
if (!buildPromise2) {
|
|
40771
|
-
let currentPromise;
|
|
40772
|
-
currentPromise = (async () => {
|
|
40773
|
-
let succeeded = false;
|
|
40774
|
-
try {
|
|
40775
|
-
const diskIndex = loadCachedIndex2();
|
|
40776
|
-
const previousData = diskIndex ? preparePreviousIndexData2(diskIndex) : undefined;
|
|
40777
|
-
const buildResult = await buildIndex2(previousData);
|
|
40778
|
-
if (diskIndex && diskIndex.metadata.rootHash === buildResult.rootHash) {
|
|
40779
|
-
({ entries: cachedEntries2, paths: cachedEntryPaths2 } = buildCachedEntries2(buildResult.entries, buildResult.stats));
|
|
40780
|
-
succeeded = true;
|
|
40781
|
-
return;
|
|
40782
|
-
}
|
|
40783
|
-
if (buildResult.truncated) {
|
|
40784
|
-
debugLog("file-index", `Index truncated: workspace exceeds ${MAX_INDEX_DEPTH2} directory levels deep. ` + `Files beyond that depth will fall back to disk search.`);
|
|
40785
|
-
}
|
|
40786
|
-
cacheProjectIndex2(buildResult);
|
|
40787
|
-
({ entries: cachedEntries2, paths: cachedEntryPaths2 } = buildCachedEntries2(buildResult.entries, buildResult.stats));
|
|
40788
|
-
succeeded = true;
|
|
40789
|
-
} finally {
|
|
40790
|
-
if (buildPromise2 === currentPromise)
|
|
40791
|
-
buildPromise2 = null;
|
|
40792
|
-
if (succeeded)
|
|
40793
|
-
hasCompletedBuild2 = true;
|
|
40794
|
-
}
|
|
40795
|
-
})();
|
|
40796
|
-
buildPromise2 = currentPromise;
|
|
40797
|
-
}
|
|
40798
|
-
return buildPromise2;
|
|
40799
|
-
}
|
|
40800
|
-
function refreshFileIndex() {
|
|
40801
|
-
hasCompletedBuild2 = false;
|
|
40802
|
-
buildPromise2 = null;
|
|
40803
|
-
return ensureFileIndex2();
|
|
40804
|
-
}
|
|
40805
|
-
function addEntriesToCache(matches) {
|
|
40806
|
-
const available = MAX_CACHE_ENTRIES2 - cachedEntries2.length;
|
|
40807
|
-
if (available <= 0)
|
|
40808
|
-
return;
|
|
40809
|
-
let added = 0;
|
|
40810
|
-
for (const match of matches) {
|
|
40811
|
-
if (added >= available)
|
|
40812
|
-
break;
|
|
40813
|
-
if (!cachedEntryPaths2.has(match.path)) {
|
|
40814
|
-
cachedEntries2.push({
|
|
40815
|
-
path: match.path,
|
|
40816
|
-
type: match.type,
|
|
40817
|
-
lowerPath: match.path.toLowerCase(),
|
|
40818
|
-
parent: normalizeParent2(match.path)
|
|
40819
|
-
});
|
|
40820
|
-
cachedEntryPaths2.add(match.path);
|
|
40821
|
-
added++;
|
|
40822
|
-
}
|
|
40823
|
-
}
|
|
40824
|
-
}
|
|
40825
|
-
function searchFileIndex(options) {
|
|
40826
|
-
const { searchDir, pattern, deep, maxResults } = options;
|
|
40827
|
-
const normalizedDir = searchDir === "." ? "" : searchDir;
|
|
40828
|
-
const dirWithSep = normalizedDir === "" ? "" : `${normalizedDir}${sep2}`;
|
|
40829
|
-
const lowerPattern = pattern.toLowerCase();
|
|
40830
|
-
const results = [];
|
|
40831
|
-
for (const entry of cachedEntries2) {
|
|
40832
|
-
if (normalizedDir) {
|
|
40833
|
-
if (entry.path !== normalizedDir && !entry.path.startsWith(dirWithSep)) {
|
|
40834
|
-
continue;
|
|
40835
|
-
}
|
|
40836
|
-
}
|
|
40837
|
-
if (!deep && entry.parent !== normalizedDir) {
|
|
40838
|
-
continue;
|
|
40839
|
-
}
|
|
40840
|
-
if (lowerPattern && !entry.lowerPath.includes(lowerPattern)) {
|
|
40841
|
-
continue;
|
|
40842
|
-
}
|
|
40843
|
-
results.push({ path: entry.path, type: entry.type });
|
|
40844
|
-
if (results.length >= maxResults) {
|
|
40845
|
-
break;
|
|
40846
|
-
}
|
|
40847
|
-
}
|
|
40848
|
-
return results;
|
|
40849
|
-
}
|
|
40850
|
-
var MAX_INDEX_DEPTH2 = 12, PROJECT_INDEX_FILENAME2 = "file-index.json", MAX_CACHE_ENTRIES2, cachedEntries2, cachedEntryPaths2, buildPromise2 = null, hasCompletedBuild2 = false;
|
|
40851
|
-
var init_fileIndex = __esm(() => {
|
|
40852
|
-
init_debug();
|
|
40853
|
-
init_lettaSettings();
|
|
40854
|
-
init_fileSearchConfig();
|
|
40855
|
-
MAX_CACHE_ENTRIES2 = readIntSetting("MAX_ENTRIES", 50000);
|
|
40856
|
-
cachedEntries2 = [];
|
|
40857
|
-
cachedEntryPaths2 = new Set;
|
|
40858
|
-
});
|
|
40859
|
-
|
|
40860
40882
|
// src/permissions/session.ts
|
|
40861
40883
|
var exports_session = {};
|
|
40862
40884
|
__export(exports_session, {
|
|
@@ -43551,7 +43573,7 @@ If a directory has more than 1,000 entries, only the first 1,000 will be shown.`
|
|
|
43551
43573
|
var init_LS = () => {};
|
|
43552
43574
|
|
|
43553
43575
|
// src/tools/descriptions/Memory.md
|
|
43554
|
-
var Memory_default = '# Memory\nA convinience tool for memories stored in the memory directory (`$MEMORY_DIR`) that automatically commits and pushes changes. \n\nFiles stored inside of `system/` eventually become part of the agent\'s system prompt, so are always in the context window and do not need to be re-read. Other files only have metadata in the system prompt, so may need to be explicitly read to be updated. \n\nSupported operations on memory files: \n- `str_replace`\n- `insert`\n- `delete
|
|
43576
|
+
var Memory_default = '# Memory\nA convinience tool for memories stored in the memory directory (`$MEMORY_DIR`) that automatically commits and pushes changes. \n\nFiles stored inside of `system/` eventually become part of the agent\'s system prompt, so are always in the context window and do not need to be re-read. Other files only have metadata in the system prompt, so may need to be explicitly read to be updated. \n\nSupported operations on memory files: \n- `str_replace`\n- `insert`\n- `delete` (files, or directories recursively)\n- `rename` (path rename only)\n- `update_description`\n- `create`\nMore general operations can be performanced through directory modifying the files. \n\nPath formats accepted:\n- relative memory file paths (e.g. `system/contacts.md`, `reference/project/team.md`)\n- absolute paths only when they are inside `$MEMORY_DIR`\n\nNote: absolute paths outside `$MEMORY_DIR` are rejected.\n\nExamples:\n\n```python\n# Replace text in a memory file \nmemory(command="str_replace", reason="Update theme preference", path="system/human/preferences.md", old_string="theme: dark", new_string="theme: light")\n\n# Insert text at line 5\nmemory(command="insert", reason="Add note about meeting", path="reference/history/meeting-notes.md", insert_line=5, insert_text="New note here")\n\n# Delete a memory file \nmemory(command="delete", reason="Remove stale notes", path="reference/history/old_notes.md")\n\n# Rename a memory file \nmemory(command="rename", reason="Promote temp notes", old_path="reference/history/temp.md", new_path="reference/history/permanent.md")\n\n# Update a block description\nmemory(command="update_description", reason="Clarify coding prefs block", path="system/human/prefs/coding.md", description="Dr. Wooders\' coding preferences.")\n\n# Create a block with starting text\nmemory(command="create", reason="Track coding preferences", path="system/human/prefs/coding.md", description="The user\'s coding preferences.", file_text="The user seems to add type hints to all of their Python code.")\n\n# Create an empty block\nmemory(command="create", reason="Create coding preferences block", path="reference/history/coding_preferences.md", description="The user\'s coding preferences.")\n```\n';
|
|
43555
43577
|
var init_Memory = () => {};
|
|
43556
43578
|
|
|
43557
43579
|
// src/tools/descriptions/MultiEdit.md
|
|
@@ -47563,7 +47585,15 @@ var init_ListDirectoryGemini2 = __esm(() => {
|
|
|
47563
47585
|
// src/tools/impl/Memory.ts
|
|
47564
47586
|
import { execFile as execFileCb2 } from "node:child_process";
|
|
47565
47587
|
import { existsSync as existsSync13 } from "node:fs";
|
|
47566
|
-
import {
|
|
47588
|
+
import {
|
|
47589
|
+
mkdir as mkdir2,
|
|
47590
|
+
readFile as readFile3,
|
|
47591
|
+
rename,
|
|
47592
|
+
rm,
|
|
47593
|
+
stat as stat2,
|
|
47594
|
+
unlink,
|
|
47595
|
+
writeFile as writeFile2
|
|
47596
|
+
} from "node:fs/promises";
|
|
47567
47597
|
import { homedir as homedir15 } from "node:os";
|
|
47568
47598
|
import { dirname as dirname5, isAbsolute as isAbsolute8, relative as relative5, resolve as resolve12 } from "node:path";
|
|
47569
47599
|
import { promisify as promisify9 } from "node:util";
|
|
@@ -47604,20 +47634,16 @@ async function memory(args) {
|
|
|
47604
47634
|
if (command === "create") {
|
|
47605
47635
|
const pathArg = requireString(args.path, "path", "create");
|
|
47606
47636
|
const description = requireString(args.description, "description", "create");
|
|
47607
|
-
const label = normalizeMemoryLabel(pathArg, "path");
|
|
47637
|
+
const label = normalizeMemoryLabel(memoryDir, pathArg, "path");
|
|
47608
47638
|
const filePath = resolveMemoryFilePath(memoryDir, label);
|
|
47609
47639
|
const relPath = toRepoRelative(memoryDir, filePath);
|
|
47610
47640
|
if (existsSync13(filePath)) {
|
|
47611
47641
|
throw new Error(`memory create: block already exists at ${pathArg}`);
|
|
47612
47642
|
}
|
|
47613
|
-
const limit2 = args.limit ?? DEFAULT_LIMIT3;
|
|
47614
|
-
if (!Number.isInteger(limit2) || limit2 <= 0) {
|
|
47615
|
-
throw new Error("memory create: 'limit' must be a positive integer");
|
|
47616
|
-
}
|
|
47617
47643
|
const body = args.file_text ?? "";
|
|
47618
47644
|
const rendered = renderMemoryFile({
|
|
47619
47645
|
description,
|
|
47620
|
-
limit:
|
|
47646
|
+
limit: DEFAULT_LIMIT3
|
|
47621
47647
|
}, body);
|
|
47622
47648
|
await mkdir2(dirname5(filePath), { recursive: true });
|
|
47623
47649
|
await writeFile2(filePath, rendered, "utf8");
|
|
@@ -47626,7 +47652,7 @@ async function memory(args) {
|
|
|
47626
47652
|
const pathArg = requireString(args.path, "path", "str_replace");
|
|
47627
47653
|
const oldString = requireString(args.old_string, "old_string", "str_replace");
|
|
47628
47654
|
const newString = requireString(args.new_string, "new_string", "str_replace");
|
|
47629
|
-
const label = normalizeMemoryLabel(pathArg, "path");
|
|
47655
|
+
const label = normalizeMemoryLabel(memoryDir, pathArg, "path");
|
|
47630
47656
|
const filePath = resolveMemoryFilePath(memoryDir, label);
|
|
47631
47657
|
const relPath = toRepoRelative(memoryDir, filePath);
|
|
47632
47658
|
const file = await loadEditableMemoryFile(filePath, pathArg);
|
|
@@ -47644,7 +47670,7 @@ async function memory(args) {
|
|
|
47644
47670
|
if (typeof args.insert_line !== "number" || Number.isNaN(args.insert_line)) {
|
|
47645
47671
|
throw new Error("memory insert: 'insert_line' must be a number");
|
|
47646
47672
|
}
|
|
47647
|
-
const label = normalizeMemoryLabel(pathArg, "path");
|
|
47673
|
+
const label = normalizeMemoryLabel(memoryDir, pathArg, "path");
|
|
47648
47674
|
const filePath = resolveMemoryFilePath(memoryDir, label);
|
|
47649
47675
|
const relPath = toRepoRelative(memoryDir, filePath);
|
|
47650
47676
|
const file = await loadEditableMemoryFile(filePath, pathArg);
|
|
@@ -47662,44 +47688,48 @@ async function memory(args) {
|
|
|
47662
47688
|
affectedPaths = [relPath];
|
|
47663
47689
|
} else if (command === "delete") {
|
|
47664
47690
|
const pathArg = requireString(args.path, "path", "delete");
|
|
47665
|
-
const label = normalizeMemoryLabel(pathArg, "path");
|
|
47666
|
-
const
|
|
47667
|
-
|
|
47668
|
-
|
|
47669
|
-
|
|
47670
|
-
|
|
47671
|
-
|
|
47672
|
-
const hasDescriptionUpdate = typeof args.path === "string" && args.path.trim().length > 0 && typeof args.description === "string" && args.description.trim().length > 0 && !args.old_path && !args.new_path;
|
|
47673
|
-
if (hasDescriptionUpdate) {
|
|
47674
|
-
const pathArg = requireString(args.path, "path", "rename");
|
|
47675
|
-
const newDescription = requireString(args.description, "description", "rename description update");
|
|
47676
|
-
const label = normalizeMemoryLabel(pathArg, "path");
|
|
47691
|
+
const label = normalizeMemoryLabel(memoryDir, pathArg, "path");
|
|
47692
|
+
const targetPath = resolveMemoryPath(memoryDir, label);
|
|
47693
|
+
if (existsSync13(targetPath) && (await stat2(targetPath)).isDirectory()) {
|
|
47694
|
+
const relPath = toRepoRelative(memoryDir, targetPath);
|
|
47695
|
+
await rm(targetPath, { recursive: true, force: false });
|
|
47696
|
+
affectedPaths = [relPath];
|
|
47697
|
+
} else {
|
|
47677
47698
|
const filePath = resolveMemoryFilePath(memoryDir, label);
|
|
47678
47699
|
const relPath = toRepoRelative(memoryDir, filePath);
|
|
47679
|
-
|
|
47680
|
-
|
|
47681
|
-
...file.frontmatter,
|
|
47682
|
-
description: newDescription
|
|
47683
|
-
}, file.body);
|
|
47684
|
-
await writeFile2(filePath, rendered, "utf8");
|
|
47700
|
+
await loadEditableMemoryFile(filePath, pathArg);
|
|
47701
|
+
await unlink(filePath);
|
|
47685
47702
|
affectedPaths = [relPath];
|
|
47686
|
-
} else {
|
|
47687
|
-
const oldPathArg = requireString(args.old_path, "old_path", "rename");
|
|
47688
|
-
const newPathArg = requireString(args.new_path, "new_path", "rename");
|
|
47689
|
-
const oldLabel = normalizeMemoryLabel(oldPathArg, "old_path");
|
|
47690
|
-
const newLabel = normalizeMemoryLabel(newPathArg, "new_path");
|
|
47691
|
-
const oldFilePath = resolveMemoryFilePath(memoryDir, oldLabel);
|
|
47692
|
-
const newFilePath = resolveMemoryFilePath(memoryDir, newLabel);
|
|
47693
|
-
const oldRelPath = toRepoRelative(memoryDir, oldFilePath);
|
|
47694
|
-
const newRelPath = toRepoRelative(memoryDir, newFilePath);
|
|
47695
|
-
if (existsSync13(newFilePath)) {
|
|
47696
|
-
throw new Error(`memory rename: destination already exists at ${newPathArg}`);
|
|
47697
|
-
}
|
|
47698
|
-
await loadEditableMemoryFile(oldFilePath, oldPathArg);
|
|
47699
|
-
await mkdir2(dirname5(newFilePath), { recursive: true });
|
|
47700
|
-
await rename(oldFilePath, newFilePath);
|
|
47701
|
-
affectedPaths = [oldRelPath, newRelPath];
|
|
47702
47703
|
}
|
|
47704
|
+
} else if (command === "rename") {
|
|
47705
|
+
const oldPathArg = requireString(args.old_path, "old_path", "rename");
|
|
47706
|
+
const newPathArg = requireString(args.new_path, "new_path", "rename");
|
|
47707
|
+
const oldLabel = normalizeMemoryLabel(memoryDir, oldPathArg, "old_path");
|
|
47708
|
+
const newLabel = normalizeMemoryLabel(memoryDir, newPathArg, "new_path");
|
|
47709
|
+
const oldFilePath = resolveMemoryFilePath(memoryDir, oldLabel);
|
|
47710
|
+
const newFilePath = resolveMemoryFilePath(memoryDir, newLabel);
|
|
47711
|
+
const oldRelPath = toRepoRelative(memoryDir, oldFilePath);
|
|
47712
|
+
const newRelPath = toRepoRelative(memoryDir, newFilePath);
|
|
47713
|
+
if (existsSync13(newFilePath)) {
|
|
47714
|
+
throw new Error(`memory rename: destination already exists at ${newPathArg}`);
|
|
47715
|
+
}
|
|
47716
|
+
await loadEditableMemoryFile(oldFilePath, oldPathArg);
|
|
47717
|
+
await mkdir2(dirname5(newFilePath), { recursive: true });
|
|
47718
|
+
await rename(oldFilePath, newFilePath);
|
|
47719
|
+
affectedPaths = [oldRelPath, newRelPath];
|
|
47720
|
+
} else if (command === "update_description") {
|
|
47721
|
+
const pathArg = requireString(args.path, "path", "update_description");
|
|
47722
|
+
const newDescription = requireString(args.description, "description", "update_description");
|
|
47723
|
+
const label = normalizeMemoryLabel(memoryDir, pathArg, "path");
|
|
47724
|
+
const filePath = resolveMemoryFilePath(memoryDir, label);
|
|
47725
|
+
const relPath = toRepoRelative(memoryDir, filePath);
|
|
47726
|
+
const file = await loadEditableMemoryFile(filePath, pathArg);
|
|
47727
|
+
const rendered = renderMemoryFile({
|
|
47728
|
+
...file.frontmatter,
|
|
47729
|
+
description: newDescription
|
|
47730
|
+
}, file.body);
|
|
47731
|
+
await writeFile2(filePath, rendered, "utf8");
|
|
47732
|
+
affectedPaths = [relPath];
|
|
47703
47733
|
} else {
|
|
47704
47734
|
throw new Error(`Unsupported memory command: ${command}`);
|
|
47705
47735
|
}
|
|
@@ -47743,18 +47773,31 @@ function ensureMemoryRepo(memoryDir) {
|
|
|
47743
47773
|
throw new Error(`memory: ${memoryDir} is not a git repository. This tool requires a git-backed memory filesystem.`);
|
|
47744
47774
|
}
|
|
47745
47775
|
}
|
|
47746
|
-
function normalizeMemoryLabel(inputPath, fieldName) {
|
|
47776
|
+
function normalizeMemoryLabel(memoryDir, inputPath, fieldName) {
|
|
47747
47777
|
const raw = inputPath.trim();
|
|
47748
47778
|
if (!raw) {
|
|
47749
47779
|
throw new Error(`memory: '${fieldName}' must be a non-empty string`);
|
|
47750
47780
|
}
|
|
47751
|
-
|
|
47752
|
-
if (/^[a-zA-Z]:\//.test(normalized)) {
|
|
47753
|
-
throw new Error(`memory: '${fieldName}' must be a memory-relative file path, not an absolute host path`);
|
|
47754
|
-
}
|
|
47755
|
-
if (normalized.startsWith("~/") || normalized.startsWith("$HOME/")) {
|
|
47781
|
+
if (raw.startsWith("~/") || raw.startsWith("$HOME/")) {
|
|
47756
47782
|
throw new Error(`memory: '${fieldName}' must be a memory-relative file path, not a home-relative filesystem path`);
|
|
47757
47783
|
}
|
|
47784
|
+
const isWindowsAbsolute = /^[a-zA-Z]:[\\/]/.test(raw);
|
|
47785
|
+
if (isAbsolute8(raw) || isWindowsAbsolute) {
|
|
47786
|
+
const absolutePath = resolve12(raw);
|
|
47787
|
+
const relToMemory = relative5(memoryDir, absolutePath);
|
|
47788
|
+
if (relToMemory && !relToMemory.startsWith("..") && !isAbsolute8(relToMemory)) {
|
|
47789
|
+
return normalizeRelativeMemoryLabel(relToMemory, fieldName);
|
|
47790
|
+
}
|
|
47791
|
+
throw new Error(memoryPrefixError(memoryDir));
|
|
47792
|
+
}
|
|
47793
|
+
return normalizeRelativeMemoryLabel(raw, fieldName);
|
|
47794
|
+
}
|
|
47795
|
+
function normalizeRelativeMemoryLabel(inputPath, fieldName) {
|
|
47796
|
+
const raw = inputPath.trim();
|
|
47797
|
+
if (!raw) {
|
|
47798
|
+
throw new Error(`memory: '${fieldName}' must be a non-empty string`);
|
|
47799
|
+
}
|
|
47800
|
+
const normalized = raw.replace(/\\/g, "/");
|
|
47758
47801
|
if (normalized.startsWith("/")) {
|
|
47759
47802
|
throw new Error(`memory: '${fieldName}' must be a relative path like system/contacts.md`);
|
|
47760
47803
|
}
|
|
@@ -47778,8 +47821,15 @@ function normalizeMemoryLabel(inputPath, fieldName) {
|
|
|
47778
47821
|
}
|
|
47779
47822
|
return segments.join("/");
|
|
47780
47823
|
}
|
|
47824
|
+
function memoryPrefixError(memoryDir) {
|
|
47825
|
+
return `The memory tool can only be used to modify files in {${memoryDir}} or provided as a relative path`;
|
|
47826
|
+
}
|
|
47781
47827
|
function resolveMemoryFilePath(memoryDir, label) {
|
|
47782
|
-
const absolute =
|
|
47828
|
+
const absolute = resolveMemoryPath(memoryDir, `${label}.md`);
|
|
47829
|
+
return absolute;
|
|
47830
|
+
}
|
|
47831
|
+
function resolveMemoryPath(memoryDir, path11) {
|
|
47832
|
+
const absolute = resolve12(memoryDir, path11);
|
|
47783
47833
|
const rel = relative5(memoryDir, absolute);
|
|
47784
47834
|
if (rel.startsWith("..") || isAbsolute8(rel)) {
|
|
47785
47835
|
throw new Error("memory: resolved path escapes memory directory");
|
|
@@ -61473,7 +61523,7 @@ __export(exports_skills, {
|
|
|
61473
61523
|
GLOBAL_SKILLS_DIR: () => GLOBAL_SKILLS_DIR
|
|
61474
61524
|
});
|
|
61475
61525
|
import { existsSync as existsSync15 } from "node:fs";
|
|
61476
|
-
import { readdir as readdir4, readFile as readFile4, realpath as realpath2, stat as
|
|
61526
|
+
import { readdir as readdir4, readFile as readFile4, realpath as realpath2, stat as stat3 } from "node:fs/promises";
|
|
61477
61527
|
import { dirname as dirname6, join as join18 } from "node:path";
|
|
61478
61528
|
import { fileURLToPath as fileURLToPath7 } from "node:url";
|
|
61479
61529
|
function getBundledSkillsPath() {
|
|
@@ -61570,7 +61620,7 @@ async function findSkillFiles(currentPath, rootPath, skills, errors, source, vis
|
|
|
61570
61620
|
let isDirectory = entry.isDirectory();
|
|
61571
61621
|
let isFile = entry.isFile();
|
|
61572
61622
|
if (entry.isSymbolicLink()) {
|
|
61573
|
-
const entryStat = await
|
|
61623
|
+
const entryStat = await stat3(fullPath);
|
|
61574
61624
|
isDirectory = entryStat.isDirectory();
|
|
61575
61625
|
isFile = entryStat.isFile();
|
|
61576
61626
|
}
|
|
@@ -63692,7 +63742,14 @@ var init_Memory3 = __esm(() => {
|
|
|
63692
63742
|
properties: {
|
|
63693
63743
|
command: {
|
|
63694
63744
|
type: "string",
|
|
63695
|
-
enum: [
|
|
63745
|
+
enum: [
|
|
63746
|
+
"str_replace",
|
|
63747
|
+
"insert",
|
|
63748
|
+
"delete",
|
|
63749
|
+
"rename",
|
|
63750
|
+
"update_description",
|
|
63751
|
+
"create"
|
|
63752
|
+
],
|
|
63696
63753
|
description: "Memory operation to perform"
|
|
63697
63754
|
},
|
|
63698
63755
|
reason: {
|
|
@@ -63701,15 +63758,15 @@ var init_Memory3 = __esm(() => {
|
|
|
63701
63758
|
},
|
|
63702
63759
|
path: {
|
|
63703
63760
|
type: "string",
|
|
63704
|
-
description: "Target memory file
|
|
63761
|
+
description: "Target memory path (file or directory). Accepts relative paths like system/contacts.md or absolute paths under MEMORY_DIR"
|
|
63705
63762
|
},
|
|
63706
63763
|
old_path: {
|
|
63707
63764
|
type: "string",
|
|
63708
|
-
description: "Source memory file path for rename operations (
|
|
63765
|
+
description: "Source memory file path for rename operations (relative path or absolute path under MEMORY_DIR)"
|
|
63709
63766
|
},
|
|
63710
63767
|
new_path: {
|
|
63711
63768
|
type: "string",
|
|
63712
|
-
description: "Destination memory file path for rename operations (
|
|
63769
|
+
description: "Destination memory file path for rename operations (relative path or absolute path under MEMORY_DIR)"
|
|
63713
63770
|
},
|
|
63714
63771
|
old_string: {
|
|
63715
63772
|
type: "string",
|
|
@@ -63729,15 +63786,11 @@ var init_Memory3 = __esm(() => {
|
|
|
63729
63786
|
},
|
|
63730
63787
|
description: {
|
|
63731
63788
|
type: "string",
|
|
63732
|
-
description: "Block description (required for create
|
|
63789
|
+
description: "Block description (required for create and update_description)"
|
|
63733
63790
|
},
|
|
63734
63791
|
file_text: {
|
|
63735
63792
|
type: "string",
|
|
63736
63793
|
description: "Initial block content for create"
|
|
63737
|
-
},
|
|
63738
|
-
limit: {
|
|
63739
|
-
type: "number",
|
|
63740
|
-
description: "Optional positive integer limit for create"
|
|
63741
63794
|
}
|
|
63742
63795
|
},
|
|
63743
63796
|
required: ["command", "reason"],
|
|
@@ -70033,11 +70086,17 @@ function isTerminalKillCommand(value) {
|
|
|
70033
70086
|
const c = value;
|
|
70034
70087
|
return c.type === "terminal_kill" && typeof c.terminal_id === "string";
|
|
70035
70088
|
}
|
|
70089
|
+
function isSearchFilesCommand(value) {
|
|
70090
|
+
if (!value || typeof value !== "object")
|
|
70091
|
+
return false;
|
|
70092
|
+
const c = value;
|
|
70093
|
+
return c.type === "search_files" && typeof c.query === "string" && typeof c.request_id === "string";
|
|
70094
|
+
}
|
|
70036
70095
|
function parseServerMessage(data) {
|
|
70037
70096
|
try {
|
|
70038
70097
|
const raw = typeof data === "string" ? data : data.toString();
|
|
70039
70098
|
const parsed = JSON.parse(raw);
|
|
70040
|
-
if (isInputCommand(parsed) || isChangeDeviceStateCommand(parsed) || isAbortMessageCommand(parsed) || isSyncCommand(parsed) || isTerminalSpawnCommand(parsed) || isTerminalInputCommand(parsed) || isTerminalResizeCommand(parsed) || isTerminalKillCommand(parsed)) {
|
|
70099
|
+
if (isInputCommand(parsed) || isChangeDeviceStateCommand(parsed) || isAbortMessageCommand(parsed) || isSyncCommand(parsed) || isTerminalSpawnCommand(parsed) || isTerminalInputCommand(parsed) || isTerminalResizeCommand(parsed) || isTerminalKillCommand(parsed) || isSearchFilesCommand(parsed)) {
|
|
70041
70100
|
return parsed;
|
|
70042
70101
|
}
|
|
70043
70102
|
const invalidInput = getInvalidInputReason(parsed);
|
|
@@ -76705,6 +76764,8 @@ async function handleIncomingMessage(msg, socket, runtime, onStatusChange, conne
|
|
|
76705
76764
|
});
|
|
76706
76765
|
return;
|
|
76707
76766
|
}
|
|
76767
|
+
setCurrentAgentId(agentId);
|
|
76768
|
+
setConversationId2(conversationId);
|
|
76708
76769
|
if (isDebugEnabled()) {
|
|
76709
76770
|
console.log(`[Listen] Handling message: agentId=${agentId}, requestedConversationId=${requestedConversationId}, conversationId=${conversationId}`);
|
|
76710
76771
|
}
|
|
@@ -77134,6 +77195,7 @@ async function handleIncomingMessage(msg, socket, runtime, onStatusChange, conne
|
|
|
77134
77195
|
}
|
|
77135
77196
|
var init_turn = __esm(async () => {
|
|
77136
77197
|
init_check_approval();
|
|
77198
|
+
init_context();
|
|
77137
77199
|
init_turn_recovery_policy();
|
|
77138
77200
|
init_errorFormatter();
|
|
77139
77201
|
init_listenContext();
|
|
@@ -77159,7 +77221,7 @@ var init_turn = __esm(async () => {
|
|
|
77159
77221
|
});
|
|
77160
77222
|
|
|
77161
77223
|
// src/websocket/listener/client.ts
|
|
77162
|
-
import { realpath as realpath3, stat as
|
|
77224
|
+
import { realpath as realpath3, stat as stat4 } from "node:fs/promises";
|
|
77163
77225
|
import path22 from "node:path";
|
|
77164
77226
|
import WebSocket4 from "ws";
|
|
77165
77227
|
function handleModeChange(msg, socket, runtime, scope) {
|
|
@@ -77323,7 +77385,7 @@ async function handleCwdChange(msg, socket, runtime) {
|
|
|
77323
77385
|
}
|
|
77324
77386
|
const resolvedPath = path22.isAbsolute(requestedPath) ? requestedPath : path22.resolve(currentWorkingDirectory, requestedPath);
|
|
77325
77387
|
const normalizedPath = await realpath3(resolvedPath);
|
|
77326
|
-
const stats = await
|
|
77388
|
+
const stats = await stat4(normalizedPath);
|
|
77327
77389
|
if (!stats.isDirectory()) {
|
|
77328
77390
|
throw new Error(`Not a directory: ${normalizedPath}`);
|
|
77329
77391
|
}
|
|
@@ -77668,6 +77730,24 @@ async function connectWithRetry(runtime, opts, attempt = 0, startTime = Date.now
|
|
|
77668
77730
|
scheduleQueuePump(scopedRuntime, socket, opts, processQueuedTurn);
|
|
77669
77731
|
return;
|
|
77670
77732
|
}
|
|
77733
|
+
if (isSearchFilesCommand(parsed)) {
|
|
77734
|
+
(async () => {
|
|
77735
|
+
await ensureFileIndex2();
|
|
77736
|
+
const files = searchFileIndex({
|
|
77737
|
+
searchDir: ".",
|
|
77738
|
+
pattern: parsed.query,
|
|
77739
|
+
deep: true,
|
|
77740
|
+
maxResults: parsed.max_results ?? 5
|
|
77741
|
+
});
|
|
77742
|
+
socket.send(JSON.stringify({
|
|
77743
|
+
type: "search_files_response",
|
|
77744
|
+
request_id: parsed.request_id,
|
|
77745
|
+
files,
|
|
77746
|
+
success: true
|
|
77747
|
+
}));
|
|
77748
|
+
})();
|
|
77749
|
+
return;
|
|
77750
|
+
}
|
|
77671
77751
|
if (parsed.type === "terminal_spawn") {
|
|
77672
77752
|
handleTerminalSpawn(parsed, socket, runtime.bootWorkingDirectory);
|
|
77673
77753
|
return;
|
|
@@ -77901,6 +77981,7 @@ function createLegacyTestRuntime() {
|
|
|
77901
77981
|
}
|
|
77902
77982
|
var __listenClientTestUtils;
|
|
77903
77983
|
var init_client4 = __esm(async () => {
|
|
77984
|
+
init_fileIndex();
|
|
77904
77985
|
init_planName();
|
|
77905
77986
|
init_constants();
|
|
77906
77987
|
init_queueRuntime();
|
|
@@ -78015,7 +78096,7 @@ __export(exports_skills2, {
|
|
|
78015
78096
|
GLOBAL_SKILLS_DIR: () => GLOBAL_SKILLS_DIR2
|
|
78016
78097
|
});
|
|
78017
78098
|
import { existsSync as existsSync20 } from "node:fs";
|
|
78018
|
-
import { readdir as readdir6, readFile as readFile6, realpath as realpath4, stat as
|
|
78099
|
+
import { readdir as readdir6, readFile as readFile6, realpath as realpath4, stat as stat5 } from "node:fs/promises";
|
|
78019
78100
|
import { dirname as dirname10, join as join27 } from "node:path";
|
|
78020
78101
|
import { fileURLToPath as fileURLToPath8 } from "node:url";
|
|
78021
78102
|
function getBundledSkillsPath2() {
|
|
@@ -78112,7 +78193,7 @@ async function findSkillFiles2(currentPath, rootPath, skills, errors, source, vi
|
|
|
78112
78193
|
let isDirectory = entry.isDirectory();
|
|
78113
78194
|
let isFile = entry.isFile();
|
|
78114
78195
|
if (entry.isSymbolicLink()) {
|
|
78115
|
-
const entryStat = await
|
|
78196
|
+
const entryStat = await stat5(fullPath);
|
|
78116
78197
|
isDirectory = entryStat.isDirectory();
|
|
78117
78198
|
isFile = entryStat.isFile();
|
|
78118
78199
|
}
|
|
@@ -78549,7 +78630,7 @@ __export(exports_auto_update, {
|
|
|
78549
78630
|
});
|
|
78550
78631
|
import { execFile as execFile10 } from "node:child_process";
|
|
78551
78632
|
import { realpathSync as realpathSync2 } from "node:fs";
|
|
78552
|
-
import { readdir as readdir7, rm } from "node:fs/promises";
|
|
78633
|
+
import { readdir as readdir7, rm as rm2 } from "node:fs/promises";
|
|
78553
78634
|
import { join as join28 } from "node:path";
|
|
78554
78635
|
import { promisify as promisify10 } from "node:util";
|
|
78555
78636
|
function debugLog3(...args) {
|
|
@@ -78717,7 +78798,7 @@ async function cleanupOrphanedDirs(globalPath) {
|
|
|
78717
78798
|
if (entry.startsWith(".letta-code-")) {
|
|
78718
78799
|
const orphanPath = join28(lettaAiDir, entry);
|
|
78719
78800
|
debugLog3("Cleaning orphaned temp directory:", orphanPath);
|
|
78720
|
-
await
|
|
78801
|
+
await rm2(orphanPath, { recursive: true, force: true });
|
|
78721
78802
|
}
|
|
78722
78803
|
}
|
|
78723
78804
|
} catch {}
|
|
@@ -80637,7 +80718,6 @@ async function handleHeadlessCommand(parsedArgs, model, skillsDirectoryOverride,
|
|
|
80637
80718
|
if (values.resume) {
|
|
80638
80719
|
console.error(`Error: --resume is for interactive mode only (opens conversation selector).
|
|
80639
80720
|
In headless mode, use:
|
|
80640
|
-
--continue Resume the last session (agent + conversation)
|
|
80641
80721
|
--conversation <id> Resume a specific conversation by ID`);
|
|
80642
80722
|
process.exit(1);
|
|
80643
80723
|
}
|
|
@@ -80647,7 +80727,6 @@ In headless mode, use:
|
|
|
80647
80727
|
let specifiedAgentId = values.agent;
|
|
80648
80728
|
const specifiedAgentName = values.name;
|
|
80649
80729
|
let specifiedConversationId = values.conversation;
|
|
80650
|
-
const shouldContinue = values.continue;
|
|
80651
80730
|
const forceNew = values["new-agent"];
|
|
80652
80731
|
const systemPromptPreset = values.system;
|
|
80653
80732
|
const systemCustom = values["system-custom"];
|
|
@@ -80740,10 +80819,6 @@ In headless mode, use:
|
|
|
80740
80819
|
console.error("Error: --from-agent requires --agent <id> or --conversation <id>.");
|
|
80741
80820
|
process.exit(1);
|
|
80742
80821
|
}
|
|
80743
|
-
if (shouldContinue) {
|
|
80744
|
-
console.error("Error: --from-agent cannot be used with --continue");
|
|
80745
|
-
process.exit(1);
|
|
80746
|
-
}
|
|
80747
80822
|
if (forceNew) {
|
|
80748
80823
|
console.error("Error: --from-agent cannot be used with --new-agent");
|
|
80749
80824
|
process.exit(1);
|
|
@@ -80771,20 +80846,12 @@ In headless mode, use:
|
|
|
80771
80846
|
{
|
|
80772
80847
|
when: fromAfFile,
|
|
80773
80848
|
message: "--conversation cannot be used with --import"
|
|
80774
|
-
},
|
|
80775
|
-
{
|
|
80776
|
-
when: shouldContinue,
|
|
80777
|
-
message: "--conversation cannot be used with --continue"
|
|
80778
80849
|
}
|
|
80779
80850
|
]
|
|
80780
80851
|
});
|
|
80781
80852
|
validateFlagConflicts2({
|
|
80782
80853
|
guard: forceNewConversation,
|
|
80783
80854
|
checks: [
|
|
80784
|
-
{
|
|
80785
|
-
when: shouldContinue,
|
|
80786
|
-
message: "--new cannot be used with --continue"
|
|
80787
|
-
},
|
|
80788
80855
|
{
|
|
80789
80856
|
when: specifiedConversationId,
|
|
80790
80857
|
message: "--new cannot be used with --conversation"
|
|
@@ -80809,10 +80876,6 @@ In headless mode, use:
|
|
|
80809
80876
|
when: specifiedAgentName,
|
|
80810
80877
|
message: "--import cannot be used with --name"
|
|
80811
80878
|
},
|
|
80812
|
-
{
|
|
80813
|
-
when: shouldContinue,
|
|
80814
|
-
message: "--import cannot be used with --continue"
|
|
80815
|
-
},
|
|
80816
80879
|
{
|
|
80817
80880
|
when: forceNew,
|
|
80818
80881
|
message: "--import cannot be used with --new-agent"
|
|
@@ -80987,11 +81050,6 @@ In headless mode, use:
|
|
|
80987
81050
|
} catch (_error) {}
|
|
80988
81051
|
}
|
|
80989
81052
|
}
|
|
80990
|
-
if (!agent && shouldContinue) {
|
|
80991
|
-
console.error("No recent session found in .letta/ or ~/.letta.");
|
|
80992
|
-
console.error("Run 'letta' to get started.");
|
|
80993
|
-
process.exit(1);
|
|
80994
|
-
}
|
|
80995
81053
|
if (!agent) {
|
|
80996
81054
|
const { ensureDefaultAgents: ensureDefaultAgents2 } = await init_defaults().then(() => exports_defaults);
|
|
80997
81055
|
const defaultAgent = await ensureDefaultAgents2(client, {
|
|
@@ -81006,7 +81064,7 @@ In headless mode, use:
|
|
|
81006
81064
|
process.exit(1);
|
|
81007
81065
|
}
|
|
81008
81066
|
markMilestone("HEADLESS_AGENT_RESOLVED");
|
|
81009
|
-
const isResumingAgent = !!(specifiedAgentId ||
|
|
81067
|
+
const isResumingAgent = !!(specifiedAgentId || !forceNew && !fromAfFile);
|
|
81010
81068
|
if (isResumingAgent) {
|
|
81011
81069
|
if (model) {
|
|
81012
81070
|
const modelHandle = resolveModel2(model);
|
|
@@ -81132,28 +81190,6 @@ In headless mode, use:
|
|
|
81132
81190
|
process.exit(1);
|
|
81133
81191
|
}
|
|
81134
81192
|
}
|
|
81135
|
-
} else if (shouldContinue) {
|
|
81136
|
-
await settingsManager.loadLocalProjectSettings();
|
|
81137
|
-
const lastSession = settingsManager.getLocalLastSession(process.cwd()) ?? settingsManager.getGlobalLastSession();
|
|
81138
|
-
if (lastSession && lastSession.agentId === agent.id) {
|
|
81139
|
-
if (lastSession.conversationId === "default") {
|
|
81140
|
-
conversationId = "default";
|
|
81141
|
-
} else {
|
|
81142
|
-
try {
|
|
81143
|
-
debugLog("conversations", `retrieve(${lastSession.conversationId}) [headless lastSession resume]`);
|
|
81144
|
-
await client.conversations.retrieve(lastSession.conversationId);
|
|
81145
|
-
conversationId = lastSession.conversationId;
|
|
81146
|
-
} catch {
|
|
81147
|
-
console.error(`Attempting to resume conversation ${lastSession.conversationId}, but conversation was not found.`);
|
|
81148
|
-
console.error("Resume the default conversation with 'letta -p ...', view recent conversations with 'letta --resume', or start a new conversation with 'letta -p ... --new'.");
|
|
81149
|
-
process.exit(1);
|
|
81150
|
-
}
|
|
81151
|
-
}
|
|
81152
|
-
} else {
|
|
81153
|
-
console.error("No previous session found for this agent to resume.");
|
|
81154
|
-
console.error("Resume the default conversation with 'letta -p ...', or start a new conversation with 'letta -p ... --new'.");
|
|
81155
|
-
process.exit(1);
|
|
81156
|
-
}
|
|
81157
81193
|
} else if (forceNewConversation) {
|
|
81158
81194
|
const conversation = await client.conversations.create({
|
|
81159
81195
|
agent_id: agent.id,
|
|
@@ -103794,20 +103830,6 @@ function ConversationSelector2({
|
|
|
103794
103830
|
children: "⎿ "
|
|
103795
103831
|
}, undefined, false, undefined, this);
|
|
103796
103832
|
const indent = " ";
|
|
103797
|
-
if (conv.summary) {
|
|
103798
|
-
return /* @__PURE__ */ jsx_dev_runtime34.jsxDEV(Box_default, {
|
|
103799
|
-
flexDirection: "row",
|
|
103800
|
-
marginLeft: 2,
|
|
103801
|
-
children: [
|
|
103802
|
-
bracket,
|
|
103803
|
-
/* @__PURE__ */ jsx_dev_runtime34.jsxDEV(Text2, {
|
|
103804
|
-
dimColor: true,
|
|
103805
|
-
italic: true,
|
|
103806
|
-
children: conv.summary.length > 57 ? `${conv.summary.slice(0, 54)}...` : conv.summary
|
|
103807
|
-
}, undefined, false, undefined, this)
|
|
103808
|
-
]
|
|
103809
|
-
}, undefined, true, undefined, this);
|
|
103810
|
-
}
|
|
103811
103833
|
if (previewLines.length > 0) {
|
|
103812
103834
|
return /* @__PURE__ */ jsx_dev_runtime34.jsxDEV(jsx_dev_runtime34.Fragment, {
|
|
103813
103835
|
children: previewLines.map((line, idx) => /* @__PURE__ */ jsx_dev_runtime34.jsxDEV(Box_default, {
|
|
@@ -103880,9 +103902,9 @@ function ConversationSelector2({
|
|
|
103880
103902
|
/* @__PURE__ */ jsx_dev_runtime34.jsxDEV(Text2, {
|
|
103881
103903
|
bold: isSelected,
|
|
103882
103904
|
color: isSelected ? colors.selector.itemHighlighted : undefined,
|
|
103883
|
-
children: isDefault ? "default" : conv.id
|
|
103905
|
+
children: conv.summary ? `${conv.summary.length > 40 ? `${conv.summary.slice(0, 37)}...` : conv.summary} (${conv.id})` : isDefault ? "default" : conv.id
|
|
103884
103906
|
}, undefined, false, undefined, this),
|
|
103885
|
-
isDefault && /* @__PURE__ */ jsx_dev_runtime34.jsxDEV(Text2, {
|
|
103907
|
+
!conv.summary && isDefault && /* @__PURE__ */ jsx_dev_runtime34.jsxDEV(Text2, {
|
|
103886
103908
|
dimColor: true,
|
|
103887
103909
|
children: " (agent's default conversation)"
|
|
103888
103910
|
}, undefined, false, undefined, this),
|
|
@@ -116536,7 +116558,7 @@ function MessageSearch({
|
|
|
116536
116558
|
const [searchInput, setSearchInput] = import_react79.useState(initialQuery ?? "");
|
|
116537
116559
|
const [activeQuery, setActiveQuery] = import_react79.useState(initialQuery ?? "");
|
|
116538
116560
|
const [searchMode, setSearchMode] = import_react79.useState("hybrid");
|
|
116539
|
-
const [searchRange, setSearchRange] = import_react79.useState("
|
|
116561
|
+
const [searchRange, setSearchRange] = import_react79.useState("agent");
|
|
116540
116562
|
const [results, setResults] = import_react79.useState([]);
|
|
116541
116563
|
const [loading, setLoading] = import_react79.useState(false);
|
|
116542
116564
|
const [error, setError] = import_react79.useState(null);
|
|
@@ -130079,8 +130101,10 @@ Type your task to begin the loop.`, true);
|
|
|
130079
130101
|
}
|
|
130080
130102
|
return { submitted: true };
|
|
130081
130103
|
}
|
|
130082
|
-
|
|
130083
|
-
|
|
130104
|
+
const newMatch = msg.trim().match(/^\/new(?:\s+(.+))?$/);
|
|
130105
|
+
if (newMatch) {
|
|
130106
|
+
const conversationName = newMatch[1]?.trim();
|
|
130107
|
+
const cmd = commandRunner.start(msg.trim(), conversationName ? `Starting new conversation: ${conversationName}...` : "Starting new conversation...");
|
|
130084
130108
|
resetPendingReasoningCycle();
|
|
130085
130109
|
setCommandRunning(true);
|
|
130086
130110
|
await runEndHooks();
|
|
@@ -130088,8 +130112,12 @@ Type your task to begin the loop.`, true);
|
|
|
130088
130112
|
const client = await getClient2();
|
|
130089
130113
|
const conversation = await client.conversations.create({
|
|
130090
130114
|
agent_id: agentId,
|
|
130091
|
-
isolated_block_labels: [...ISOLATED_BLOCK_LABELS]
|
|
130115
|
+
isolated_block_labels: [...ISOLATED_BLOCK_LABELS],
|
|
130116
|
+
...conversationName && { summary: conversationName }
|
|
130092
130117
|
});
|
|
130118
|
+
if (conversationName) {
|
|
130119
|
+
hasSetConversationSummaryRef.current = true;
|
|
130120
|
+
}
|
|
130093
130121
|
await maybeCarryOverActiveConversationModel(conversation.id);
|
|
130094
130122
|
setConversationId3(conversation.id);
|
|
130095
130123
|
pendingConversationSwitchRef.current = {
|
|
@@ -133862,6 +133890,9 @@ If using apply_patch, use this exact relative patch path: ${applyPatchRelativePa
|
|
|
133862
133890
|
summary: selectorContext?.summary,
|
|
133863
133891
|
messageHistory: resumeData.messageHistory
|
|
133864
133892
|
};
|
|
133893
|
+
if (selectorContext?.summary) {
|
|
133894
|
+
hasSetConversationSummaryRef.current = true;
|
|
133895
|
+
}
|
|
133865
133896
|
settingsManager.setLocalLastSession({ agentId, conversationId: convId }, process.cwd());
|
|
133866
133897
|
settingsManager.setGlobalLastSession({
|
|
133867
133898
|
agentId,
|
|
@@ -134864,7 +134895,7 @@ var init_release_notes = __esm(async () => {
|
|
|
134864
134895
|
→ Read more: https://docs.letta.com/letta-code/changelog#0134`,
|
|
134865
134896
|
"0.13.0": `\uD83C\uDF81 **Letta Code 0.13.0: Introducing Conversations!**
|
|
134866
134897
|
→ Letta Code now starts a new conversation on each startup (memory is shared across all conversations)
|
|
134867
|
-
→ Use **/resume** to switch conversations, or run **letta --
|
|
134898
|
+
→ Use **/resume** to switch conversations, or run **letta --conv <id>** to continue a specific conversation
|
|
134868
134899
|
→ Read more: https://docs.letta.com/letta-code/changelog#0130`
|
|
134869
134900
|
};
|
|
134870
134901
|
});
|
|
@@ -136449,13 +136480,6 @@ var CLI_FLAG_CATALOG = {
|
|
|
136449
136480
|
mode: "both",
|
|
136450
136481
|
help: { description: "Show current directory, skills, and pinned agents" }
|
|
136451
136482
|
},
|
|
136452
|
-
continue: {
|
|
136453
|
-
parser: { type: "boolean", short: "c" },
|
|
136454
|
-
mode: "both",
|
|
136455
|
-
help: {
|
|
136456
|
-
description: "Resume last session (agent + conversation) directly"
|
|
136457
|
-
}
|
|
136458
|
-
},
|
|
136459
136483
|
resume: {
|
|
136460
136484
|
parser: { type: "boolean", short: "r" },
|
|
136461
136485
|
mode: "interactive",
|
|
@@ -137005,20 +137029,6 @@ function ConversationSelector({
|
|
|
137005
137029
|
children: "⎿ "
|
|
137006
137030
|
}, undefined, false, undefined, this);
|
|
137007
137031
|
const indent = " ";
|
|
137008
|
-
if (conv.summary) {
|
|
137009
|
-
return /* @__PURE__ */ jsx_dev_runtime4.jsxDEV(Box_default, {
|
|
137010
|
-
flexDirection: "row",
|
|
137011
|
-
marginLeft: 2,
|
|
137012
|
-
children: [
|
|
137013
|
-
bracket,
|
|
137014
|
-
/* @__PURE__ */ jsx_dev_runtime4.jsxDEV(Text2, {
|
|
137015
|
-
dimColor: true,
|
|
137016
|
-
italic: true,
|
|
137017
|
-
children: conv.summary.length > 57 ? `${conv.summary.slice(0, 54)}...` : conv.summary
|
|
137018
|
-
}, undefined, false, undefined, this)
|
|
137019
|
-
]
|
|
137020
|
-
}, undefined, true, undefined, this);
|
|
137021
|
-
}
|
|
137022
137032
|
if (previewLines.length > 0) {
|
|
137023
137033
|
return /* @__PURE__ */ jsx_dev_runtime4.jsxDEV(jsx_dev_runtime4.Fragment, {
|
|
137024
137034
|
children: previewLines.map((line, idx) => /* @__PURE__ */ jsx_dev_runtime4.jsxDEV(Box_default, {
|
|
@@ -137091,9 +137101,9 @@ function ConversationSelector({
|
|
|
137091
137101
|
/* @__PURE__ */ jsx_dev_runtime4.jsxDEV(Text2, {
|
|
137092
137102
|
bold: isSelected,
|
|
137093
137103
|
color: isSelected ? colors.selector.itemHighlighted : undefined,
|
|
137094
|
-
children: isDefault ? "default" : conv.id
|
|
137104
|
+
children: conv.summary ? `${conv.summary.length > 40 ? `${conv.summary.slice(0, 37)}...` : conv.summary} (${conv.id})` : isDefault ? "default" : conv.id
|
|
137095
137105
|
}, undefined, false, undefined, this),
|
|
137096
|
-
isDefault && /* @__PURE__ */ jsx_dev_runtime4.jsxDEV(Text2, {
|
|
137106
|
+
!conv.summary && isDefault && /* @__PURE__ */ jsx_dev_runtime4.jsxDEV(Text2, {
|
|
137097
137107
|
dimColor: true,
|
|
137098
137108
|
children: " (agent's default conversation)"
|
|
137099
137109
|
}, undefined, false, undefined, this),
|
|
@@ -139653,8 +139663,8 @@ async function listBackups(agentId) {
|
|
|
139653
139663
|
const path23 = join23(agentRoot, entry.name);
|
|
139654
139664
|
let createdAt = null;
|
|
139655
139665
|
try {
|
|
139656
|
-
const
|
|
139657
|
-
createdAt =
|
|
139666
|
+
const stat5 = statSync5(path23);
|
|
139667
|
+
createdAt = stat5.mtime.toISOString();
|
|
139658
139668
|
} catch {
|
|
139659
139669
|
createdAt = null;
|
|
139660
139670
|
}
|
|
@@ -139762,8 +139772,8 @@ async function runMemfsSubcommand(argv) {
|
|
|
139762
139772
|
console.error(`Backup not found: ${backupPath}`);
|
|
139763
139773
|
return 1;
|
|
139764
139774
|
}
|
|
139765
|
-
const
|
|
139766
|
-
if (!
|
|
139775
|
+
const stat5 = statSync5(backupPath);
|
|
139776
|
+
if (!stat5.isDirectory()) {
|
|
139767
139777
|
console.error(`Backup path is not a directory: ${backupPath}`);
|
|
139768
139778
|
return 1;
|
|
139769
139779
|
}
|
|
@@ -139785,8 +139795,8 @@ async function runMemfsSubcommand(argv) {
|
|
|
139785
139795
|
return 1;
|
|
139786
139796
|
}
|
|
139787
139797
|
if (existsSync18(out)) {
|
|
139788
|
-
const
|
|
139789
|
-
if (
|
|
139798
|
+
const stat5 = statSync5(out);
|
|
139799
|
+
if (stat5.isDirectory()) {
|
|
139790
139800
|
const contents = await readdir5(out);
|
|
139791
139801
|
if (contents.length > 0) {
|
|
139792
139802
|
console.error(`Export directory not empty: ${out}`);
|
|
@@ -141990,9 +142000,8 @@ Letta Code is a general purpose CLI for interacting with Letta agents
|
|
|
141990
142000
|
|
|
141991
142001
|
USAGE
|
|
141992
142002
|
# interactive TUI
|
|
141993
|
-
letta Resume
|
|
142003
|
+
letta Resume last conversation for this project
|
|
141994
142004
|
letta --new Create a new conversation (for concurrent sessions)
|
|
141995
|
-
letta --continue Resume last session (agent + conversation) directly
|
|
141996
142005
|
letta --resume Open agent selector UI to pick agent/conversation
|
|
141997
142006
|
letta --new-agent Create a new agent directly (skip profile selector)
|
|
141998
142007
|
letta --agent <id> Open a specific agent by ID
|
|
@@ -142261,7 +142270,6 @@ Note: Flags should use double dashes for full names (e.g., --yolo, not -yolo)`);
|
|
|
142261
142270
|
console.log(result.message);
|
|
142262
142271
|
process.exit(result.success ? 0 : 1);
|
|
142263
142272
|
}
|
|
142264
|
-
const shouldContinue = values.continue ?? false;
|
|
142265
142273
|
const shouldResume = values.resume ?? false;
|
|
142266
142274
|
let specifiedConversationId = values.conversation ?? null;
|
|
142267
142275
|
const forceNew = values["new-agent"] ?? false;
|
|
@@ -142396,20 +142404,12 @@ Note: Flags should use double dashes for full names (e.g., --yolo, not -yolo)`);
|
|
|
142396
142404
|
{
|
|
142397
142405
|
when: shouldResume,
|
|
142398
142406
|
message: "--conversation cannot be used with --resume"
|
|
142399
|
-
},
|
|
142400
|
-
{
|
|
142401
|
-
when: shouldContinue,
|
|
142402
|
-
message: "--conversation cannot be used with --continue"
|
|
142403
142407
|
}
|
|
142404
142408
|
]
|
|
142405
142409
|
});
|
|
142406
142410
|
validateFlagConflicts({
|
|
142407
142411
|
guard: forceNewConversation,
|
|
142408
142412
|
checks: [
|
|
142409
|
-
{
|
|
142410
|
-
when: shouldContinue,
|
|
142411
|
-
message: "--new cannot be used with --continue"
|
|
142412
|
-
},
|
|
142413
142413
|
{
|
|
142414
142414
|
when: specifiedConversationId,
|
|
142415
142415
|
message: "--new cannot be used with --conversation"
|
|
@@ -142600,7 +142600,6 @@ Error: ${message}`);
|
|
|
142600
142600
|
const AppModule = await init_App2().then(() => exports_App);
|
|
142601
142601
|
const App3 = AppModule.default;
|
|
142602
142602
|
function LoadingApp({
|
|
142603
|
-
continueSession,
|
|
142604
142603
|
forceNew: forceNew2,
|
|
142605
142604
|
initBlocks: initBlocks2,
|
|
142606
142605
|
baseTools: baseTools2,
|
|
@@ -142754,8 +142753,8 @@ Error: ${message}`);
|
|
|
142754
142753
|
}
|
|
142755
142754
|
}
|
|
142756
142755
|
if (shouldResume) {
|
|
142757
|
-
const
|
|
142758
|
-
const localAgentId2 =
|
|
142756
|
+
const localSession2 = settingsManager2.getLocalLastSession(process.cwd());
|
|
142757
|
+
const localAgentId2 = localSession2?.agentId ?? localSettings.lastAgent;
|
|
142759
142758
|
if (localAgentId2) {
|
|
142760
142759
|
try {
|
|
142761
142760
|
const agent = await client.agents.retrieve(localAgentId2);
|
|
@@ -142782,41 +142781,6 @@ Error: ${message}`);
|
|
|
142782
142781
|
console.error("Run 'letta' to get started.");
|
|
142783
142782
|
process.exit(1);
|
|
142784
142783
|
}
|
|
142785
|
-
if (continueSession) {
|
|
142786
|
-
const localSession = settingsManager2.getLocalLastSession(process.cwd());
|
|
142787
|
-
const localAgentId2 = localSession?.agentId ?? localSettings.lastAgent;
|
|
142788
|
-
if (localAgentId2) {
|
|
142789
|
-
try {
|
|
142790
|
-
await client.agents.retrieve(localAgentId2);
|
|
142791
|
-
setSelectedGlobalAgentId(localAgentId2);
|
|
142792
|
-
if (localSession?.conversationId) {
|
|
142793
|
-
setSelectedConversationId(localSession.conversationId);
|
|
142794
|
-
}
|
|
142795
|
-
setLoadingState("assembling");
|
|
142796
|
-
return;
|
|
142797
|
-
} catch {
|
|
142798
|
-
setFailedAgentMessage(`Unable to locate agent ${localAgentId2} in .letta/, checking global (~/.letta)`);
|
|
142799
|
-
}
|
|
142800
|
-
} else {
|
|
142801
|
-
console.log("No recent agent in .letta/, using global (~/.letta)");
|
|
142802
|
-
}
|
|
142803
|
-
const globalSession = settingsManager2.getGlobalLastSession();
|
|
142804
|
-
const globalAgentId2 = globalSession?.agentId;
|
|
142805
|
-
if (globalAgentId2) {
|
|
142806
|
-
try {
|
|
142807
|
-
await client.agents.retrieve(globalAgentId2);
|
|
142808
|
-
setSelectedGlobalAgentId(globalAgentId2);
|
|
142809
|
-
if (globalSession?.conversationId) {
|
|
142810
|
-
setSelectedConversationId(globalSession.conversationId);
|
|
142811
|
-
}
|
|
142812
|
-
setLoadingState("assembling");
|
|
142813
|
-
return;
|
|
142814
|
-
} catch {}
|
|
142815
|
-
}
|
|
142816
|
-
console.error("No recent session found in .letta/ or ~/.letta.");
|
|
142817
|
-
console.error("Run 'letta' to get started.");
|
|
142818
|
-
process.exit(1);
|
|
142819
|
-
}
|
|
142820
142784
|
if (forceNew2 || agentIdArg || fromAfFile2) {
|
|
142821
142785
|
setLoadingState("assembling");
|
|
142822
142786
|
return;
|
|
@@ -142844,9 +142808,10 @@ Error: ${message}`);
|
|
|
142844
142808
|
}
|
|
142845
142809
|
const mergedPinned = settingsManager2.getMergedPinnedAgents(process.cwd());
|
|
142846
142810
|
const { resolveStartupTarget: resolveStartupTarget2 } = await Promise.resolve().then(() => exports_resolve_startup_agent);
|
|
142811
|
+
const localSession = settingsManager2.getLocalLastSession(process.cwd());
|
|
142847
142812
|
const target = resolveStartupTarget2({
|
|
142848
142813
|
localAgentId,
|
|
142849
|
-
localConversationId: null,
|
|
142814
|
+
localConversationId: localSession?.conversationId ?? null,
|
|
142850
142815
|
localAgentExists,
|
|
142851
142816
|
globalAgentId,
|
|
142852
142817
|
globalAgentExists,
|
|
@@ -142860,6 +142825,9 @@ Error: ${message}`);
|
|
|
142860
142825
|
if (cachedAgent && cachedAgent.id === target.agentId) {
|
|
142861
142826
|
setValidatedAgent(cachedAgent);
|
|
142862
142827
|
}
|
|
142828
|
+
if (target.conversationId && !forceNewConversation) {
|
|
142829
|
+
setSelectedConversationId(target.conversationId);
|
|
142830
|
+
}
|
|
142863
142831
|
setLoadingState("assembling");
|
|
142864
142832
|
return;
|
|
142865
142833
|
case "select":
|
|
@@ -142890,7 +142858,6 @@ Error: ${message}`);
|
|
|
142890
142858
|
forceNew2,
|
|
142891
142859
|
agentIdArg,
|
|
142892
142860
|
fromAfFile2,
|
|
142893
|
-
continueSession,
|
|
142894
142861
|
shouldResume,
|
|
142895
142862
|
specifiedConversationId
|
|
142896
142863
|
]);
|
|
@@ -142930,15 +142897,6 @@ Error: ${message}`);
|
|
|
142930
142897
|
return;
|
|
142931
142898
|
}
|
|
142932
142899
|
}
|
|
142933
|
-
if (!resumingAgentId && continueSession && settings.lastAgent) {
|
|
142934
|
-
try {
|
|
142935
|
-
await client.agents.retrieve(settings.lastAgent);
|
|
142936
|
-
resumingAgentId = settings.lastAgent;
|
|
142937
|
-
} catch {
|
|
142938
|
-
setLoadingState("selecting_global");
|
|
142939
|
-
return;
|
|
142940
|
-
}
|
|
142941
|
-
}
|
|
142942
142900
|
}
|
|
142943
142901
|
setIsResumingSession(!!resumingAgentId);
|
|
142944
142902
|
const modelForTools = getModelForToolLoading(model, toolset);
|
|
@@ -143044,15 +143002,6 @@ Error: ${message}`);
|
|
|
143044
143002
|
return;
|
|
143045
143003
|
}
|
|
143046
143004
|
}
|
|
143047
|
-
if (!agent && continueSession && settings.lastAgent) {
|
|
143048
|
-
try {
|
|
143049
|
-
agent = await client.agents.retrieve(settings.lastAgent);
|
|
143050
|
-
} catch (error) {
|
|
143051
|
-
console.error(`Previous agent ${settings.lastAgent} not found (error: ${JSON.stringify(error)})`);
|
|
143052
|
-
setLoadingState("selecting_global");
|
|
143053
|
-
return;
|
|
143054
|
-
}
|
|
143055
|
-
}
|
|
143056
143005
|
if (!agent) {
|
|
143057
143006
|
console.error("No agent found. Use --new-agent to create a new agent.");
|
|
143058
143007
|
process.exit(1);
|
|
@@ -143073,7 +143022,7 @@ Error: ${message}`);
|
|
|
143073
143022
|
}));
|
|
143074
143023
|
const isResumingProject = !shouldCreateNew && !!resumingAgentId;
|
|
143075
143024
|
const isReusingExistingAgent = !shouldCreateNew && !fromAfFile2 && agent && agent.id;
|
|
143076
|
-
const resuming = !!(
|
|
143025
|
+
const resuming = !!(agentIdArg || isResumingProject || isReusingExistingAgent);
|
|
143077
143026
|
setIsResumingSession(resuming);
|
|
143078
143027
|
if (resuming) {
|
|
143079
143028
|
if (model) {
|
|
@@ -143122,7 +143071,6 @@ Error: ${message}`);
|
|
|
143122
143071
|
});
|
|
143123
143072
|
let conversationIdToUse;
|
|
143124
143073
|
if (isDebugEnabled2()) {
|
|
143125
|
-
debugLog2("startup", "shouldContinue=%o", shouldContinue);
|
|
143126
143074
|
debugLog2("startup", "shouldResume=%o", shouldResume);
|
|
143127
143075
|
debugLog2("startup", "specifiedConversationId=%s", specifiedConversationId);
|
|
143128
143076
|
}
|
|
@@ -143140,34 +143088,6 @@ Error: ${message}`);
|
|
|
143140
143088
|
}
|
|
143141
143089
|
throw error;
|
|
143142
143090
|
}
|
|
143143
|
-
} else if (shouldContinue) {
|
|
143144
|
-
const lastSession = settingsManager2.getLocalLastSession(process.cwd()) ?? settingsManager2.getGlobalLastSession();
|
|
143145
|
-
if (isDebugEnabled2()) {
|
|
143146
|
-
debugLog2("startup", "lastSession=%s", JSON.stringify(lastSession));
|
|
143147
|
-
debugLog2("startup", "agent.id=%s", agent.id);
|
|
143148
|
-
}
|
|
143149
|
-
let resumedSuccessfully = false;
|
|
143150
|
-
if (lastSession && lastSession.agentId === agent.id) {
|
|
143151
|
-
try {
|
|
143152
|
-
setLoadingState("checking");
|
|
143153
|
-
const data = await getResumeData(client, agent, lastSession.conversationId);
|
|
143154
|
-
conversationIdToUse = lastSession.conversationId;
|
|
143155
|
-
setResumedExistingConversation(true);
|
|
143156
|
-
setResumeData(data);
|
|
143157
|
-
resumedSuccessfully = true;
|
|
143158
|
-
} catch (error) {
|
|
143159
|
-
if (error instanceof APIError && (error.status === 404 || error.status === 422)) {
|
|
143160
|
-
console.warn(`Previous conversation ${lastSession.conversationId} not found, creating new`);
|
|
143161
|
-
} else {
|
|
143162
|
-
throw error;
|
|
143163
|
-
}
|
|
143164
|
-
}
|
|
143165
|
-
}
|
|
143166
|
-
if (!resumedSuccessfully) {
|
|
143167
|
-
console.error(`Attempting to resume conversation ${lastSession?.conversationId ?? "(unknown)"}, but conversation was not found.`);
|
|
143168
|
-
console.error("Resume the default conversation with 'letta', view recent conversations with 'letta --resume', or start a new conversation with 'letta --new'.");
|
|
143169
|
-
process.exit(1);
|
|
143170
|
-
}
|
|
143171
143091
|
} else if (selectedConversationId) {
|
|
143172
143092
|
try {
|
|
143173
143093
|
setLoadingState("checking");
|
|
@@ -143177,10 +143097,15 @@ Error: ${message}`);
|
|
|
143177
143097
|
setResumeData(data);
|
|
143178
143098
|
} catch (error) {
|
|
143179
143099
|
if (error instanceof APIError && (error.status === 404 || error.status === 422)) {
|
|
143180
|
-
console.
|
|
143181
|
-
|
|
143100
|
+
console.warn(`Previous conversation ${selectedConversationId} not found, falling back to default`);
|
|
143101
|
+
conversationIdToUse = "default";
|
|
143102
|
+
setLoadingState("checking");
|
|
143103
|
+
const data = await getResumeData(client, agent, "default");
|
|
143104
|
+
setResumeData(data);
|
|
143105
|
+
setResumedExistingConversation(data.messageHistory.length > 0);
|
|
143106
|
+
} else {
|
|
143107
|
+
throw error;
|
|
143182
143108
|
}
|
|
143183
|
-
throw error;
|
|
143184
143109
|
}
|
|
143185
143110
|
} else if (forceNewConversation) {
|
|
143186
143111
|
const conversation = await client.conversations.create({
|
|
@@ -143251,7 +143176,6 @@ Error during initialization: ${message}`);
|
|
|
143251
143176
|
process.exit(1);
|
|
143252
143177
|
});
|
|
143253
143178
|
}, [
|
|
143254
|
-
continueSession,
|
|
143255
143179
|
forceNew2,
|
|
143256
143180
|
userRequestedNewAgent,
|
|
143257
143181
|
agentIdArg,
|
|
@@ -143261,7 +143185,6 @@ Error during initialization: ${message}`);
|
|
|
143261
143185
|
loadingState,
|
|
143262
143186
|
selectedGlobalAgentId,
|
|
143263
143187
|
validatedAgent,
|
|
143264
|
-
shouldContinue,
|
|
143265
143188
|
resumeAgentId,
|
|
143266
143189
|
selectedConversationId
|
|
143267
143190
|
]);
|
|
@@ -143362,7 +143285,6 @@ Error during initialization: ${message}`);
|
|
|
143362
143285
|
}
|
|
143363
143286
|
markMilestone2("REACT_RENDER_START");
|
|
143364
143287
|
render2(React14.createElement(LoadingApp, {
|
|
143365
|
-
continueSession: shouldContinue,
|
|
143366
143288
|
forceNew,
|
|
143367
143289
|
initBlocks,
|
|
143368
143290
|
baseTools,
|
|
@@ -143379,4 +143301,4 @@ Error during initialization: ${message}`);
|
|
|
143379
143301
|
}
|
|
143380
143302
|
main();
|
|
143381
143303
|
|
|
143382
|
-
//# debugId=
|
|
143304
|
+
//# debugId=370E7E3EE35E2CB664756E2164756E21
|