Phase 9: wire session_compact to defer and immediate reinject — SPEC §5.2, §8.

Connect compaction source gate with plan/enqueue/send paths and consume deferred queue on before_agent_start for end-to-end auto compaction trigger.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-06-17 12:35:01 +07:00
parent 0d274881dd
commit 0e32a498ee
+83 -2
View File
@@ -1,10 +1,31 @@
import { dirname } from "node:path";
import { isToolCallEventType, type ExtensionAPI, type ExtensionContext, type Skill } from "@earendil-works/pi-coding-agent";
import {
isToolCallEventType,
type ExtensionAPI,
type ExtensionContext,
type SessionCompactEvent,
type Skill,
} from "@earendil-works/pi-coding-agent";
import { detectAndCachePiAutoCompact, resolveDeliveryMode } from "./auto-compact.js";
import {
consumeCompactionOnSessionCompact,
createCompactionRuntime,
markAutoCompactionBeforeCompact,
markManualCompactionFromInput,
} from "./compaction.js";
import { detectSlashSkill, matchReadPathToSkillWhenEnabled, parseSkillBlocksFromText, userMessageText } from "./detect.js";
import {
enqueueDeferredReinjectFromCompact,
planReinject,
sendImmediateReinjectAllFollowUp,
sendImmediateReinjectIdle,
tryConsumeDeferredReinject,
} from "./reinject.js";
import { readSettings } from "./settings.js";
import { findRegisteredSkillByName, resolveRegisteredSkills } from "./skills-registry.js";
import {
createInitialState,
createRuntimeFlags,
saveState,
trackSkill,
type TrackSkillInput,
@@ -12,6 +33,8 @@ import {
export default function skillReinject(pi: ExtensionAPI): void {
const state = createInitialState();
const runtime = createRuntimeFlags();
const compactionRuntime = createCompactionRuntime();
let registeredSkills: Skill[] = [];
function persistState(): void {
@@ -38,8 +61,64 @@ export default function skillReinject(pi: ExtensionAPI): void {
});
}
pi.on("before_agent_start", async (event) => {
function handleSessionCompact(event: SessionCompactEvent, ctx: ExtensionContext): void {
const settings = readSettings(ctx);
const shouldReinject = consumeCompactionOnSessionCompact(
compactionRuntime,
state,
state.sessionOverride,
settings,
);
if (!shouldReinject) {
persistState();
return;
}
const skills = resolveRegisteredSkills(ctx.cwd, registeredSkills);
const deliveryMode = resolveDeliveryMode(settings, runtime);
if (deliveryMode === "defer") {
enqueueDeferredReinjectFromCompact(state, settings, ctx, event, skills);
persistState();
return;
}
const skillNames = planReinject(state, settings, ctx, event, skills);
if (skillNames.length === 0) {
persistState();
return;
}
if (ctx.isIdle()) {
sendImmediateReinjectIdle(pi, skillNames, state, settings, skills, ctx);
} else {
sendImmediateReinjectAllFollowUp(pi, skillNames, state, settings, skills, ctx);
}
persistState();
}
pi.on("session_start", async () => {
detectAndCachePiAutoCompact(pi, runtime);
});
pi.on("session_before_compact", async () => {
markAutoCompactionBeforeCompact(compactionRuntime);
});
pi.on("session_compact", async (event, ctx) => {
handleSessionCompact(event, ctx);
});
pi.on("before_agent_start", async (event, ctx) => {
registeredSkills = event.systemPromptOptions.skills ?? registeredSkills;
const settings = readSettings(ctx);
const pendingBefore = state.pendingReinject.length;
const deferred = tryConsumeDeferredReinject(state, settings, registeredSkills, ctx);
if (pendingBefore > 0) {
persistState();
}
if (deferred) {
return deferred;
}
});
pi.on("input", async (event, ctx) => {
@@ -47,6 +126,8 @@ export default function skillReinject(pi: ExtensionAPI): void {
return { action: "continue" };
}
markManualCompactionFromInput(event.text, compactionRuntime);
const skillName = detectSlashSkill(event.text);
if (skillName) {
const skills = resolveRegisteredSkills(ctx.cwd, registeredSkills);