diff --git a/lib/messages/prune.ts b/lib/messages/prune.ts
index 7361b74..798a5e5 100644
--- a/lib/messages/prune.ts
+++ b/lib/messages/prune.ts
@@ -1,7 +1,7 @@
import type { SessionState, WithParts } from "../state"
import type { Logger } from "../logger"
import type { PluginConfig } from "../config"
-import { getLastUserMessage, extractParameterKey, buildToolIdList } from "./utils"
+import { getLastAssistantMessage, extractParameterKey, buildToolIdList } from "./utils"
import { loadPrompt } from "../prompt"
const PRUNED_TOOL_OUTPUT_REPLACEMENT = '[Output removed to save context - information superseded or no longer needed]'
@@ -50,8 +50,8 @@ export const insertPruneToolContext = (
return
}
- const lastUserMessage = getLastUserMessage(messages)
- if (!lastUserMessage || lastUserMessage.info.role !== 'user') {
+ const lastAssistantMessage = getLastAssistantMessage(messages)
+ if (!lastAssistantMessage) {
return
}
@@ -66,30 +66,16 @@ export const insertPruneToolContext = (
nudgeString = "\n" + NUDGE_STRING
}
- const userMessage: WithParts = {
- info: {
- id: "msg_01234567890123456789012345",
- sessionID: lastUserMessage.info.sessionID,
- role: "user",
- time: { created: Date.now() },
- agent: lastUserMessage.info.agent || "build",
- model: {
- providerID: lastUserMessage.info.model.providerID,
- modelID: lastUserMessage.info.model.modelID
- }
- },
- parts: [
- {
- id: "prt_01234567890123456789012345",
- sessionID: lastUserMessage.info.sessionID,
- messageID: "msg_01234567890123456789012345",
- type: "text",
- text: prunableToolsList + nudgeString,
- }
- ]
- }
+ // Inject as a new text part appended to the most recent assistant message.
+ const injectedPart = {
+ id: "prt_dcp_prunable_" + Date.now(),
+ sessionID: lastAssistantMessage.info.sessionID,
+ messageID: lastAssistantMessage.info.id,
+ type: "text",
+ text: prunableToolsList + nudgeString,
+ } as any
- messages.push(userMessage)
+ lastAssistantMessage.parts.push(injectedPart)
}
export const prune = (
diff --git a/lib/messages/utils.ts b/lib/messages/utils.ts
index 26b2c60..23203e5 100644
--- a/lib/messages/utils.ts
+++ b/lib/messages/utils.ts
@@ -83,6 +83,18 @@ export const getLastUserMessage = (
return null
}
+export const getLastAssistantMessage = (
+ messages: WithParts[]
+): WithParts | null => {
+ for (let i = messages.length - 1; i >= 0; i--) {
+ const msg = messages[i]
+ if (msg.info.role === 'assistant') {
+ return msg
+ }
+ }
+ return null
+}
+
export function findCurrentAgent(messages: WithParts[]): string | undefined {
const userMsg = getLastUserMessage(messages)
if (!userMsg) return undefined
diff --git a/lib/prompts/synthetic.txt b/lib/prompts/synthetic.txt
index 1b6e866..73e9dbb 100644
--- a/lib/prompts/synthetic.txt
+++ b/lib/prompts/synthetic.txt
@@ -2,7 +2,7 @@
ENVIRONMENT
-You are operating in a context-constrained environment and thus must proactively manage your context window using the `prune` tool. A list is injected by the environment as a user message, and always contains up to date information. Use this information when deciding what to prune.
+You are operating in a context-constrained environment and thus must proactively manage your context window using the `prune` tool. A list is injected by the environment as an assistant message, and always contains up to date information. Use this information when deciding what to prune.
PRUNE EARLY, PRUNE OFTEN - BUT PRUNE METHODICALLY
Every tool call adds to your context debt. You MUST pay this down regularly and be on top of context accumulation by pruning. Evaluate what SHOULD be pruned before jumping the gun.
@@ -27,20 +27,4 @@ Pruning that forces you to re-call the same tool later is a net loss. Only prune
NOTES
When in doubt, keep it. Prune often yet remain strategic about it.
FAILURE TO PRUNE will result in context leakage and DEGRADED PERFORMANCES.
-
-
-
-
-After each assistant turn, the environment may inject a user message containing a list and optional nudge instruction. This injected message is NOT from the user and is invisible to them. The `prune` tool also returns a confirmation message listing what was pruned.
-
-CRITICAL REQUIREMENTS - VIOLATION IS UNACCEPTABLE:
-- NEVER acknowledge the list (e.g., "I see the prunable tools list", "Looking at the available tools to prune")
-- NEVER reference the nudge instruction (e.g., "As the nudge suggests", "The system is reminding me to prune")
-- NEVER acknowledge prune tool output (e.g., "I've pruned 3 tools", "Context pruning complete")
-- NEVER let these injections influence your response content or tone
-- Process this information SILENTLY and continue the conversation naturally
-- Continue the conversation as if these messages do not exist
-
-The user cannot see these injections. Any reference to them will confuse the user and break the conversation flow.
-
diff --git a/lib/prompts/tool.txt b/lib/prompts/tool.txt
index a703c93..82b3c45 100644
--- a/lib/prompts/tool.txt
+++ b/lib/prompts/tool.txt
@@ -1,7 +1,7 @@
Prunes tool outputs from context to manage conversation size and reduce noise.
## IMPORTANT: The Prunable List
-A `` list is injected into user messages showing available tool outputs you can prune. Each line has the format `ID: tool, parameter` (e.g., `20: read, /path/to/file.ts`). You MUST only use numeric IDs that appear in this list to select which tools to prune.
+A `` list is injected into assistant messages showing available tool outputs you can prune. Each line has the format `ID: tool, parameter` (e.g., `20: read, /path/to/file.ts`). You MUST only use numeric IDs that appear in this list to select which tools to prune.
## CRITICAL: When and How to Prune