Skip to content

Commit d79a200

Browse files
authored
Merge pull request #1830 from entireio/fix/opencode-stale-injection
fix(opencode): clear pending injection on session change
2 parents 0f52986 + 3fcf023 commit d79a200

2 files changed

Lines changed: 22 additions & 0 deletions

File tree

cmd/entire/cli/agent/opencode/entire_plugin.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,9 @@ export const EntirePlugin: Plugin = async ({ directory }) => {
117117
messageStore.clear()
118118
currentModel = null
119119
currentSessionID = sessionID
120+
// Drop any turn-start injection captured for the prior session so it
121+
// can't leak into the new session's system prompt.
122+
pendingInjection = null
120123
return true
121124
}
122125

@@ -236,6 +239,7 @@ export const EntirePlugin: Plugin = async ({ directory }) => {
236239
seenUserMessages.clear()
237240
messageStore.clear()
238241
currentSessionID = null
242+
pendingInjection = null
239243
// Use sync variant: session-end may fire during shutdown.
240244
callHookSync("session-end", {
241245
session_id: session.id,
@@ -252,6 +256,7 @@ export const EntirePlugin: Plugin = async ({ directory }) => {
252256
seenUserMessages.clear()
253257
messageStore.clear()
254258
currentSessionID = null
259+
pendingInjection = null
255260
// Use sync variant: this is the last event before process exit.
256261
callHookSync("session-end", {
257262
session_id: sessionID,

cmd/entire/cli/agent/opencode/hooks_test.go

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -195,6 +195,23 @@ func TestInstallHooks_AppliesContextInjection(t *testing.T) {
195195
if !strings.Contains(content, `output.system.push(pendingInjection)`) {
196196
t.Fatal("plugin file should push the injection onto the system prompt")
197197
}
198+
// Every session-reset site must clear the stashed injection so a session
199+
// change cannot leak the prior session's context into the next session.
200+
resetSites := []struct{ name, start, end string }{
201+
{"resetSessionTracking", "function resetSessionTracking", "return true"},
202+
{"session.deleted", `case "session.deleted"`, `callHookSync("session-end"`},
203+
{"server.instance.disposed", `case "server.instance.disposed"`, `callHookSync("session-end"`},
204+
}
205+
for _, site := range resetSites {
206+
_, after, found := strings.Cut(content, site.start)
207+
if !found {
208+
t.Fatalf("plugin file missing reset site %q", site.name)
209+
}
210+
body, _, _ := strings.Cut(after, site.end)
211+
if !strings.Contains(body, `pendingInjection = null`) {
212+
t.Fatalf("%s should clear pendingInjection to avoid cross-session leakage", site.name)
213+
}
214+
}
198215
}
199216

200217
func TestInstallHooks_MessageUpdatedFallsBackToSessionStart(t *testing.T) {

0 commit comments

Comments
 (0)