@letta-ai/letta-code 0.33.7 → 0.33.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/agent-presets.js.map +1 -1
- package/dist/channels-public.js.map +1 -1
- package/dist/mcp-client.js +8 -7
- package/dist/mcp-client.js.map +3 -3
- package/dist/mcp-oauth.js +23 -9
- package/dist/mcp-oauth.js.map +4 -4
- package/dist/types/agent/client-skills.d.ts.map +1 -1
- package/dist/types/agent/skills.d.ts +5 -0
- package/dist/types/agent/skills.d.ts.map +1 -1
- package/dist/types/backend/dev/pi-ollama-provider.d.ts +7 -16
- package/dist/types/backend/dev/pi-ollama-provider.d.ts.map +1 -1
- package/dist/types/constants.d.ts +1 -1
- package/dist/types/constants.d.ts.map +1 -1
- package/dist/types/experiments/manager.d.ts.map +1 -1
- package/dist/types/experiments/types.d.ts +1 -1
- package/dist/types/experiments/types.d.ts.map +1 -1
- package/dist/types/mcp-client.d.ts +4 -0
- package/dist/types/mcp-client.d.ts.map +1 -1
- package/dist/types/mcp-oauth-public.d.ts +10 -1
- package/dist/types/mcp-oauth-public.d.ts.map +1 -1
- package/dist/types/tools/toolset-catalog.d.ts +1 -1
- package/dist/types/types/protocol_v2.d.ts +1 -1
- package/dist/types/types/protocol_v2.d.ts.map +1 -1
- package/letta.js +110 -45
- package/package.json +1 -1
- package/skills/curating-memory-palace/SKILL.md +105 -0
package/letta.js
CHANGED
|
@@ -5648,7 +5648,7 @@ var package_default;
|
|
|
5648
5648
|
var init_package = __esm(() => {
|
|
5649
5649
|
package_default = {
|
|
5650
5650
|
name: "@letta-ai/letta-code",
|
|
5651
|
-
version: "0.33.
|
|
5651
|
+
version: "0.33.8",
|
|
5652
5652
|
lettaStartupLogProtocol: 1,
|
|
5653
5653
|
description: "Letta Code is a CLI tool for interacting with stateful Letta agents from the terminal.",
|
|
5654
5654
|
type: "module",
|
|
@@ -90892,7 +90892,7 @@ var init_context = __esm(() => {
|
|
|
90892
90892
|
});
|
|
90893
90893
|
|
|
90894
90894
|
// src/constants.ts
|
|
90895
|
-
var DEFAULT_SUMMARIZATION_MODEL = "letta/auto", DEFAULT_TITLE_SUMMARIZATION_MODEL = "openai/gpt-
|
|
90895
|
+
var DEFAULT_SUMMARIZATION_MODEL = "letta/auto", DEFAULT_TITLE_SUMMARIZATION_MODEL = "openai/gpt-6-luna", DEFAULT_AGENT_NAME = "Letta Code", INTERRUPTED_BY_USER = "Interrupted by user", TURN_DID_NOT_COMPLETE = "Turn did not complete", SYSTEM_REMINDER_TAG = "system-reminder", SYSTEM_REMINDER_OPEN, SYSTEM_REMINDER_CLOSE, SYSTEM_ALERT_TAG = "system-alert", SYSTEM_ALERT_OPEN, SYSTEM_ALERT_CLOSE, COMPACTION_SUMMARY_HEADER = "(Earlier messages in this conversation have been compacted to free up context, summarized below)", TOKEN_DISPLAY_THRESHOLD = 100, ELAPSED_DISPLAY_THRESHOLD_MS;
|
|
90896
90896
|
var init_constants2 = __esm(() => {
|
|
90897
90897
|
SYSTEM_REMINDER_OPEN = `<${SYSTEM_REMINDER_TAG}>`;
|
|
90898
90898
|
SYSTEM_REMINDER_CLOSE = `</${SYSTEM_REMINDER_TAG}>`;
|
|
@@ -107158,27 +107158,63 @@ function parseOllamaTags(data) {
|
|
|
107158
107158
|
};
|
|
107159
107159
|
}).filter((entry) => entry !== undefined);
|
|
107160
107160
|
}
|
|
107161
|
-
function
|
|
107162
|
-
const
|
|
107161
|
+
function ollamaIdentityKeys(id2) {
|
|
107162
|
+
const normalized = normalizeOllamaModelId(id2);
|
|
107163
|
+
return normalized === id2 ? [id2] : [id2, normalized];
|
|
107164
|
+
}
|
|
107165
|
+
function parseOllamaPsEntries(data) {
|
|
107163
107166
|
if (!data || typeof data !== "object")
|
|
107164
|
-
return
|
|
107167
|
+
return [];
|
|
107165
107168
|
const models3 = data.models;
|
|
107166
107169
|
if (!Array.isArray(models3))
|
|
107167
|
-
return
|
|
107170
|
+
return [];
|
|
107171
|
+
const entries = [];
|
|
107168
107172
|
for (const entry of models3) {
|
|
107169
107173
|
if (!entry || typeof entry !== "object")
|
|
107170
107174
|
continue;
|
|
107171
107175
|
const record4 = entry;
|
|
107172
|
-
const
|
|
107173
|
-
|
|
107174
|
-
if (typeof id2 !== "string" || id2.length === 0)
|
|
107176
|
+
const rawIds = [record4.name, record4.model].filter((id2) => typeof id2 === "string" && id2.length > 0);
|
|
107177
|
+
if (rawIds.length === 0)
|
|
107175
107178
|
continue;
|
|
107176
|
-
|
|
107179
|
+
const contextLength = record4.context_length;
|
|
107180
|
+
entries.push({
|
|
107181
|
+
ids: [...new Set(rawIds.flatMap(ollamaIdentityKeys))],
|
|
107182
|
+
displayId: rawIds[0],
|
|
107183
|
+
...typeof contextLength === "number" && contextLength > 0 ? { contextLength } : {}
|
|
107184
|
+
});
|
|
107185
|
+
}
|
|
107186
|
+
return entries;
|
|
107187
|
+
}
|
|
107188
|
+
function parseOllamaRunningContexts(data) {
|
|
107189
|
+
const contexts = new Map;
|
|
107190
|
+
for (const entry of parseOllamaPsEntries(data)) {
|
|
107191
|
+
if (entry.contextLength === undefined)
|
|
107177
107192
|
continue;
|
|
107178
|
-
|
|
107193
|
+
for (const id2 of entry.ids)
|
|
107194
|
+
contexts.set(id2, entry.contextLength);
|
|
107179
107195
|
}
|
|
107180
107196
|
return contexts;
|
|
107181
107197
|
}
|
|
107198
|
+
function readOllamaServedContextOverride(env4) {
|
|
107199
|
+
const raw = env4[OLLAMA_SERVED_CONTEXT_OVERRIDE_ENV];
|
|
107200
|
+
if (raw === undefined || raw.trim() === "")
|
|
107201
|
+
return;
|
|
107202
|
+
const trimmed = raw.trim();
|
|
107203
|
+
if (!/^[1-9]\d*$/.test(trimmed) || !Number.isSafeInteger(Number(trimmed))) {
|
|
107204
|
+
throw new Error(`${OLLAMA_SERVED_CONTEXT_OVERRIDE_ENV}=${JSON.stringify(trimmed)} is not a positive integer token count. ` + `Set it to the context window your Ollama daemon actually serves.`);
|
|
107205
|
+
}
|
|
107206
|
+
return Number(trimmed);
|
|
107207
|
+
}
|
|
107208
|
+
function missingServedContextError(modelId, data) {
|
|
107209
|
+
const entries = parseOllamaPsEntries(data);
|
|
107210
|
+
const match2 = entries.find((entry) => entry.ids.includes(modelId));
|
|
107211
|
+
if (match2) {
|
|
107212
|
+
return `Ollama lists "${modelId}" in /api/ps but did not report context_length. ` + `Refusing to send the prompt because Ollama may silently truncate it. ` + `context_length requires Ollama 0.10.0 or newer. ` + `Upgrade Ollama, or set ${OLLAMA_SERVED_CONTEXT_OVERRIDE_ENV} to the window your daemon actually serves.`;
|
|
107213
|
+
}
|
|
107214
|
+
const running = entries.map((entry) => entry.displayId).filter((id2) => id2 !== undefined);
|
|
107215
|
+
const runningNote = running.length > 0 ? ` Running models: ${running.join(", ")}.` : ` /api/ps lists no running models.`;
|
|
107216
|
+
return `Ollama loaded "${modelId}", but /api/ps does not list it. ` + `Refusing to send the prompt because Ollama may silently truncate it. ` + `If OLLAMA_KEEP_ALIVE=0, the model unloaded before this check.` + runningNote + ` Set ${OLLAMA_SERVED_CONTEXT_OVERRIDE_ENV} to the window your daemon actually serves.`;
|
|
107217
|
+
}
|
|
107182
107218
|
async function fetchOllamaNative(fetchImpl, url, options) {
|
|
107183
107219
|
const controller = new AbortController;
|
|
107184
107220
|
const timeout = setTimeout(() => controller.abort(), options.timeoutMs);
|
|
@@ -107210,42 +107246,49 @@ async function fetchOllamaNative(fetchImpl, url, options) {
|
|
|
107210
107246
|
}
|
|
107211
107247
|
}
|
|
107212
107248
|
async function resolveOllamaServedContext(options) {
|
|
107249
|
+
const override = readOllamaServedContextOverride(options.env ?? process.env);
|
|
107250
|
+
if (override !== undefined)
|
|
107251
|
+
return override;
|
|
107213
107252
|
const fetchImpl = options.fetchImpl ?? fetch;
|
|
107214
107253
|
const modelId = normalizeOllamaModelId(options.modelId);
|
|
107215
107254
|
const nativeBaseURL = localEndpointNativeBaseURL(options.baseURL);
|
|
107216
107255
|
const psURL = `${nativeBaseURL}/api/ps`;
|
|
107217
|
-
const
|
|
107218
|
-
const data = await fetchOllamaNative(fetchImpl, psURL, {
|
|
107219
|
-
...options.apiKey ? { apiKey: options.apiKey } : {},
|
|
107220
|
-
...options.signal ? { signal: options.signal } : {},
|
|
107221
|
-
timeoutMs: OLLAMA_STATUS_TIMEOUT_MS,
|
|
107222
|
-
consume: (response) => response.json()
|
|
107223
|
-
});
|
|
107224
|
-
return parseOllamaRunningContexts(data).get(modelId);
|
|
107225
|
-
};
|
|
107256
|
+
const overrideHint = `or set ${OLLAMA_SERVED_CONTEXT_OVERRIDE_ENV} to the window your daemon actually serves`;
|
|
107226
107257
|
try {
|
|
107227
107258
|
await fetchOllamaNative(fetchImpl, `${nativeBaseURL}/api/generate`, {
|
|
107228
107259
|
...options.apiKey ? { apiKey: options.apiKey } : {},
|
|
107229
107260
|
...options.signal ? { signal: options.signal } : {},
|
|
107230
|
-
body: {
|
|
107261
|
+
body: {
|
|
107262
|
+
model: modelId,
|
|
107263
|
+
prompt: "",
|
|
107264
|
+
stream: false,
|
|
107265
|
+
keep_alive: OLLAMA_PREFLIGHT_KEEP_ALIVE
|
|
107266
|
+
},
|
|
107231
107267
|
timeoutMs: OLLAMA_MODEL_LOAD_TIMEOUT_MS,
|
|
107232
107268
|
consume: (response) => response.text()
|
|
107233
107269
|
});
|
|
107234
107270
|
} catch (error4) {
|
|
107235
107271
|
if (options.signal?.aborted)
|
|
107236
107272
|
throw options.signal.reason ?? error4;
|
|
107237
|
-
throw new Error(`Unable to load Ollama model "${modelId}" to determine its served context window. ` + `Refusing to send the prompt because Ollama may silently truncate it. ` + `Check the Ollama endpoint, model installation, and available memory. (${error4 instanceof Error ? error4.message : String(error4)})`);
|
|
107273
|
+
throw new Error(`Unable to load Ollama model "${modelId}" to determine its served context window. ` + `Refusing to send the prompt because Ollama may silently truncate it. ` + `Check the Ollama endpoint, model installation, and available memory, ${overrideHint}. (${error4 instanceof Error ? error4.message : String(error4)})`);
|
|
107238
107274
|
}
|
|
107275
|
+
let running;
|
|
107239
107276
|
try {
|
|
107240
|
-
|
|
107241
|
-
|
|
107242
|
-
|
|
107277
|
+
running = await fetchOllamaNative(fetchImpl, psURL, {
|
|
107278
|
+
...options.apiKey ? { apiKey: options.apiKey } : {},
|
|
107279
|
+
...options.signal ? { signal: options.signal } : {},
|
|
107280
|
+
timeoutMs: OLLAMA_STATUS_TIMEOUT_MS,
|
|
107281
|
+
consume: (response) => response.json()
|
|
107282
|
+
});
|
|
107243
107283
|
} catch (error4) {
|
|
107244
107284
|
if (options.signal?.aborted)
|
|
107245
107285
|
throw options.signal.reason ?? error4;
|
|
107246
|
-
throw new Error(`Ollama loaded model "${modelId}", but /api/ps could not verify its served context window. ` + `Refusing to send the prompt because Ollama may silently truncate it. ` + `Check that the endpoint supports /api/ps. (${error4 instanceof Error ? error4.message : String(error4)})`);
|
|
107286
|
+
throw new Error(`Ollama loaded model "${modelId}", but /api/ps could not verify its served context window. ` + `Refusing to send the prompt because Ollama may silently truncate it. ` + `Check that the endpoint supports /api/ps, ${overrideHint}. (${error4 instanceof Error ? error4.message : String(error4)})`);
|
|
107247
107287
|
}
|
|
107248
|
-
|
|
107288
|
+
const loadedContext = parseOllamaRunningContexts(running).get(modelId);
|
|
107289
|
+
if (loadedContext !== undefined)
|
|
107290
|
+
return loadedContext;
|
|
107291
|
+
throw new Error(missingServedContextError(modelId, running));
|
|
107249
107292
|
}
|
|
107250
107293
|
function parseOllamaShow(modelId, data, runtimeContextLength) {
|
|
107251
107294
|
if (!data || typeof data !== "object")
|
|
@@ -107275,7 +107318,7 @@ function createOllamaPiProvider(options) {
|
|
|
107275
107318
|
discover: ollamaDiscover
|
|
107276
107319
|
});
|
|
107277
107320
|
}
|
|
107278
|
-
var OLLAMA_PI_PROVIDER_ID = "ollama", OLLAMA_CLOUD_PI_PROVIDER_ID = "ollama-cloud", OLLAMA_STATUS_TIMEOUT_MS = 2000, OLLAMA_MODEL_LOAD_TIMEOUT_MS = 120000, ollamaDiscover = async (context3) => {
|
|
107321
|
+
var OLLAMA_PI_PROVIDER_ID = "ollama", OLLAMA_CLOUD_PI_PROVIDER_ID = "ollama-cloud", OLLAMA_STATUS_TIMEOUT_MS = 2000, OLLAMA_MODEL_LOAD_TIMEOUT_MS = 120000, OLLAMA_PREFLIGHT_KEEP_ALIVE = "5m", OLLAMA_SERVED_CONTEXT_OVERRIDE_ENV = "LETTA_OLLAMA_CONTEXT_LENGTH", ollamaDiscover = async (context3) => {
|
|
107279
107322
|
const tags = await context3.fetchJson(`${context3.nativeBaseURL}/api/tags`);
|
|
107280
107323
|
const entries = parseOllamaTags(tags);
|
|
107281
107324
|
const runtimeContexts = await context3.fetchJson(`${context3.nativeBaseURL}/api/ps`).then(parseOllamaRunningContexts).catch(() => new Map);
|
|
@@ -188517,6 +188560,12 @@ var init_manager = __esm(() => {
|
|
|
188517
188560
|
label: "diffs",
|
|
188518
188561
|
description: "Open browser-based worktree diff previews powered by Diffs from Pierre."
|
|
188519
188562
|
},
|
|
188563
|
+
{
|
|
188564
|
+
id: "memory_palace",
|
|
188565
|
+
label: "memory palace",
|
|
188566
|
+
description: "Opt-in memory palace experiment flag for disposable local listener runs. Disabled by default; no behavior changes unless consumers gate on it.",
|
|
188567
|
+
envVar: "LETTA_MEMORY_PALACE"
|
|
188568
|
+
},
|
|
188520
188569
|
{
|
|
188521
188570
|
id: "reflection_arena",
|
|
188522
188571
|
label: "reflection arena",
|
|
@@ -198050,6 +198099,7 @@ var init_protocol_inbound = __esm(() => {
|
|
|
198050
198099
|
EXPERIMENT_IDS = new Set([
|
|
198051
198100
|
"conversation_titles",
|
|
198052
198101
|
"desktop_conversation_bootstrap",
|
|
198102
|
+
"memory_palace",
|
|
198053
198103
|
"tui_cron"
|
|
198054
198104
|
]);
|
|
198055
198105
|
});
|
|
@@ -213145,7 +213195,7 @@ class CodexAppServerClient {
|
|
|
213145
213195
|
await this.request("initialize", {
|
|
213146
213196
|
clientInfo: {
|
|
213147
213197
|
name: "letta-code",
|
|
213148
|
-
version: "0.33.
|
|
213198
|
+
version: "0.33.8"
|
|
213149
213199
|
},
|
|
213150
213200
|
capabilities: null
|
|
213151
213201
|
});
|
|
@@ -218304,6 +218354,7 @@ __export(exports_skills2, {
|
|
|
218304
218354
|
getBundledSkills: () => getBundledSkills,
|
|
218305
218355
|
getAgentSkillsDir: () => getAgentSkillsDir,
|
|
218306
218356
|
formatSkillsAsSystemReminder: () => formatSkillsAsSystemReminder,
|
|
218357
|
+
enabledSkillExperiments: () => enabledSkillExperiments,
|
|
218307
218358
|
discoverSkills: () => discoverSkills,
|
|
218308
218359
|
compareSkills: () => compareSkills,
|
|
218309
218360
|
SKILLS_DIR: () => SKILLS_DIR,
|
|
@@ -218359,7 +218410,14 @@ function isModelInvocableSkill(skill) {
|
|
|
218359
218410
|
function isUserInvocableSkill(skill) {
|
|
218360
218411
|
return skill.userInvocable !== false;
|
|
218361
218412
|
}
|
|
218413
|
+
function enabledSkillExperiments() {
|
|
218414
|
+
return [...new Set(EXPERIMENT_BUNDLED_SKILLS.values())].filter((id2) => experimentManager.isEnabled(id2)).sort().join(",");
|
|
218415
|
+
}
|
|
218362
218416
|
function isSkillAvailableForAgent(skill, agentId) {
|
|
218417
|
+
const experiment = skill.source === "bundled" ? EXPERIMENT_BUNDLED_SKILLS.get(skill.id) : undefined;
|
|
218418
|
+
if (experiment && !experimentManager.isEnabled(experiment)) {
|
|
218419
|
+
return false;
|
|
218420
|
+
}
|
|
218363
218421
|
if (skill.source === "bundled" && agentId && isLocalAgentId(agentId) && LOCAL_AGENT_EXCLUDED_BUNDLED_SKILLS.has(skill.id)) {
|
|
218364
218422
|
return false;
|
|
218365
218423
|
}
|
|
@@ -218423,7 +218481,7 @@ async function discoverSkills(projectSkillsPath = join61(process.cwd(), SKILLS_D
|
|
|
218423
218481
|
}
|
|
218424
218482
|
}
|
|
218425
218483
|
return {
|
|
218426
|
-
skills: Array.from(skillsById.values()).sort(compareSkills),
|
|
218484
|
+
skills: Array.from(skillsById.values()).filter((skill) => isSkillAvailableForAgent(skill, agentId)).sort(compareSkills),
|
|
218427
218485
|
errors: allErrors
|
|
218428
218486
|
};
|
|
218429
218487
|
}
|
|
@@ -218531,14 +218589,18 @@ ${lines.join(`
|
|
|
218531
218589
|
`)}
|
|
218532
218590
|
</system-reminder>`;
|
|
218533
218591
|
}
|
|
218534
|
-
var LOCAL_AGENT_EXCLUDED_BUNDLED_SKILLS, PROJECT_SKILLS_DIR, SKILLS_DIR = ".skills", GLOBAL_SKILLS_DIR;
|
|
218592
|
+
var LOCAL_AGENT_EXCLUDED_BUNDLED_SKILLS, EXPERIMENT_BUNDLED_SKILLS, PROJECT_SKILLS_DIR, SKILLS_DIR = ".skills", GLOBAL_SKILLS_DIR;
|
|
218535
218593
|
var init_skills5 = __esm(() => {
|
|
218594
|
+
init_manager();
|
|
218536
218595
|
init_skill_sources();
|
|
218537
218596
|
LOCAL_AGENT_EXCLUDED_BUNDLED_SKILLS = new Set([
|
|
218538
218597
|
"image-generation",
|
|
218539
218598
|
"managing-shared-memory",
|
|
218540
218599
|
"working-across-computers"
|
|
218541
218600
|
]);
|
|
218601
|
+
EXPERIMENT_BUNDLED_SKILLS = new Map([
|
|
218602
|
+
["curating-memory-palace", "memory_palace"]
|
|
218603
|
+
]);
|
|
218542
218604
|
PROJECT_SKILLS_DIR = join61(".agents", "skills");
|
|
218543
218605
|
GLOBAL_SKILLS_DIR = join61(process.env.HOME || process.env.USERPROFILE || "~", ".letta/skills");
|
|
218544
218606
|
});
|
|
@@ -228048,7 +228110,8 @@ function computeCacheKey(components) {
|
|
|
228048
228110
|
components.primaryProjectSkillsDirectory,
|
|
228049
228111
|
[...components.memorySkillsDirs].sort().join(","),
|
|
228050
228112
|
[...components.sharedMemorySkillsDirs].sort().join(","),
|
|
228051
|
-
components.sharedMemoryErrors.map((error4) => `${error4.path}:${error4.message}`).sort().join(",")
|
|
228113
|
+
components.sharedMemoryErrors.map((error4) => `${error4.path}:${error4.message}`).sort().join(","),
|
|
228114
|
+
components.skillExperiments
|
|
228052
228115
|
].join("|");
|
|
228053
228116
|
}
|
|
228054
228117
|
function getSkillRoots(components) {
|
|
@@ -228341,7 +228404,8 @@ async function buildClientSkillsPayload(options = {}) {
|
|
|
228341
228404
|
primaryProjectSkillsDirectory,
|
|
228342
228405
|
memorySkillsDirs,
|
|
228343
228406
|
sharedMemorySkillsDirs: sharedMemoryContext.skillsDirs,
|
|
228344
|
-
sharedMemoryErrors: sharedMemoryContext.errors
|
|
228407
|
+
sharedMemoryErrors: sharedMemoryContext.errors,
|
|
228408
|
+
skillExperiments: enabledSkillExperiments()
|
|
228345
228409
|
};
|
|
228346
228410
|
const cacheKey = computeCacheKey(cacheComponents);
|
|
228347
228411
|
if (useCache) {
|
|
@@ -412478,12 +412542,12 @@ function rowToolCalls(row, index, diagnostics2) {
|
|
|
412478
412542
|
}
|
|
412479
412543
|
return calls;
|
|
412480
412544
|
}
|
|
412481
|
-
function
|
|
412545
|
+
function contentText2(content) {
|
|
412482
412546
|
if (typeof content === "string") {
|
|
412483
412547
|
if (content.startsWith(CONTENT_JSON_PREFIX)) {
|
|
412484
412548
|
const encoded = content.slice(CONTENT_JSON_PREFIX.length);
|
|
412485
412549
|
try {
|
|
412486
|
-
return
|
|
412550
|
+
return contentText2(JSON.parse(encoded));
|
|
412487
412551
|
} catch {
|
|
412488
412552
|
return encoded;
|
|
412489
412553
|
}
|
|
@@ -412569,7 +412633,7 @@ var init_hermes = __esm(() => {
|
|
|
412569
412633
|
});
|
|
412570
412634
|
};
|
|
412571
412635
|
if (row.role === "user") {
|
|
412572
|
-
const content =
|
|
412636
|
+
const content = contentText2(row.content);
|
|
412573
412637
|
if (content) {
|
|
412574
412638
|
emit({
|
|
412575
412639
|
type: "message",
|
|
@@ -412589,7 +412653,7 @@ var init_hermes = __esm(() => {
|
|
|
412589
412653
|
...timestamp ? { timestamp } : {}
|
|
412590
412654
|
});
|
|
412591
412655
|
}
|
|
412592
|
-
const content =
|
|
412656
|
+
const content = contentText2(row.content);
|
|
412593
412657
|
if (content) {
|
|
412594
412658
|
emit({
|
|
412595
412659
|
type: "message",
|
|
@@ -412612,7 +412676,7 @@ var init_hermes = __esm(() => {
|
|
|
412612
412676
|
if (row.role === "tool") {
|
|
412613
412677
|
emit({
|
|
412614
412678
|
type: "tool_result",
|
|
412615
|
-
content:
|
|
412679
|
+
content: contentText2(row.content),
|
|
412616
412680
|
...typeof row.tool_call_id === "string" && row.tool_call_id ? { callId: row.tool_call_id } : {},
|
|
412617
412681
|
...timestamp ? { timestamp } : {}
|
|
412618
412682
|
});
|
|
@@ -445266,7 +445330,7 @@ function createTransport2(config2, options) {
|
|
|
445266
445330
|
return new StreamableHTTPClientTransport(new URL(config2.url), {
|
|
445267
445331
|
requestInit: headersRequestInit(headers),
|
|
445268
445332
|
authProvider: options.oauth?.authProvider,
|
|
445269
|
-
fetch: abortAwareFetch(options.signal)
|
|
445333
|
+
fetch: abortAwareFetch(options.signal, undefined, options.fetch)
|
|
445270
445334
|
});
|
|
445271
445335
|
}
|
|
445272
445336
|
if (config2.transport === "sse") {
|
|
@@ -445275,7 +445339,7 @@ function createTransport2(config2, options) {
|
|
|
445275
445339
|
return new SSEClientTransport(new URL(config2.url), {
|
|
445276
445340
|
requestInit,
|
|
445277
445341
|
authProvider: options.oauth?.authProvider,
|
|
445278
|
-
fetch: abortAwareFetch(options.signal, headers)
|
|
445342
|
+
fetch: abortAwareFetch(options.signal, headers, options.fetch)
|
|
445279
445343
|
});
|
|
445280
445344
|
}
|
|
445281
445345
|
return new StdioClientTransport({
|
|
@@ -445286,13 +445350,14 @@ function createTransport2(config2, options) {
|
|
|
445286
445350
|
stderr: options.stderr ?? "inherit"
|
|
445287
445351
|
});
|
|
445288
445352
|
}
|
|
445289
|
-
function abortAwareFetch(operationSignal2, headers) {
|
|
445353
|
+
function abortAwareFetch(operationSignal2, headers, fetchFn) {
|
|
445290
445354
|
if (!operationSignal2 && !headers)
|
|
445291
|
-
return;
|
|
445355
|
+
return fetchFn;
|
|
445356
|
+
const request = fetchFn ?? fetch;
|
|
445292
445357
|
return (url2, init) => {
|
|
445293
445358
|
const requestInit = headers ? mergeHeaders4(init, headers) : { ...init };
|
|
445294
445359
|
const requestSignal3 = requestInit.signal ?? undefined;
|
|
445295
|
-
return
|
|
445360
|
+
return request(url2, {
|
|
445296
445361
|
...requestInit,
|
|
445297
445362
|
signal: operationSignal2 && requestSignal3 ? AbortSignal.any([operationSignal2, requestSignal3]) : operationSignal2 ?? requestSignal3
|
|
445298
445363
|
});
|
|
@@ -445344,7 +445409,7 @@ var init_mcp_client = __esm(() => {
|
|
|
445344
445409
|
init_streamableHttp();
|
|
445345
445410
|
DEFAULT_CLIENT_INFO = {
|
|
445346
445411
|
name: "letta-code",
|
|
445347
|
-
version: "0.33.
|
|
445412
|
+
version: "0.33.8"
|
|
445348
445413
|
};
|
|
445349
445414
|
});
|
|
445350
445415
|
|
|
@@ -513196,4 +513261,4 @@ function registerBunOAuthFlows() {
|
|
|
513196
513261
|
registerBunOAuthFlows();
|
|
513197
513262
|
await init_src5().then(() => exports_src2);
|
|
513198
513263
|
|
|
513199
|
-
//# debugId=
|
|
513264
|
+
//# debugId=7B5F416253AF257964756E2164756E21
|
package/package.json
CHANGED
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: curating-memory-palace
|
|
3
|
+
description: Curates the Memory Palace, a one-page view in palace/ where the user reviews and acts on agent state. Use whenever you have something the user should review in one place, such as tasks, suggested improvements, open questions, follow-ups, blockers, or changes in your understanding; during reflection; when asked to set up or update the Palace; and when handling a Palace action or reply.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Curating the Memory Palace
|
|
7
|
+
|
|
8
|
+
Treat the Memory Palace as a command center for state: make your ongoing understanding, commitments, and possibilities legible to the user, and let them influence it through actions and replies. Desktop shows it on the Palace tab of the Memory page.
|
|
9
|
+
|
|
10
|
+
Choose contents that fit the agent and its relationship with the user. A companion might share relational understanding, shared interests, or unresolved questions. A work agent might surface pending work, proactively identified issues, or tasks it can resume. Neither is the universal template.
|
|
11
|
+
|
|
12
|
+
Show meaningful current state, not a transcript recap or a page about maintaining the Palace itself. Keep it concise without forcing everything into a task list.
|
|
13
|
+
|
|
14
|
+
## When to write to it
|
|
15
|
+
|
|
16
|
+
The Palace is where you put things for the user to review. Update it as you go, not only when asked:
|
|
17
|
+
|
|
18
|
+
- **During work:** when you notice a task, an improvement you could make, a question only the user can answer, a blocker, or a follow-up, add it to the right section. Mention it in the conversation too if it matters now.
|
|
19
|
+
- **During reflection:** check the Palace against what happened. Add new items, update changed ones, and remove items that are done, stale, or dismissed.
|
|
20
|
+
- **When the user asks** to set up or update the Palace: set up means build a first Palace from what you already know; update means bring every section current.
|
|
21
|
+
- **After a Palace action or reply:** update the section it came from.
|
|
22
|
+
|
|
23
|
+
Skip it for things that only matter inside the current conversation.
|
|
24
|
+
|
|
25
|
+
## Files
|
|
26
|
+
|
|
27
|
+
The Palace is the `palace/` folder in your memory.
|
|
28
|
+
|
|
29
|
+
- Each Markdown file directly inside `palace/` is one section, except `palace/MEMORY.md`. Nested folders and other files are not shown.
|
|
30
|
+
- The section title comes from the file name: `needs-attention.md` shows as "Needs Attention". Pick file names that read well as titles, and keep `name` the same as the title.
|
|
31
|
+
- Frontmatter holds exactly `name` and `description`, like every memory file. MemFS rejects any other key. The description shows under the title, so write it as the section's purpose in one short line.
|
|
32
|
+
- The body is Markdown. The date beside the title is the file's last commit.
|
|
33
|
+
|
|
34
|
+
Example `palace/needs-attention.md`:
|
|
35
|
+
|
|
36
|
+
````markdown
|
|
37
|
+
---
|
|
38
|
+
name: Needs Attention
|
|
39
|
+
description: Decisions and follow-ups that need the user.
|
|
40
|
+
---
|
|
41
|
+
**The staging deploy is blocked on a secret.** `SLACK_SIGNING_SECRET` is not in 1Password yet, so the Atlantis plan fails.
|
|
42
|
+
|
|
43
|
+
```palace-action
|
|
44
|
+
{"actionId": "add-secret", "label": "Walk me through adding it", "instruction": "List the exact 1Password and Terraform steps"}
|
|
45
|
+
```
|
|
46
|
+
````
|
|
47
|
+
|
|
48
|
+
## Order
|
|
49
|
+
|
|
50
|
+
`palace/MEMORY.md` is the folder's index, and it sets the order. List the sections in the order you want them shown. Relative links such as `[Overview](overview.md)` work, and so do `./overview.md` and `palace/overview.md`. The first mention of a file decides its place. Sections you leave out come after, in file-name order.
|
|
51
|
+
|
|
52
|
+
Like every `MEMORY.md`, it has no frontmatter:
|
|
53
|
+
|
|
54
|
+
```markdown
|
|
55
|
+
# Memory Palace
|
|
56
|
+
|
|
57
|
+
State worth understanding, discussing, or acting on. Choose sections for this user; these are examples, not required categories.
|
|
58
|
+
|
|
59
|
+
- [Needs Attention](needs-attention.md) - Decisions and follow-ups that need the user
|
|
60
|
+
- [Suggestions](suggestions.md) - Next steps worth taking
|
|
61
|
+
- [Recently Learned](recently-learned.md) - What changed in my understanding
|
|
62
|
+
- [Overview](overview.md) - Who I am and what I am working on
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
## Icons
|
|
66
|
+
|
|
67
|
+
Each section gets an icon picked from its title. Titles with "attention" or "blocker" get a flag, "overview" or "summary" a house, "learned" or "insight" a lightbulb, and "suggestions" or "next steps" a bolt. Other titles get a note icon.
|
|
68
|
+
|
|
69
|
+
## Action buttons
|
|
70
|
+
|
|
71
|
+
A `palace-action` code block becomes a button. It holds one strict JSON object:
|
|
72
|
+
|
|
73
|
+
```palace-action
|
|
74
|
+
{"actionId": "review-pr", "label": "Review the PR", "conversationId": "new", "instruction": "Review PR 123 and list the blocking issues"}
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
- `actionId` (required): 1 to 64 characters, no spaces. Unique within the section.
|
|
78
|
+
- `label` (required): the button text, up to 80 characters. Start it with a verb.
|
|
79
|
+
- `instruction` (optional): what you should do when it is clicked, up to 300 characters.
|
|
80
|
+
- `conversationId` (optional): one of your conversation ids, or `new` for a fresh conversation. Leave it out to use the main chat.
|
|
81
|
+
|
|
82
|
+
Any other key, or invalid JSON, shows the block as code with an error instead of a button. Action blocks next to each other share one row.
|
|
83
|
+
|
|
84
|
+
When the user clicks a button, Desktop opens the target conversation and sends you one message. A hidden system reminder in it names the action, the section's path, and the section's current content. Do what the label and instruction ask, in that conversation.
|
|
85
|
+
|
|
86
|
+
## Replies
|
|
87
|
+
|
|
88
|
+
Every section has a Reply button. The user's note arrives in the main chat, or in the conversation named by the section's first action. A hidden system reminder in the message holds the section's path and content. Treat the note as feedback on that section:
|
|
89
|
+
|
|
90
|
+
- **Dismissal** ("drop this", "I don't care about X"): remove that item from the file. If the section is then empty, say so in one line, such as "Nothing needs you right now.", or delete the file and its index line. Don't bring the item back unless something important changes. Note the preference in memory so later updates don't add it again.
|
|
91
|
+
- **Correction**: fix the section.
|
|
92
|
+
- **Question**: answer in the conversation, and update the section if the answer changes it.
|
|
93
|
+
|
|
94
|
+
Then reply briefly with what you changed.
|
|
95
|
+
|
|
96
|
+
## Writing a good Palace
|
|
97
|
+
|
|
98
|
+
- Let sections reflect what matters in this relationship. Do not fill a fixed template or invent content to reach a section count.
|
|
99
|
+
- Lead with the point and enough context to understand it. Prefer short sections; use headlines where they help scanning.
|
|
100
|
+
- Keep state current. Remove stale items and empty categories unless their absence is itself useful information.
|
|
101
|
+
- Distinguish what the user told you, what you infer, and what you propose. Do not present interpretations as facts or possible work as already underway.
|
|
102
|
+
- Make continuation offers concrete: name the unfinished work and the next step, not just "I can continue."
|
|
103
|
+
- Add a button only for a useful, specific action. Understanding or correcting your state can be the whole purpose of a section; Reply is enough.
|
|
104
|
+
- Never put secrets, tokens, or keys in the Palace. It is shown in the app and sent in messages.
|
|
105
|
+
- Don't repeat an item in two sections.
|