Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
34ad193
feat: allow trailing commas in config schema
marmitar Jul 6, 2026
18c3393
Github Copilot doesn't charge per (premium) request anymore
viktorashi Jul 6, 2026
5f8f33b
fix: normalize a single backslash so protectedFilePatterns work on Wi…
LHMQ878 Jul 30, 2026
9f9a185
fix: reset compress-pending manual mode after compression
LHMQ878 Aug 8, 2026
e2047e2
fix: detect internal agents from primary system prompt only
LHMQ878 Aug 8, 2026
acb1fdc
fix: strip trailing mXXXX</parameter> hallucinations
LHMQ878 Aug 8, 2026
f236e0d
fix: strip injected message-id suffix before paired tag regex
LHMQ878 Aug 8, 2026
77d800b
fix: peer/devDependencies update to >=0.4.2, ^0.5.0 respectively for …
linellazatin Aug 10, 2026
838581a
fix: dev/peerDependencies update
linellazatin Aug 10, 2026
c14ae4c
fix: install OpenTUI runtime dependencies
Tarquinen Aug 16, 2026
1169803
Merge pull request #603 from linellazatin/dev-lines
Tarquinen Aug 16, 2026
042010a
chore: bump version to 3.1.15
Tarquinen Aug 16, 2026
35616fb
Merge pull request #600 from LHMQ878/fix/555-hallucinated-parameter-s…
Tarquinen Aug 16, 2026
d6069af
Merge remote-tracking branch 'origin/dev' into pr-601
Tarquinen Aug 16, 2026
25417d2
fix: update vulnerable brace expansion
Tarquinen Aug 16, 2026
264aa0d
Merge pull request #601 from LHMQ878/fix/556-injected-tag-suffix
Tarquinen Aug 16, 2026
d455619
Merge pull request #598 from LHMQ878/fix/581-internal-agent-detection
Tarquinen Aug 16, 2026
b2f8660
Merge remote-tracking branch 'origin/dev' into pr-596-review
Tarquinen Aug 16, 2026
42ac1a0
fix: restore manual mode after compression
Tarquinen Aug 16, 2026
1d1f5c5
Merge pull request #596 from LHMQ878/fix/590-manual-mode-compress-pen…
Tarquinen Aug 16, 2026
5fd2335
Merge pull request #593 from LHMQ878/fix/protected-patterns-windows-s…
Tarquinen Aug 16, 2026
59f110e
Merge branch 'dev' into patch-1
Tarquinen Aug 16, 2026
575cd92
Merge pull request #584 from viktorashi/patch-1
Tarquinen Aug 16, 2026
e80a065
Merge pull request #583 from marmitar/allow-trailing-comma-in-schema
Tarquinen Aug 16, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -231,7 +231,7 @@ LLM providers cache prompts based on exact prefix matching. When DCP prunes cont

**No impact for:**

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

## License
Expand Down
1 change: 1 addition & 0 deletions dcp.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
"description": "Configuration schema for the OpenCode Dynamic Context Pruning plugin",
"type": "object",
"additionalProperties": false,
"allowTrailingCommas": true,
"properties": {
"$schema": {
"type": "string",
Expand Down
10 changes: 9 additions & 1 deletion lib/compress/pipeline.ts
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,15 @@ export async function finalizeSession(
entries: NotificationEntry[],
batchTopic: string | undefined,
): Promise<void> {
ctx.state.manualMode = ctx.state.manualMode ? "active" : false
if (ctx.state.manualMode === "compress-pending") {
ctx.state.manualMode = false
await refreshManualMode(
ctx.state,
toolCtx.sessionID,
ctx.logger,
ctx.config.manualMode.enabled,
)
}
applyPendingCompressionDurations(ctx.state)
await saveSessionState(ctx.state, ctx.logger)

Expand Down
12 changes: 10 additions & 2 deletions lib/hooks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,15 @@ const INTERNAL_AGENT_SIGNATURES = [
"Summarize what was done in this conversation",
]

function isInternalAgentCall(systemPrompts: string[]): boolean {
const primaryPrompt = systemPrompts[0]
if (typeof primaryPrompt !== "string" || primaryPrompt.length === 0) {
return false
}

return INTERNAL_AGENT_SIGNATURES.some((signature) => primaryPrompt.includes(signature))
}

export function createSystemPromptHandler(
state: SessionState,
logger: Logger,
Expand All @@ -65,8 +74,7 @@ export function createSystemPromptHandler(
return
}

const systemText = output.system.join("\n")
if (INTERNAL_AGENT_SIGNATURES.some((sig) => systemText.includes(sig))) {
if (isInternalAgentCall(output.system)) {
logger.info("Skipping DCP system prompt injection for internal agent")
return
}
Expand Down
9 changes: 8 additions & 1 deletion lib/messages/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ const SUMMARY_ID_HASH_LENGTH = 16
const DCP_BLOCK_ID_TAG_REGEX = /(<dcp-message-id(?=[\s>])[^>]*>)b\d+(<\/dcp-message-id>)/g
const DCP_PAIRED_TAG_REGEX = /<dcp[^>]*>[\s\S]*?<\/dcp[^>]*>/gi
const DCP_UNPAIRED_TAG_REGEX = /<\/?dcp[^>]*>/gi
const INJECTED_MESSAGE_ID_SUFFIX_REGEX = /(?<=\n)<dcp-message-id[^>]*>m\d+<\/dcp-message-id>\s*$/
const HALLUCINATED_PARAMETER_SUFFIX_REGEX = /(?<=\n)m\d+<\/parameter>\s*$/

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

export const stripHallucinationsFromString = (text: string): string => {
return text.replace(DCP_PAIRED_TAG_REGEX, "").replace(DCP_UNPAIRED_TAG_REGEX, "")
const withoutKnownSuffixes = text
.replace(INJECTED_MESSAGE_ID_SUFFIX_REGEX, "")
.replace(HALLUCINATED_PARAMETER_SUFFIX_REGEX, "")
return withoutKnownSuffixes
.replace(DCP_PAIRED_TAG_REGEX, "")
.replace(DCP_UNPAIRED_TAG_REGEX, "")
}

export const stripHallucinations = (messages: WithParts[]): void => {
Expand Down
6 changes: 5 additions & 1 deletion lib/protected-patterns.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
function normalizePath(input: string): string {
return input.replaceAll("\\\\", "/")
// A single backslash. In source, "\\" is the one-character string; the
// previous "\\\\" was a *two*-character string, so it only ever matched a
// doubled separator -- which a real Windows path does not contain. The
// normalisation was therefore a no-op on the only platform that needs it.
return input.replaceAll("\\", "/")
}

function escapeRegExpChar(ch: string): string {
Expand Down
Loading
Loading