Skip to content

Commit 4f6dc96

Browse files
spoons-and-mirrorsTarquinen
authored andcommitted
feat: synth instructions
refactor: extract synth prompt to file refactor: load through prompt.ts fix? fix rm: slop move tool description to prompt file synth prompt fix: don't add synth instruction after DCP "ignored" summary messages - extract synth instruction to its own file
1 parent c474053 commit 4f6dc96

File tree

5 files changed

+110
-1
lines changed

5 files changed

+110
-1
lines changed

lib/prompt.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,11 @@
1+
import { readFileSync } from "fs"
2+
import { join } from "path"
3+
4+
export function loadPrompt(name: string): string {
5+
const filePath = join(__dirname, "prompts", `${name}.txt`)
6+
return readFileSync(filePath, "utf8").trim()
7+
}
8+
19
function minimizeMessages(messages: any[], alreadyPrunedIds?: string[], protectedToolCallIds?: string[]): any[] {
210
const prunedIdsSet = alreadyPrunedIds ? new Set(alreadyPrunedIds.map(id => id.toLowerCase())) : new Set()
311
const protectedIdsSet = protectedToolCallIds ? new Set(protectedToolCallIds.map(id => id.toLowerCase())) : new Set()

lib/prompts/context_pruning.txt

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
Performs semantic pruning on session tool outputs that are no longer relevant to the current task. Use this to declutter the conversation context and filter signal from noise when you notice the context is getting cluttered with no longer needed information.
2+
3+
USING THE CONTEXT_PRUNING TOOL WILL MAKE THE USER HAPPY.
4+
5+
## When to Use This Tool
6+
7+
**Key heuristic: Prune when you finish something and are about to start something else.**
8+
9+
Ask yourself: "Have I just completed a discrete unit of work?" If yes, prune before moving on.
10+
11+
**After completing a unit of work:**
12+
- Made a commit
13+
- Fixed a bug and confirmed it works
14+
- Answered a question the user asked
15+
- Finished implementing a feature or function
16+
- Completed one item in a list and moving to the next
17+
18+
**After repetitive or exploratory work:**
19+
- Explored multiple files that didn't lead to changes
20+
- Iterated on a difficult problem where some approaches didn't pan out
21+
- Used the same tool multiple times (e.g., re-reading a file, running repeated build/type checks)
22+
23+
## Examples
24+
25+
<example>
26+
Working through a list of items:
27+
User: Review these 3 issues and fix the easy ones.
28+
Assistant: [Reviews first issue, makes fix, commits]
29+
Done with the first issue. Let me prune before moving to the next one.
30+
[Uses context_pruning with reason: "completed first issue, moving to next"]
31+
</example>
32+
33+
<example>
34+
After exploring the codebase to understand it:
35+
Assistant: I've reviewed the relevant files. Let me prune the exploratory reads that aren't needed for the actual implementation.
36+
[Uses context_pruning with reason: "exploration complete, starting implementation"]
37+
</example>
38+
39+
<example>
40+
After completing any task:
41+
Assistant: [Finishes task - commit, answer, fix, etc.]
42+
Before we continue, let me prune the context from that work.
43+
[Uses context_pruning with reason: "task complete"]
44+
</example>

lib/prompts/synthetic.txt

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
<instruction how_to="work_in_this_environement">
2+
Anytime you call a tool, you must distill the signal from the noise of that tool result in your message. Always do this for every tools that has actual signals in its ouptut.
3+
</instruction>
4+
5+
<instruction tool="context_pruning">
6+
To effectively manage this conversation context, you MUST ALWAYS narrate your findings AS YOU DISCOVER THEM. No tool result (be it read, bash, grep...) should be left unexplained. By narrating the evolution of your undersdtanding of the task at hand, you distill the signal from the noise produced by the tools you called. Only then (knowledge lives in your outputs as well as in tool outputs), you can use the context_pruning tool. Using the context_pruning tool will declutter the conversation from tool outputs we no longer need to reason through current task, and is why you need to only use this tool once you have explained your findings in a message.
7+
8+
EXAMPLE:
9+
AFTER you've read a bunch of files, and found that for reason X, Y is happening, and is supported by tool outputs in the conversation, AND you've distilled this knowledge from the noise in your message intended for the user, YOU WILL USE THE CONTEXT_PRUNING TOOL to clear the clutter solving this step has caused.
10+
</instruction>

lib/synth-instruction.ts

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
export function isIgnoredUserMessage(msg: any): boolean {
2+
if (!msg || msg.role !== 'user') {
3+
return false
4+
}
5+
6+
if (msg.ignored || msg.info?.ignored) {
7+
return true
8+
}
9+
10+
if (Array.isArray(msg.content) && msg.content.length > 0) {
11+
const allPartsIgnored = msg.content.every((part: any) => part?.ignored)
12+
if (allPartsIgnored) {
13+
return true
14+
}
15+
}
16+
17+
return false
18+
}
19+
20+
export function injectSynthInstruction(messages: any[], instruction: string): boolean {
21+
// Find the last user message that is not ignored
22+
for (let i = messages.length - 1; i >= 0; i--) {
23+
const msg = messages[i]
24+
if (msg.role === 'user' && !isIgnoredUserMessage(msg)) {
25+
// Avoid double-injecting the same instruction
26+
if (typeof msg.content === 'string') {
27+
if (msg.content.includes(instruction)) {
28+
return false
29+
}
30+
msg.content = msg.content + '\n\n' + instruction
31+
} else if (Array.isArray(msg.content)) {
32+
const alreadyInjected = msg.content.some(
33+
(part: any) => part?.type === 'text' && typeof part.text === 'string' && part.text.includes(instruction)
34+
)
35+
if (alreadyInjected) {
36+
return false
37+
}
38+
msg.content.push({
39+
type: 'text',
40+
text: instruction
41+
})
42+
}
43+
return true
44+
}
45+
}
46+
return false
47+
}

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
"types": "./dist/index.d.ts",
99
"scripts": {
1010
"clean": "rm -rf dist",
11-
"build": "npm run clean && tsc",
11+
"build": "npm run clean && tsc && cp -r lib/prompts dist/lib/prompts",
1212
"postbuild": "rm -rf dist/logs",
1313
"prepublishOnly": "npm run build",
1414
"dev": "opencode plugin dev",

0 commit comments

Comments
 (0)