chore: Add --system flag for existing agents + update system prompt variable names (#328)

This commit is contained in:
Devansh Jain
2025-12-19 17:16:21 -08:00
committed by GitHub
parent f9bffaed81
commit 7d73219c50
6 changed files with 127 additions and 59 deletions

View File

@@ -53,7 +53,7 @@ export async function createAgent(
skillsDirectory?: string,
parallelToolCalls = true,
enableSleeptime = false,
systemPrompt?: string,
systemPromptId?: string,
initBlocks?: string[],
baseTools?: string[],
) {
@@ -202,13 +202,13 @@ export async function createAgent(
const modelUpdateArgs = getModelUpdateArgs(modelHandle);
const contextWindow = (modelUpdateArgs?.context_window as number) || 200_000;
// Resolve system prompt (ID, subagent name, or literal content)
const resolvedSystemPrompt = await resolveSystemPrompt(systemPrompt);
// Resolve system prompt ID to content
const systemPromptContent = await resolveSystemPrompt(systemPromptId);
// Create agent with all block IDs (existing + newly created)
const agent = await client.agents.create({
agent_type: "letta_v1_agent" as AgentType,
system: resolvedSystemPrompt,
system: systemPromptContent,
name,
description: `Letta Code agent created in ${process.cwd()}`,
embedding: embeddingModel,

View File

@@ -2,6 +2,7 @@
// Utilities for modifying agent configuration
import type {
AgentState,
AnthropicModelSettings,
GoogleAIModelSettings,
OpenAIModelSettings,
@@ -316,21 +317,21 @@ export interface SystemPromptUpdateResult {
}
/**
* Updates an agent's system prompt.
* Updates an agent's system prompt with raw content.
*
* @param agentId - The agent ID
* @param systemPrompt - The new system prompt content
* @param systemPromptContent - The raw system prompt content to update
* @returns Result with success status and message
*/
export async function updateAgentSystemPrompt(
export async function updateAgentSystemPromptRaw(
agentId: string,
systemPrompt: string,
systemPromptContent: string,
): Promise<SystemPromptUpdateResult> {
try {
const client = await getClient();
await client.agents.update(agentId, {
system: systemPrompt,
system: systemPromptContent,
});
return {
@@ -344,3 +345,58 @@ export async function updateAgentSystemPrompt(
};
}
}
/**
* Result from updating a system prompt on an agent
*/
export interface UpdateSystemPromptResult {
success: boolean;
message: string;
agent: AgentState | null;
}
/**
* Updates an agent's system prompt by ID or subagent name.
* Resolves the ID to content, updates the agent, and returns the refreshed agent state.
*
* @param agentId - The agent ID to update
* @param systemPromptId - System prompt ID (e.g., "codex") or subagent name (e.g., "explore")
* @returns Result with success status, message, and updated agent state
*/
export async function updateAgentSystemPrompt(
agentId: string,
systemPromptId: string,
): Promise<UpdateSystemPromptResult> {
try {
const { resolveSystemPrompt } = await import("./promptAssets");
const systemPromptContent = await resolveSystemPrompt(systemPromptId);
const updateResult = await updateAgentSystemPromptRaw(
agentId,
systemPromptContent,
);
if (!updateResult.success) {
return {
success: false,
message: updateResult.message,
agent: null,
};
}
// Re-fetch agent to get updated state
const client = await getClient();
const agent = await client.agents.retrieve(agentId);
return {
success: true,
message: "System prompt applied successfully",
agent,
};
} catch (error) {
return {
success: false,
message: `Failed to apply system prompt: ${error instanceof Error ? error.message : String(error)}`,
agent: null,
};
}
}

View File

@@ -99,26 +99,26 @@ export const SYSTEM_PROMPTS: SystemPromptOption[] = [
];
/**
* Resolve a system prompt string to its content.
* Resolve a system prompt ID to its content.
*
* Resolution order:
* 1. If it matches a systemPromptId from SYSTEM_PROMPTS, use its content
* 1. If it matches an ID from SYSTEM_PROMPTS, use its content
* 2. If it matches a subagent name, use that subagent's system prompt
* 3. Otherwise, use the default system prompt
*
* @param systemPromptInput - The system prompt ID or subagent name
* @param systemPromptId - The system prompt ID (e.g., "codex") or subagent name (e.g., "explore")
* @returns The resolved system prompt content
*/
export async function resolveSystemPrompt(
systemPromptInput: string | undefined,
systemPromptId: string | undefined,
): Promise<string> {
// No input - use default
if (!systemPromptInput) {
if (!systemPromptId) {
return SYSTEM_PROMPT;
}
// 1. Check if it matches a system prompt ID
const matchedPrompt = SYSTEM_PROMPTS.find((p) => p.id === systemPromptInput);
const matchedPrompt = SYSTEM_PROMPTS.find((p) => p.id === systemPromptId);
if (matchedPrompt) {
return matchedPrompt.content;
}
@@ -126,7 +126,7 @@ export async function resolveSystemPrompt(
// 2. Check if it matches a subagent name
const { getAllSubagentConfigs } = await import("./subagents");
const subagentConfigs = await getAllSubagentConfigs();
const matchedSubagent = subagentConfigs[systemPromptInput];
const matchedSubagent = subagentConfigs[systemPromptId];
if (matchedSubagent) {
return matchedSubagent.systemPrompt;
}

View File

@@ -3916,8 +3916,10 @@ ${recentCommits}
refreshDerived();
// Update the agent's system prompt
const { updateAgentSystemPrompt } = await import("../agent/modify");
const result = await updateAgentSystemPrompt(
const { updateAgentSystemPromptRaw } = await import(
"../agent/modify"
);
const result = await updateAgentSystemPromptRaw(
agentId,
selectedPrompt.content,
);

View File

@@ -115,7 +115,7 @@ export async function handleHeadlessCommand(
const specifiedAgentId = values.agent as string | undefined;
const shouldContinue = values.continue as boolean | undefined;
const forceNew = values.new as boolean | undefined;
const specifiedSystem = values.system as string | undefined;
const systemPromptId = values.system as string | undefined;
const initBlocksRaw = values["init-blocks"] as string | undefined;
const baseToolsRaw = values["base-tools"] as string | undefined;
const sleeptimeFlag = (values.sleeptime as boolean | undefined) ?? undefined;
@@ -209,7 +209,7 @@ export async function handleHeadlessCommand(
skillsDirectory,
true, // parallelToolCalls always enabled
sleeptimeFlag ?? settings.enableSleeptime,
specifiedSystem,
systemPromptId,
initBlocks,
baseTools,
);
@@ -226,7 +226,7 @@ export async function handleHeadlessCommand(
skillsDirectory,
true,
sleeptimeFlag ?? settings.enableSleeptime,
specifiedSystem,
systemPromptId,
initBlocks,
baseTools,
);
@@ -275,7 +275,7 @@ export async function handleHeadlessCommand(
skillsDirectory,
true, // parallelToolCalls always enabled
sleeptimeFlag ?? settings.enableSleeptime,
specifiedSystem,
systemPromptId,
undefined,
undefined,
);
@@ -292,7 +292,7 @@ export async function handleHeadlessCommand(
skillsDirectory,
true,
sleeptimeFlag ?? settings.enableSleeptime,
specifiedSystem,
systemPromptId,
undefined,
undefined,
);
@@ -311,7 +311,7 @@ export async function handleHeadlessCommand(
);
// If resuming and a model or system prompt was specified, apply those changes
if (isResumingAgent && (model || specifiedSystem)) {
if (isResumingAgent && (model || systemPromptId)) {
if (model) {
const { resolveModel } = await import("./agent/model");
const modelHandle = resolveModel(model);
@@ -334,19 +334,14 @@ export async function handleHeadlessCommand(
}
}
if (specifiedSystem) {
if (systemPromptId) {
const { updateAgentSystemPrompt } = await import("./agent/modify");
const { SYSTEM_PROMPTS } = await import("./agent/promptAssets");
const systemPromptOption = SYSTEM_PROMPTS.find(
(p) => p.id === specifiedSystem,
);
if (!systemPromptOption) {
console.error(`Error: Invalid system prompt "${specifiedSystem}"`);
const result = await updateAgentSystemPrompt(agent.id, systemPromptId);
if (!result.success || !result.agent) {
console.error(`Failed to update system prompt: ${result.message}`);
process.exit(1);
}
await updateAgentSystemPrompt(agent.id, systemPromptOption.content);
// Refresh agent state after system prompt update
agent = await client.agents.retrieve(agent.id);
agent = result.agent;
}
}

View File

@@ -41,7 +41,7 @@ OPTIONS
--base-tools <list> Comma-separated base tools to attach when using --new (e.g., "memory,web_search,conversation_search")
-a, --agent <id> Use a specific agent ID
-m, --model <id> Model ID or handle (e.g., "opus-4.5" or "anthropic/claude-opus-4-5")
-s, --system <id> System prompt ID (e.g., "codex", "gpt-5.1", "review")
-s, --system <id> System prompt ID or subagent name (applies to new or existing agent)
--toolset <name> Force toolset: "codex", "default", or "gemini" (overrides model-based auto-selection)
-p, --prompt Headless prompt mode
--output-format <fmt> Output format for headless mode (text, json, stream-json)
@@ -308,7 +308,7 @@ async function main(): Promise<void> {
const baseToolsRaw = values["base-tools"] as string | undefined;
const specifiedAgentId = (values.agent as string | undefined) ?? null;
const specifiedModel = (values.model as string | undefined) ?? undefined;
const specifiedSystem = (values.system as string | undefined) ?? undefined;
const systemPromptId = (values.system as string | undefined) ?? undefined;
const specifiedToolset = (values.toolset as string | undefined) ?? undefined;
const skillsDirectory = (values.skills as string | undefined) ?? undefined;
const sleeptimeFlag = (values.sleeptime as boolean | undefined) ?? undefined;
@@ -379,7 +379,7 @@ async function main(): Promise<void> {
}
// Validate system prompt if provided (can be a system prompt ID or subagent name)
if (specifiedSystem) {
if (systemPromptId) {
const { SYSTEM_PROMPTS } = await import("./agent/promptAssets");
const { getAllSubagentConfigs } = await import("./agent/subagents");
@@ -387,13 +387,13 @@ async function main(): Promise<void> {
const subagentConfigs = await getAllSubagentConfigs();
const validSubagentNames = Object.keys(subagentConfigs);
const isValidSystemPrompt = validSystemPrompts.includes(specifiedSystem);
const isValidSubagent = validSubagentNames.includes(specifiedSystem);
const isValidSystemPrompt = validSystemPrompts.includes(systemPromptId);
const isValidSubagent = validSubagentNames.includes(systemPromptId);
if (!isValidSystemPrompt && !isValidSubagent) {
const allValid = [...validSystemPrompts, ...validSubagentNames];
console.error(
`Error: Invalid system prompt "${specifiedSystem}". Must be one of: ${allValid.join(", ")}.`,
`Error: Invalid system prompt "${systemPromptId}". Must be one of: ${allValid.join(", ")}.`,
);
process.exit(1);
}
@@ -593,7 +593,7 @@ async function main(): Promise<void> {
baseTools,
agentIdArg,
model,
system,
systemPromptId,
toolset,
skillsDirectory,
fromAfFile,
@@ -604,7 +604,7 @@ async function main(): Promise<void> {
baseTools?: string[];
agentIdArg: string | null;
model?: string;
system?: string;
systemPromptId?: string;
toolset?: "codex" | "default" | "gemini";
skillsDirectory?: string;
fromAfFile?: string;
@@ -763,7 +763,24 @@ async function main(): Promise<void> {
if (!agent && agentIdArg) {
try {
agent = await client.agents.retrieve(agentIdArg);
// console.log(`Using agent ${agentIdArg}...`);
// Apply --system flag to existing agent if provided
if (systemPromptId) {
const { updateAgentSystemPrompt } = await import(
"./agent/modify"
);
const result = await updateAgentSystemPrompt(
agent.id,
systemPromptId,
);
if (!result.success || !result.agent) {
console.error(
`Failed to update system prompt: ${result.message}`,
);
process.exit(1);
}
agent = result.agent;
}
} catch (error) {
console.error(
`Agent ${agentIdArg} not found (error: ${JSON.stringify(error)})`,
@@ -788,7 +805,7 @@ async function main(): Promise<void> {
skillsDirectory,
true, // parallelToolCalls always enabled
sleeptimeFlag ?? settings.enableSleeptime,
system,
systemPromptId,
initBlocks,
baseTools,
);
@@ -810,7 +827,7 @@ async function main(): Promise<void> {
skillsDirectory,
true,
sleeptimeFlag ?? settings.enableSleeptime,
system,
systemPromptId,
initBlocks,
baseTools,
);
@@ -865,7 +882,7 @@ async function main(): Promise<void> {
skillsDirectory,
true, // parallelToolCalls always enabled
sleeptimeFlag ?? settings.enableSleeptime,
system,
systemPromptId,
undefined,
undefined,
);
@@ -887,7 +904,7 @@ async function main(): Promise<void> {
skillsDirectory,
true,
sleeptimeFlag ?? settings.enableSleeptime,
system,
systemPromptId,
undefined,
undefined,
);
@@ -968,7 +985,7 @@ async function main(): Promise<void> {
setIsResumingSession(resuming);
// If resuming and a model or system prompt was specified, apply those changes
if (resuming && (model || system)) {
if (resuming && (model || systemPromptId)) {
if (model) {
const { resolveModel } = await import("./agent/model");
const modelHandle = resolveModel(model);
@@ -992,19 +1009,17 @@ async function main(): Promise<void> {
}
}
if (system) {
if (systemPromptId) {
const { updateAgentSystemPrompt } = await import("./agent/modify");
const { SYSTEM_PROMPTS } = await import("./agent/promptAssets");
const systemPromptOption = SYSTEM_PROMPTS.find(
(p) => p.id === system,
const result = await updateAgentSystemPrompt(
agent.id,
systemPromptId,
);
if (!systemPromptOption) {
console.error(`Error: Invalid system prompt "${system}"`);
if (!result.success || !result.agent) {
console.error(`Error: ${result.message}`);
process.exit(1);
}
await updateAgentSystemPrompt(agent.id, systemPromptOption.content);
// Refresh agent state after system prompt update
agent = await client.agents.retrieve(agent.id);
agent = result.agent;
}
}
@@ -1035,7 +1050,7 @@ async function main(): Promise<void> {
forceNew,
agentIdArg,
model,
system,
systemPromptId,
fromAfFile,
loadingState,
]);
@@ -1078,7 +1093,7 @@ async function main(): Promise<void> {
baseTools: baseTools,
agentIdArg: specifiedAgentId,
model: specifiedModel,
system: specifiedSystem,
systemPromptId: systemPromptId,
toolset: specifiedToolset as "codex" | "default" | "gemini" | undefined,
skillsDirectory: skillsDirectory,
fromAfFile: fromAfFile,