fix(athena): harden council members — compaction recovery, block TodoWrite, analysis mode
- Add session.compacted handler in BackgroundManager to prevent premature task completion after compaction (defer first post-compaction idle) - Explicitly block TodoWrite/TodoRead for council members in all sync points (AgentConfig permission + session tools + prompt instructions) - Add council member prefix check to todo-continuation-enforcer skip list to prevent infinite continuation loops on completed council members - Add optional analysis mode (solo/delegation) question to Athena setup: solo = thorough but heavier, delegation = fast via explore/librarian - Allow call_omo_agent in council member allow-list for delegation mode - Update COUNCIL_MEMBER_PROMPT with TodoWrite prohibition and delegation addendum for when delegation mode is selected - Update prepare_council_prompt tool with mode parameter
This commit is contained in:
@@ -165,6 +165,7 @@ export class BackgroundManager {
|
||||
private observedIncompleteTodosBySession: Map<string, boolean> = new Map()
|
||||
private rootDescendantCounts: Map<string, number>
|
||||
private preStartDescendantReservations: Set<string>
|
||||
private recentlyCompactedSessions: Set<string> = new Set()
|
||||
private enableParentSessionNotifications: boolean
|
||||
readonly taskHistory = new TaskHistory()
|
||||
private cachedCircuitBreakerSettings?: CircuitBreakerSettings
|
||||
@@ -1122,12 +1123,31 @@ export class BackgroundManager {
|
||||
return
|
||||
}
|
||||
|
||||
if (event.type === "session.compacted") {
|
||||
const sessionID = typeof props?.sessionID === "string"
|
||||
? props.sessionID
|
||||
: typeof (props?.info as { id?: string } | undefined)?.id === "string"
|
||||
? (props!.info as { id: string }).id
|
||||
: undefined
|
||||
if (!sessionID) return
|
||||
|
||||
const task = this.findBySession(sessionID)
|
||||
if (!task || task.status !== "running") return
|
||||
|
||||
this.recentlyCompactedSessions.add(sessionID)
|
||||
if (task.progress) {
|
||||
task.progress.lastUpdate = new Date()
|
||||
}
|
||||
log("[background-agent] Session compacted, deferring next idle:", { taskId: task.id, sessionID })
|
||||
}
|
||||
|
||||
if (event.type === "session.idle") {
|
||||
if (!props || typeof props !== "object") return
|
||||
handleSessionIdleBackgroundEvent({
|
||||
properties: props as Record<string, unknown>,
|
||||
findBySession: (id) => this.findBySession(id),
|
||||
idleDeferralTimers: this.idleDeferralTimers,
|
||||
recentlyCompactedSessions: this.recentlyCompactedSessions,
|
||||
validateSessionHasOutput: (id) => this.validateSessionHasOutput(id),
|
||||
checkSessionTodos: (id) => this.checkSessionTodos(id),
|
||||
tryCompleteTask: (task, source) => this.tryCompleteTask(task, source),
|
||||
@@ -1219,6 +1239,7 @@ export class BackgroundManager {
|
||||
|
||||
this.rootDescendantCounts.delete(sessionID)
|
||||
SessionCategoryRegistry.remove(sessionID)
|
||||
this.recentlyCompactedSessions.delete(sessionID)
|
||||
}
|
||||
|
||||
if (event.type === "session.status") {
|
||||
@@ -2180,6 +2201,7 @@ export class BackgroundManager {
|
||||
this.pendingByParent.clear()
|
||||
this.notificationQueueByParent.clear()
|
||||
this.rootDescendantCounts.clear()
|
||||
this.recentlyCompactedSessions.clear()
|
||||
this.queuesByKey.clear()
|
||||
this.processingKeys.clear()
|
||||
this.taskHistory.clearAll()
|
||||
|
||||
@@ -11,6 +11,7 @@ export function handleSessionIdleBackgroundEvent(args: {
|
||||
properties: Record<string, unknown>
|
||||
findBySession: (sessionID: string) => BackgroundTask | undefined
|
||||
idleDeferralTimers: Map<string, ReturnType<typeof setTimeout>>
|
||||
recentlyCompactedSessions?: Set<string>
|
||||
validateSessionHasOutput: (sessionID: string) => Promise<boolean>
|
||||
checkSessionTodos: (sessionID: string) => Promise<boolean>
|
||||
tryCompleteTask: (task: BackgroundTask, source: string) => Promise<boolean>
|
||||
@@ -20,6 +21,7 @@ export function handleSessionIdleBackgroundEvent(args: {
|
||||
properties,
|
||||
findBySession,
|
||||
idleDeferralTimers,
|
||||
recentlyCompactedSessions,
|
||||
validateSessionHasOutput,
|
||||
checkSessionTodos,
|
||||
tryCompleteTask,
|
||||
@@ -32,6 +34,12 @@ export function handleSessionIdleBackgroundEvent(args: {
|
||||
const task = findBySession(sessionID)
|
||||
if (!task || task.status !== "running") return
|
||||
|
||||
if (recentlyCompactedSessions?.has(sessionID)) {
|
||||
recentlyCompactedSessions.delete(sessionID)
|
||||
log("[background-agent] Skipping post-compaction session.idle:", { taskId: task.id, sessionID })
|
||||
return
|
||||
}
|
||||
|
||||
const startedAt = task.startedAt
|
||||
if (!startedAt) return
|
||||
|
||||
|
||||
Reference in New Issue
Block a user