import { getCurrentBranch, buildCustomCompactionPrompt, fetchAndFormatPlanningState, getImageDescriptions, getRecentToolCallSummaries, storePreCompactionSnapshot, formatCompactionDiagnostics, countListItems, } from './compaction-utils';
/**
 * Session memory hooks handle compaction for non-Cadence sessions.
 *
 * Strategy:
 * 1. On compacting: Inject Memory system info into compaction prompt
 * 2. On session.compacted: Tell Lead to have Memory save the summary (it's already in context!)
 */
export function createSessionMemoryHooks(ctx, config, dbReader) {
    const log = (msg) => {
        ctx.client.app.log({
            body: {
                service: 'session-memory',
                level: 'debug',
                message: msg,
            },
        });
    };
    return {
        /**
         * Listen for session.compacted event.
         * The compaction summary is already in context - just tell Lead to save it.
         *
         * Note: Compaction continues in the SAME session (via session.prompt with
         * the existing sessionId), so permissions configured in the config hook
         * (plugin.ts) are automatically inherited — no re-application needed.
         */
        async onEvent(input) {
            const { event } = input;
            if (event?.type !== 'session.compacted')
                return;
            const sessionId = event.properties?.sessionId ??
                event.properties?.sessionID;
            if (!sessionId)
                return;
            log(`Compaction complete for session ${sessionId} - triggering memory save`);
            try {
                const branch = await getCurrentBranch();
                await ctx.client.session.prompt({
                    path: { id: sessionId },
                    body: {
                        parts: [
                            {
                                type: 'text',
                                text: `[COMPACTION COMPLETE]

The compaction summary above contains our session context.
Current branch: ${branch}

Have @Agentuity Coder Memory save this compaction:
1. Get existing session record (or create new): \`agentuity cloud kv get agentuity-opencode-memory "session:${sessionId}" --json --region use\`
2. Ensure branch field is set to "${branch}"
3. Append this compaction summary to the \`compactions\` array with timestamp
4. Save back: \`agentuity cloud kv set agentuity-opencode-memory "session:${sessionId}" '{...}' --region use\`
5. Upsert to Vector for semantic search: \`agentuity cloud vector upsert agentuity-opencode-sessions "session:${sessionId}" --document "..." --metadata '...' --region use\`

After saving the compaction:
1. Read back the session record from KV
2. Return to Lead the PREVIOUS compactions only (not the one just saved - Lead already has the current compaction in context)
3. Format as a readable summary with timestamps
4. Include "what's next" - the user's pending request if there is one

After saving the compaction, Memory should apply inline reasoning:
- If significant patterns, decisions, or corrections emerged
- Extract conclusions (explicit, deductive, inductive, abductive, corrections)
- Update entity representations with new conclusions
- Assign salience scores to conclusions

Response format:
\`\`\`
## Prior Session History: ${sessionId}

### Compaction 1 (timestamp)
[summary]

### Compaction 2 (timestamp)
[summary]

(Current compaction already in your context)

## What's Next
[User's pending request if there is one]
\`\`\`

If no prior compactions exist:
\`\`\`
## Prior Session History: ${sessionId}

No prior compactions - this is the first one.

## What's Next
[User's pending request if there is one]
\`\`\`

Then continue with the current task if there is one.`,
                            },
                        ],
                        agent: 'Agentuity Coder Lead',
                    },
                });
                log(`Memory save triggered for session ${sessionId}`);
            }
            catch (err) {
                log(`Failed to trigger memory save: ${err}`);
            }
        },
        /**
         * Inject Memory system info during compaction.
         * Uses output.prompt to REPLACE the default compaction prompt with
         * enriched context (planning state, images, tool calls, diagnostics).
         */
        async onCompacting(input, output) {
            const sessionId = input.sessionID;
            log(`Compacting session ${sessionId}`);
            // Config flags for compaction behavior
            const compactionCfg = config?.compaction ?? {};
            const useCustomPrompt = compactionCfg.customPrompt !== false;
            const useInlinePlanning = compactionCfg.inlinePlanning !== false;
            const useImageAwareness = compactionCfg.imageAwareness !== false;
            const useSnapshotToKV = compactionCfg.snapshotToKV !== false;
            const maxTokens = compactionCfg.maxContextTokens ?? 4000;
            // 1. Build custom compaction instructions
            const instructions = useCustomPrompt ? buildCustomCompactionPrompt('regular') : null;
            // 2. Gather enrichment data in parallel
            const toolCallLimit = config?.compaction?.toolCallSummaryLimit ?? 5;
            const [branch, planningState, imageDescs, toolSummaries] = await Promise.all([
                getCurrentBranch(),
                useInlinePlanning ? fetchAndFormatPlanningState(sessionId) : Promise.resolve(null),
                useImageAwareness
                    ? Promise.resolve(getImageDescriptions(dbReader ?? null, sessionId))
                    : Promise.resolve(null),
                Promise.resolve(getRecentToolCallSummaries(dbReader ?? null, sessionId, toolCallLimit)),
            ]);
            // 3. Build session state section
            const sessionStateSection = `## Session Memory

This session's context is being saved to persistent memory.
Session record location: \`session:${sessionId}\` in agentuity-opencode-memory
Current branch: ${branch}

After compaction:
1. Memory will save this summary to the session record
2. If planning is active, Memory should update planning.progress with this compaction
3. Memory will apply inline reasoning if significant patterns/corrections emerged`;
            // 4. Combine everything into the full prompt
            const sections = [];
            if (instructions)
                sections.push(instructions);
            sections.push(sessionStateSection);
            if (planningState)
                sections.push(planningState);
            if (imageDescs)
                sections.push(imageDescs);
            if (toolSummaries)
                sections.push(toolSummaries);
            // 5. Add diagnostics
            const stats = {
                planningPhasesCount: countListItems(planningState),
                imageDescriptionsCount: countListItems(imageDescs),
                toolCallSummariesCount: countListItems(toolSummaries),
                estimatedTokens: Math.ceil(sections.join('\n\n').length / 4),
            };
            const diagnostics = formatCompactionDiagnostics(stats);
            if (diagnostics)
                sections.push(diagnostics);
            // 6. Enforce token budget
            let fullPrompt = sections.join('\n\n');
            const estimatedTokens = Math.ceil(fullPrompt.length / 4);
            if (maxTokens > 0 && estimatedTokens > maxTokens) {
                // Trim least-critical sections first
                const trimOrder = [diagnostics, toolSummaries, imageDescs, planningState].filter(Boolean);
                let trimmed = [...sections];
                for (const candidate of trimOrder) {
                    if (Math.ceil(trimmed.join('\n\n').length / 4) <= maxTokens)
                        break;
                    trimmed = trimmed.filter((s) => s !== candidate);
                }
                fullPrompt = trimmed.join('\n\n');
            }
            // 7. Set the full prompt or push to context
            if (useCustomPrompt) {
                output.prompt = fullPrompt;
            }
            else {
                output.context.push(fullPrompt);
            }
            // 8. Store pre-compaction snapshot to KV (fire-and-forget)
            if (useSnapshotToKV) {
                storePreCompactionSnapshot(sessionId, {
                    timestamp: new Date().toISOString(),
                    sessionId,
                    planningState: planningState ? { raw: planningState } : undefined,
                    branch,
                }).catch(() => { }); // Fire and forget
            }
        },
    };
}
//# sourceMappingURL=session-memory.js.map