feat: update skills (migrating-memory, agent-finder, message-search) (#458)

Co-authored-by: Letta <noreply@letta.com>
This commit is contained in:
Charles Packer
2026-01-04 16:31:32 -08:00
committed by GitHub
parent d0d45cba5a
commit 9b039b7249
16 changed files with 1482 additions and 146 deletions

View File

@@ -270,7 +270,9 @@ export async function skill(args: SkillArgs): Promise<SkillResult> {
const skillsToProcess = skillIds as string[];
if (command === "load") {
// Load skills
// Load skills - track which ones were prepared successfully
const preparedSkills: string[] = [];
for (const skillId of skillsToProcess) {
if (loadedSkillIds.includes(skillId)) {
results.push(`"${skillId}" already loaded`);
@@ -288,15 +290,21 @@ export async function skill(args: SkillArgs): Promise<SkillResult> {
// Build skill header with optional path info
const skillDir = dirname(skillPath);
const pathLine = hasAdditionalFiles(skillPath)
const hasExtras = hasAdditionalFiles(skillPath);
const pathLine = hasExtras
? `# Skill Directory: ${skillDir}\n\n`
: "";
// Replace <SKILL_DIR> placeholder with actual path in skill content
const processedContent = hasExtras
? skillContent.replace(/<SKILL_DIR>/g, skillDir)
: skillContent;
// Append new skill
const separator = currentValue ? "\n\n---\n\n" : "";
currentValue = `${currentValue}${separator}# Skill: ${skillId}\n${pathLine}${skillContent}`;
currentValue = `${currentValue}${separator}# Skill: ${skillId}\n${pathLine}${processedContent}`;
loadedSkillIds.push(skillId);
results.push(`"${skillId}" loaded`);
preparedSkills.push(skillId);
} catch (error) {
results.push(
`"${skillId}" failed: ${error instanceof Error ? error.message : String(error)}`,
@@ -304,14 +312,19 @@ export async function skill(args: SkillArgs): Promise<SkillResult> {
}
}
// Update the block
await client.agents.blocks.update("loaded_skills", {
agent_id: agentId,
value: currentValue,
});
// Update the block - only report success AFTER the update succeeds
if (preparedSkills.length > 0) {
await client.agents.blocks.update("loaded_skills", {
agent_id: agentId,
value: currentValue,
});
// Update the cached flag
if (loadedSkillIds.length > 0) {
// Now we can report success
for (const skillId of preparedSkills) {
results.push(`"${skillId}" loaded`);
}
// Update the cached flag
setHasLoadedSkills(true);
}
} else {

View File

@@ -1,12 +1,14 @@
/**
* Shell environment utilities
* Provides enhanced environment variables for shell execution,
* including bundled tools like ripgrep in PATH.
* including bundled tools like ripgrep in PATH and Letta context for skill scripts.
*/
import { createRequire } from "node:module";
import * as path from "node:path";
import { fileURLToPath } from "node:url";
import { getCurrentAgentId } from "../../agent/context";
import { settingsManager } from "../../settings-manager";
/**
* Get the directory containing the bundled ripgrep binary.
@@ -26,7 +28,7 @@ function getRipgrepBinDir(): string | undefined {
/**
* Get enhanced environment variables for shell execution.
* Includes bundled tools (like ripgrep) in PATH.
* Includes bundled tools (like ripgrep) in PATH and Letta context for skill scripts.
*/
export function getShellEnv(): NodeJS.ProcessEnv {
const env = { ...process.env };
@@ -38,5 +40,24 @@ export function getShellEnv(): NodeJS.ProcessEnv {
env.PATH = `${rgBinDir}${path.delimiter}${currentPath}`;
}
// Add Letta context for skill scripts
try {
env.LETTA_AGENT_ID = getCurrentAgentId();
} catch {
// Context not set yet (e.g., during startup), skip
}
// Inject API key from settings if not already in env
if (!env.LETTA_API_KEY) {
try {
const settings = settingsManager.getSettings();
if (settings.env?.LETTA_API_KEY) {
env.LETTA_API_KEY = settings.env.LETTA_API_KEY;
}
} catch {
// Settings not initialized yet, skip
}
}
return env;
}