const agentDefinition = {
id: "context-pruner",
displayName: "Context Pruner",
publisher: "codebuff",
version: "0.0.51",
model: "openai/gpt-5-mini",
toolNames: [],
spawnableAgents: [],
inputSchema: {
params: {
type: "object",
required: [],
properties: {
maxContextLength: {
type: "number"
}
}
}
},
includeMessageHistory: true,
outputMode: "last_message",
spawnerPrompt: `Spawn this agent between steps to prune context, starting with old tool results and then old messages.`,
systemPrompt: ``,
instructionsPrompt: ``,
stepPrompt: ``,
handleSteps: function* ({ agentState, params, logger }) {
const messages = agentState.messageHistory, IMPORTANT_TOOLS = new Set([
"read_files",
"write_todos",
"write_file",
"str_replace",
"propose_write_file",
"propose_str_replace"
]), countTokensJson = (obj) => {
return Math.ceil(JSON.stringify(obj).length / 3);
}, countMessageTokens = (message) => {
if (Array.isArray(message.content)) {
if (message.content.some((part) => part.type === "image" || part.type === "media")) {
let tokens = 0;
for (const part of message.content)
if (part.type === "image" || part.type === "media")
tokens += 1000;
else
tokens += countTokensJson(part);
const { content, ...rest } = message;
tokens += countTokensJson(rest);
return tokens;
}
}
return countTokensJson(message);
}, countMessagesTokens = (msgs) => {
return msgs.reduce((sum, msg) => sum + countMessageTokens(msg), 0);
}, systemPromptTokens = agentState.systemPrompt ? countTokensJson(agentState.systemPrompt) : 0, toolDefinitionTokens = agentState.toolDefinitions ? countTokensJson(agentState.toolDefinitions) * 0.75 : 0, maxMessageTokens = (params?.maxContextLength ?? 200000) - systemPromptTokens - toolDefinitionTokens, extractToolCallIds = (msgs) => {
const ids = new Set;
for (const message of msgs)
if (message.role === "assistant" && Array.isArray(message.content)) {
for (const part of message.content)
if (part.type === "tool-call" && part.toolCallId)
ids.add(part.toolCallId);
}
return ids;
}, extractToolResultIds = (msgs) => {
const ids = new Set;
for (const message of msgs)
if (message.role === "tool" && message.toolCallId)
ids.add(message.toolCallId);
return ids;
}, removeOrphanedToolMessages = (msgs) => {
const toolCallIds = extractToolCallIds(msgs), toolResultIds = extractToolResultIds(msgs);
return msgs.filter((message) => {
if (message.role === "tool" && message.toolCallId)
return toolCallIds.has(message.toolCallId);
return !0;
}).map((message) => {
if (message.role === "assistant" && Array.isArray(message.content)) {
const filteredContent = message.content.filter((part) => {
if (part.type === "tool-call" && part.toolCallId)
return toolResultIds.has(part.toolCallId);
return !0;
});
if (filteredContent.length === 0)
return null;
if (filteredContent.length !== message.content.length)
return { ...message, content: filteredContent };
}
return message;
}).filter((m) => m !== null);
}, buildToolPairMap = (msgs) => {
const pairs = new Map;
for (const [i, message] of msgs.entries())
if (message.role === "assistant" && Array.isArray(message.content)) {
for (const part of message.content)
if (part.type === "tool-call" && part.toolCallId) {
const existing = pairs.get(part.toolCallId) || {
callIndex: -1,
resultIndex: -1,
toolName: part.toolName || ""
};
existing.callIndex = i;
existing.toolName = part.toolName || "";
pairs.set(part.toolCallId, existing);
}
} else if (message.role === "tool" && message.toolCallId) {
const existing = pairs.get(message.toolCallId) || {
callIndex: -1,
resultIndex: -1,
toolName: message.toolName || ""
};
existing.resultIndex = i;
if (!existing.toolName)
existing.toolName = message.toolName || "";
pairs.set(message.toolCallId, existing);
}
return pairs;
}, getPairedIndices = (msgs) => {
const pairs = buildToolPairMap(msgs), indices = new Set;
for (const { callIndex, resultIndex } of pairs.values()) {
if (callIndex >= 0)
indices.add(callIndex);
if (resultIndex >= 0)
indices.add(resultIndex);
}
return indices;
};
let currentMessages = [...messages];
const lastInstructionsPromptIndex = currentMessages.findLastIndex((message) => message.tags?.includes("INSTRUCTIONS_PROMPT"));
if (lastInstructionsPromptIndex !== -1)
currentMessages.splice(lastInstructionsPromptIndex, 1);
const lastSubagentSpawnIndex = currentMessages.findLastIndex((message) => message.tags?.includes("SUBAGENT_SPAWN"));
if (lastSubagentSpawnIndex !== -1)
currentMessages.splice(lastSubagentSpawnIndex, 1);
if (countMessagesTokens(currentMessages) < maxMessageTokens) {
yield {
toolName: "set_messages",
input: { messages: currentMessages },
includeToolCall: !1
};
return;
}
const remainingInstructionsPromptIndex = currentMessages.findLastIndex((message) => message.tags?.includes("INSTRUCTIONS_PROMPT"));
if (remainingInstructionsPromptIndex !== -1)
currentMessages = currentMessages.filter((message, index) => !message.tags?.includes("INSTRUCTIONS_PROMPT") || index === remainingInstructionsPromptIndex);
const afterPass1 = currentMessages.map((message) => {
if (message.role === "tool") {
const outputSize = JSON.stringify(message.content).length;
if (outputSize > 1000)
return {
...message,
content: [
{
type: "json",
value: {
message: "[LARGE_TOOL_RESULT_OMITTED]",
originalSize: outputSize
}
}
]
};
}
return message;
});
let afterPass2 = afterPass1;
{
const lastNStartIndex = Math.max(0, afterPass1.length - 30), toolPairs = buildToolPairMap(afterPass1), indicesToRemovePass2 = new Set;
for (const { callIndex, resultIndex, toolName } of toolPairs.values()) {
const isInLastN = callIndex >= 0 && callIndex >= lastNStartIndex || resultIndex >= 0 && resultIndex >= lastNStartIndex;
if (!IMPORTANT_TOOLS.has(toolName) && !isInLastN) {
if (callIndex >= 0)
indicesToRemovePass2.add(callIndex);
if (resultIndex >= 0)
indicesToRemovePass2.add(resultIndex);
}
}
if (indicesToRemovePass2.size > 0)
afterPass2 = afterPass1.filter((_, i) => !indicesToRemovePass2.has(i));
}
const replacementMessage = {
role: "user",
content: [
{
type: "text",
text: "<system>Previous message(s) omitted due to length</system>"
}
]
}, tokensAfterPass2 = countMessagesTokens(afterPass2);
let afterPass3 = afterPass2;
const pairedIndices = getPairedIndices(afterPass2), targetTokens = maxMessageTokens * 0.25, tokensToRemove = tokensAfterPass2 - targetTokens;
let removedTokens = 0;
const indicesToRemove = new Set;
for (const [i, message] of afterPass2.entries()) {
if (removedTokens >= tokensToRemove)
break;
if (message.role === "user" || pairedIndices.has(i))
continue;
indicesToRemove.add(i);
removedTokens += countMessageTokens(message);
}
if (indicesToRemove.size > 0)
afterPass3 = [
replacementMessage,
...afterPass2.filter((_, i) => !indicesToRemove.has(i))
];
let afterPass4 = afterPass3;
const tokensAfterPass3 = countMessagesTokens(afterPass3);
if (tokensAfterPass3 > targetTokens) {
let currentTokens = tokensAfterPass3, startIndex = 0;
while (currentTokens > targetTokens && startIndex < afterPass3.length) {
currentTokens -= countMessageTokens(afterPass3[startIndex]);
startIndex++;
}
if (startIndex > 0)
afterPass4 = [replacementMessage, ...afterPass3.slice(startIndex)];
}
yield {
toolName: "set_messages",
input: {
messages: removeOrphanedToolMessages(afterPass4)
},
includeToolCall: !1
};
},
mcpServers: {},
inheritParentSystemPrompt: true
}