Phase 15: add mid-turn defer reinject via sendMessage steer
Deliver pending skills on session_compact when agent is not idle, and skip before_agent_start consume when steer already ran for compaction. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -8,6 +8,10 @@ export interface CompactionRuntime {
|
||||
clearPendingReinjectOnNextUserInput: boolean;
|
||||
/** Last compact firstKeptEntryId for debug kept-window snapshots (Phase 14). */
|
||||
lastCompactionFirstKeptEntryId: string | null;
|
||||
/** Last compaction entry id on session_compact (Phase 15 / B-003 dedup). */
|
||||
lastCompactionEntryId: string | null;
|
||||
/** Compaction id when mid-turn steer already delivered reinject (Phase 15 / §6.5.1). */
|
||||
deferredDeliveredForCompactionId: string | null;
|
||||
}
|
||||
|
||||
export function createCompactionRuntime(): CompactionRuntime {
|
||||
@@ -15,6 +19,8 @@ export function createCompactionRuntime(): CompactionRuntime {
|
||||
pendingCompactionSource: null,
|
||||
clearPendingReinjectOnNextUserInput: false,
|
||||
lastCompactionFirstKeptEntryId: null,
|
||||
lastCompactionEntryId: null,
|
||||
deferredDeliveredForCompactionId: null,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -352,6 +352,46 @@ export function filterPendingReinjectForConsume(
|
||||
return resolved;
|
||||
}
|
||||
|
||||
/**
|
||||
* Mid-turn defer delivery via sendMessage/steer (SPEC §6.5.1, Phase 15 / B-003).
|
||||
* Clears pendingReinject and records compaction id so before_agent_start does not duplicate.
|
||||
*/
|
||||
export function deliverDeferredReinjectSteer(
|
||||
pi: ExtensionAPI,
|
||||
state: ExtensionState,
|
||||
settings: SkillReinjectSettings,
|
||||
registeredSkills: readonly Pick<Skill, "name" | "filePath" | "baseDir">[],
|
||||
compactionRuntime: CompactionRuntime,
|
||||
compactionEntryId: string,
|
||||
ctx?: ExtensionContext,
|
||||
): boolean {
|
||||
if (state.pendingReinject.length === 0) {
|
||||
return false;
|
||||
}
|
||||
const pendingNames = filterPendingReinjectForConsume(
|
||||
state.pendingReinject,
|
||||
state,
|
||||
settings,
|
||||
registeredSkills,
|
||||
ctx,
|
||||
);
|
||||
const content = buildDeferredReinjectContent(pendingNames, state, settings, registeredSkills, ctx);
|
||||
state.pendingReinject = [];
|
||||
if (!content) {
|
||||
return false;
|
||||
}
|
||||
pi.sendMessage(
|
||||
{
|
||||
customType: DEFERRED_REINJECT_CUSTOM_TYPE,
|
||||
content,
|
||||
display: true,
|
||||
},
|
||||
{ deliverAs: "steer" },
|
||||
);
|
||||
compactionRuntime.deferredDeliveredForCompactionId = compactionEntryId;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Defer path on before_agent_start: inject one combined message, then clear queue (SPEC §6.5.1).
|
||||
* Returns undefined when pendingReinject is empty or manual compaction scheduled a clear (SPEC §16.5).
|
||||
@@ -366,6 +406,12 @@ export function tryConsumeDeferredReinject(
|
||||
if (compactionRuntime?.clearPendingReinjectOnNextUserInput) {
|
||||
return undefined;
|
||||
}
|
||||
if (
|
||||
compactionRuntime?.deferredDeliveredForCompactionId &&
|
||||
compactionRuntime.deferredDeliveredForCompactionId === compactionRuntime.lastCompactionEntryId
|
||||
) {
|
||||
return undefined;
|
||||
}
|
||||
if (state.pendingReinject.length === 0) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user