Skip to content

Commit 11f6517

Browse files
authored
Merge pull request #606 from Opencode-DCP/dev
merge dev into main
2 parents 85b6f5c + e80a065 commit 11f6517

12 files changed

Lines changed: 411 additions & 219 deletions

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -231,7 +231,7 @@ LLM providers cache prompts based on exact prefix matching. When DCP prunes cont
231231
232232
**No impact for:**
233233

234-
- **Request-based billing**Providers like GitHub Copilot that charge per request, not tokens.
234+
- **Request-based billing**Some providers charge per request, not tokens.
235235
- **Uniform token pricing** — Providers like Cerebras that bill cached and uncached tokens at the same rate.
236236

237237
## License

dcp.schema.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
"description": "Configuration schema for the OpenCode Dynamic Context Pruning plugin",
66
"type": "object",
77
"additionalProperties": false,
8+
"allowTrailingCommas": true,
89
"properties": {
910
"$schema": {
1011
"type": "string",

lib/compress/pipeline.ts

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,15 @@ export async function finalizeSession(
8585
entries: NotificationEntry[],
8686
batchTopic: string | undefined,
8787
): Promise<void> {
88-
ctx.state.manualMode = ctx.state.manualMode ? "active" : false
88+
if (ctx.state.manualMode === "compress-pending") {
89+
ctx.state.manualMode = false
90+
await refreshManualMode(
91+
ctx.state,
92+
toolCtx.sessionID,
93+
ctx.logger,
94+
ctx.config.manualMode.enabled,
95+
)
96+
}
8997
applyPendingCompressionDurations(ctx.state)
9098
await saveSessionState(ctx.state, ctx.logger)
9199

lib/hooks.ts

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,15 @@ const INTERNAL_AGENT_SIGNATURES = [
4646
"Summarize what was done in this conversation",
4747
]
4848

49+
function isInternalAgentCall(systemPrompts: string[]): boolean {
50+
const primaryPrompt = systemPrompts[0]
51+
if (typeof primaryPrompt !== "string" || primaryPrompt.length === 0) {
52+
return false
53+
}
54+
55+
return INTERNAL_AGENT_SIGNATURES.some((signature) => primaryPrompt.includes(signature))
56+
}
57+
4958
export function createSystemPromptHandler(
5059
state: SessionState,
5160
logger: Logger,
@@ -65,8 +74,7 @@ export function createSystemPromptHandler(
6574
return
6675
}
6776

68-
const systemText = output.system.join("\n")
69-
if (INTERNAL_AGENT_SIGNATURES.some((sig) => systemText.includes(sig))) {
77+
if (isInternalAgentCall(output.system)) {
7078
logger.info("Skipping DCP system prompt injection for internal agent")
7179
return
7280
}

lib/messages/utils.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ const SUMMARY_ID_HASH_LENGTH = 16
77
const DCP_BLOCK_ID_TAG_REGEX = /(<dcp-message-id(?=[\s>])[^>]*>)b\d+(<\/dcp-message-id>)/g
88
const DCP_PAIRED_TAG_REGEX = /<dcp[^>]*>[\s\S]*?<\/dcp[^>]*>/gi
99
const DCP_UNPAIRED_TAG_REGEX = /<\/?dcp[^>]*>/gi
10+
const INJECTED_MESSAGE_ID_SUFFIX_REGEX = /(?<=\n)<dcp-message-id[^>]*>m\d+<\/dcp-message-id>\s*$/
11+
const HALLUCINATED_PARAMETER_SUFFIX_REGEX = /(?<=\n)m\d+<\/parameter>\s*$/
1012

1113
const generateStableId = (prefix: string, seed: string): string => {
1214
const hash = createHash("sha256").update(seed).digest("hex").slice(0, SUMMARY_ID_HASH_LENGTH)
@@ -163,7 +165,12 @@ export const replaceBlockIdsWithBlocked = (text: string): string => {
163165
}
164166

165167
export const stripHallucinationsFromString = (text: string): string => {
166-
return text.replace(DCP_PAIRED_TAG_REGEX, "").replace(DCP_UNPAIRED_TAG_REGEX, "")
168+
const withoutKnownSuffixes = text
169+
.replace(INJECTED_MESSAGE_ID_SUFFIX_REGEX, "")
170+
.replace(HALLUCINATED_PARAMETER_SUFFIX_REGEX, "")
171+
return withoutKnownSuffixes
172+
.replace(DCP_PAIRED_TAG_REGEX, "")
173+
.replace(DCP_UNPAIRED_TAG_REGEX, "")
167174
}
168175

169176
export const stripHallucinations = (messages: WithParts[]): void => {

lib/protected-patterns.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
function normalizePath(input: string): string {
2-
return input.replaceAll("\\\\", "/")
2+
// A single backslash. In source, "\\" is the one-character string; the
3+
// previous "\\\\" was a *two*-character string, so it only ever matched a
4+
// doubled separator -- which a real Windows path does not contain. The
5+
// normalisation was therefore a no-op on the only platform that needs it.
6+
return input.replaceAll("\\", "/")
37
}
48

59
function escapeRegExpChar(ch: string): string {

0 commit comments

Comments
 (0)