Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
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
63 changes: 63 additions & 0 deletions tests/hooks-permission.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,69 @@ test("system prompt handler caches full model context for percentage thresholds"
assert.equal(state.modelContextLimit, 200000)
})

function buildPromptStore() {
return {
reload() {},
getRuntimePrompts() {
return {
system: "DCP-RUNTIME-PROMPT",
manualExtension: "",
subagentExtension: "",
}
},
} as any
}

test("system prompt handler injects nudges for main session with bundled internal prompts", async () => {
const state = createSessionState()
const handler = createSystemPromptHandler(
state,
new Logger(false),
buildConfig("allow"),
buildPromptStore(),
)
const output = {
system: [
"You are the primary coding assistant for this repository.",
"You are a title generator for short session names.",
],
}

await handler(
{
sessionID: "session-1",
model: { limit: { context: 200000 } },
} as any,
output,
)

assert.match(output.system[output.system.length - 1], /DCP-RUNTIME-PROMPT/)
})

test("system prompt handler skips injection for internal agent calls", async () => {
const state = createSessionState()
const handler = createSystemPromptHandler(
state,
new Logger(false),
buildConfig("allow"),
buildPromptStore(),
)
const output = {
system: ["You are a title generator. Return only a short title."],
}

await handler(
{
sessionID: "session-1",
model: { limit: { context: 200000 } },
} as any,
output,
)

assert.equal(output.system.length, 1)
assert.doesNotMatch(output.system[0], /DCP-RUNTIME-PROMPT/)
})

test("chat message transform strips hallucinated tags even when compress is denied", async () => {
const state = createSessionState()
const logger = new Logger(false)
Expand Down