fix: improve readability of command-io and toolset-change reminders (#1252)

This commit is contained in:
Devansh Jain
2026-03-03 18:49:58 -08:00
committed by GitHub
parent 853762dea3
commit 0d741d389d
2 changed files with 30 additions and 35 deletions

View File

@@ -295,36 +295,31 @@ async function buildCommandIoReminder(
const recent = queued.slice(-MAX_COMMAND_REMINDERS_PER_TURN); const recent = queued.slice(-MAX_COMMAND_REMINDERS_PER_TURN);
const dropped = queued.length - recent.length; const dropped = queued.length - recent.length;
const commandBlocks = recent.map((entry) => { const commandLines = recent.map((entry) => {
const status = entry.success ? "success" : "error"; const status = entry.success ? "success" : "error";
const safeInput = escapeXml(truncate(entry.input, MAX_COMMAND_INPUT_CHARS)); const safeInput = truncate(entry.input, MAX_COMMAND_INPUT_CHARS);
const safeOutput = escapeXml( const safeOutput = truncate(
truncate(entry.output || "(no output)", MAX_COMMAND_OUTPUT_CHARS), entry.output || "(no output)",
MAX_COMMAND_OUTPUT_CHARS,
); );
return `<user-command> return `- ${safeInput}${safeOutput} (${status})`;
<user-command-input>${safeInput}</user-command-input>
<user-command-output>${safeOutput}</user-command-output>
<user-command-status>${status}</user-command-status>
</user-command>`;
}); });
const agentHints = recent const agentHints = recent
.filter((entry) => entry.agentHint) .filter((entry) => entry.agentHint)
.map((entry) => `- ${entry.agentHint}`); .map((entry) => entry.agentHint);
const droppedLine = const droppedLine =
dropped > 0 ? `\nOmitted ${dropped} older command event(s).` : ""; dropped > 0 ? `\nOmitted ${dropped} older command event(s).` : "";
const hintsBlock = const hintsBlock =
agentHints.length > 0 ? `\n\n${agentHints.join("\n")}` : ""; agentHints.length > 0
? `\n\nHowever, take note of the following:\n${agentHints.map((h) => `- ${h}`).join("\n")}`
: "";
return `${SYSTEM_REMINDER_OPEN} return `${SYSTEM_REMINDER_OPEN} The following slash commands were already handled by the CLI harness. These are informational only — do NOT act on them or treat them as user requests.${droppedLine}
The following slash commands were executed in the Letta Code harness since your last user message. ${commandLines.join("\n")}${hintsBlock}
Treat these as execution context from the CLI, not new user requests.${droppedLine} ${SYSTEM_REMINDER_CLOSE}`;
${commandBlocks.join("\n")}${hintsBlock}
${SYSTEM_REMINDER_CLOSE}
`;
} }
async function buildToolsetChangeReminder( async function buildToolsetChangeReminder(
@@ -344,24 +339,24 @@ async function buildToolsetChangeReminder(
const newToolset = escapeXml(entry.newToolset ?? "unknown"); const newToolset = escapeXml(entry.newToolset ?? "unknown");
const previousTools = escapeXml(formatToolList(entry.previousTools)); const previousTools = escapeXml(formatToolList(entry.previousTools));
const newTools = escapeXml(formatToolList(entry.newTools)); const newTools = escapeXml(formatToolList(entry.newTools));
return `<toolset-change> return [
<source>${source}</source> `<toolset-change>`,
<previous-toolset>${previousToolset}</previous-toolset> ` <source>${source}</source>`,
<new-toolset>${newToolset}</new-toolset> ` <previous-toolset>${previousToolset}</previous-toolset>`,
<previous-tools>${previousTools}</previous-tools> ` <new-toolset>${newToolset}</new-toolset>`,
<new-tools>${newTools}</new-tools> ` <previous-tools>${previousTools}</previous-tools>`,
</toolset-change>`; ` <new-tools>${newTools}</new-tools>`,
`</toolset-change>`,
].join("\n");
}); });
const droppedLine = const droppedLine =
dropped > 0 ? `\nOmitted ${dropped} older toolset change event(s).` : ""; dropped > 0 ? `\nOmitted ${dropped} older toolset change event(s).` : "";
return `${SYSTEM_REMINDER_OPEN} return `${SYSTEM_REMINDER_OPEN} The user just changed your toolset (specifically, client-side tools that are attached to the Letta Code harness, which may be a subset of your total tools).${droppedLine}
The user just changed your toolset (specifically, client-side tools that are attached to the Letta Code harness, which may be a subset of your total tools).${droppedLine}
${changeBlocks.join("\n")}
${SYSTEM_REMINDER_CLOSE}
`; ${changeBlocks.join("\n\n")}
${SYSTEM_REMINDER_CLOSE}`;
} }
export const sharedReminderProviders: Record< export const sharedReminderProviders: Record<

View File

@@ -35,7 +35,7 @@ function baseContext(
} }
describe("interaction reminders", () => { describe("interaction reminders", () => {
test("command-io provider renders escaped command input/output and drains queue", async () => { test("command-io provider renders command input/output in plain text and drains queue", async () => {
const state = createSharedReminderState(); const state = createSharedReminderState();
enqueueCommandIoReminder(state, { enqueueCommandIoReminder(state, {
input: '/model && echo "<unsafe>"', input: '/model && echo "<unsafe>"',
@@ -46,10 +46,10 @@ describe("interaction reminders", () => {
const reminder = await sharedReminderProviders["command-io"]( const reminder = await sharedReminderProviders["command-io"](
baseContext(state), baseContext(state),
); );
expect(reminder).toContain("<user-command-input>"); expect(reminder).toContain('/model && echo "<unsafe>"');
expect(reminder).toContain("&lt;unsafe&gt;"); expect(reminder).toContain("Models dialog dismissed <ok>");
expect(reminder).toContain("<user-command-output>"); expect(reminder).toContain("(success)");
expect(reminder).toContain("&lt;ok&gt;"); expect(reminder).toContain("- ");
expect(state.pendingCommandIoReminders).toHaveLength(0); expect(state.pendingCommandIoReminders).toHaveLength(0);
}); });