feat: add --no-skills flag to disable bundled skills (#948)

Co-authored-by: Letta <noreply@letta.com>
This commit is contained in:
Devansh Jain
2026-02-12 18:26:46 -08:00
committed by GitHub
parent 3a93ea2f38
commit 415b1a403b
5 changed files with 39 additions and 9 deletions

View File

@@ -6,6 +6,7 @@
interface AgentContext {
agentId: string | null;
skillsDirectory: string | null;
noSkills: boolean;
conversationId: string | null;
}
@@ -23,6 +24,7 @@ function getContext(): AgentContext {
global[CONTEXT_KEY] = {
agentId: null,
skillsDirectory: null,
noSkills: false,
conversationId: null,
};
}
@@ -35,13 +37,16 @@ const context = getContext();
* Set the current agent context
* @param agentId - The agent ID
* @param skillsDirectory - Optional skills directory path
* @param noSkills - Whether to skip bundled skills
*/
export function setAgentContext(
agentId: string,
skillsDirectory?: string,
noSkills?: boolean,
): void {
context.agentId = agentId;
context.skillsDirectory = skillsDirectory || null;
context.noSkills = noSkills ?? false;
}
/**
@@ -70,6 +75,13 @@ export function getSkillsDirectory(): string | null {
return context.skillsDirectory;
}
/**
* Get whether bundled skills should be skipped
*/
export function getNoSkills(): boolean {
return context.noSkills;
}
/**
* Set the current conversation ID
* @param conversationId - The conversation ID, or null to clear

View File

@@ -167,14 +167,17 @@ async function discoverSkillsFromDir(
export async function discoverSkills(
projectSkillsPath: string = join(process.cwd(), SKILLS_DIR),
agentId?: string,
options?: { skipBundled?: boolean },
): Promise<SkillDiscoveryResult> {
const allErrors: SkillDiscoveryError[] = [];
const skillsById = new Map<string, Skill>();
// 1. Start with bundled skills (lowest priority)
const bundledSkills = await getBundledSkills();
for (const skill of bundledSkills) {
skillsById.set(skill.id, skill);
if (!options?.skipBundled) {
const bundledSkills = await getBundledSkills();
for (const skill of bundledSkills) {
skillsById.set(skill.id, skill);
}
}
// 2. Add global skills (override bundled)

View File

@@ -8074,10 +8074,14 @@ ${SYSTEM_REMINDER_CLOSE}
try {
const { discoverSkills: discover, SKILLS_DIR: defaultDir } =
await import("../agent/skills");
const { getSkillsDirectory } = await import("../agent/context");
const { getSkillsDirectory, getNoSkills } = await import(
"../agent/context"
);
const skillsDir =
getSkillsDirectory() || join(process.cwd(), defaultDir);
const { skills } = await discover(skillsDir, agentId);
const { skills } = await discover(skillsDir, agentId, {
skipBundled: getNoSkills(),
});
discoveredSkillsRef.current = skills;
} catch {
discoveredSkillsRef.current = [];

View File

@@ -79,6 +79,7 @@ export async function handleHeadlessCommand(
argv: string[],
model?: string,
skillsDirectory?: string,
noSkills?: boolean,
) {
const settings = settingsManager.getSettings();
@@ -125,6 +126,7 @@ export async function handleHeadlessCommand(
memfs: { type: "boolean" },
"no-memfs": { type: "boolean" },
"no-skills": { type: "boolean" },
"max-turns": { type: "string" }, // Maximum number of agentic turns
},
strict: false,
@@ -807,7 +809,7 @@ export async function handleHeadlessCommand(
}
// Set agent context for tools that need it (e.g., Skill tool, Task tool)
setAgentContext(agent.id, skillsDirectory);
setAgentContext(agent.id, skillsDirectory, noSkills);
// Validate output format
const outputFormat =
@@ -1071,7 +1073,9 @@ ${SYSTEM_REMINDER_CLOSE}
const { join } = await import("node:path");
try {
const skillsDir = getSkillsDirectory() || join(process.cwd(), defaultDir);
const { skills } = await discoverSkills(skillsDir, agent.id);
const { skills } = await discoverSkills(skillsDir, agent.id, {
skipBundled: noSkills,
});
const skillsReminder = formatSkillsAsSystemReminder(skills);
if (skillsReminder) {
pushPart(skillsReminder);

View File

@@ -442,6 +442,7 @@ async function main(): Promise<void> {
memfs: { type: "boolean" },
"no-memfs": { type: "boolean" },
"no-skills": { type: "boolean" },
"max-turns": { type: "string" },
},
strict: true,
@@ -553,6 +554,7 @@ async function main(): Promise<void> {
const skillsDirectory = (values.skills as string | undefined) ?? undefined;
const memfsFlag = values.memfs as boolean | undefined;
const noMemfsFlag = values["no-memfs"] as boolean | undefined;
const noSkillsFlag = values["no-skills"] as boolean | undefined;
const fromAfFile =
(values.import as string | undefined) ??
(values["from-af"] as string | undefined);
@@ -946,7 +948,12 @@ async function main(): Promise<void> {
markMilestone("TOOLS_LOADED");
const { handleHeadlessCommand } = await import("./headless");
await handleHeadlessCommand(process.argv, specifiedModel, skillsDirectory);
await handleHeadlessCommand(
process.argv,
specifiedModel,
skillsDirectory,
noSkillsFlag,
);
return;
}
@@ -1679,7 +1686,7 @@ async function main(): Promise<void> {
}
// Set agent context for tools that need it (e.g., Skill tool)
setAgentContext(agent.id, skillsDirectory);
setAgentContext(agent.id, skillsDirectory, noSkillsFlag);
// Apply memfs flag if explicitly specified (memfs is opt-in via /memfs enable or --memfs)
const isSubagent = process.env.LETTA_CODE_AGENT_ROLE === "subagent";