chore: Add --system flag for existing agents + update system prompt variable names (#328)
This commit is contained in:
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
65
src/index.ts
65
src/index.ts
@@ -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,
|
||||
|
||||
Reference in New Issue
Block a user