feat: implement SDK/HTTP pruning for deduplication and tool-output truncation on SQLite

- executeDeduplication: now async, reads messages from SDK on SQLite via
  client.session.messages() instead of JSON file reads
- truncateToolOutputsByCallId: now async, uses truncateToolResultAsync()
  HTTP PATCH on SQLite instead of file-based truncateToolResult()
- deduplication-recovery: passes client through to both functions
- recovery-hook: passes ctx.client to attemptDeduplicationRecovery

Removes the last intentional feature gap on SQLite backend — dynamic
context pruning (dedup + tool-output truncation) now works on both
JSON and SQLite storage backends.
This commit is contained in:
YeonGyu-Kim
2026-02-15 19:06:57 +09:00
parent 8b9379e4e5
commit d0870d6fbe
4 changed files with 93 additions and 22 deletions
@@ -1,3 +1,4 @@
import type { PluginInput } from "@opencode-ai/plugin"
import type { ParsedTokenLimitError } from "./types"
import type { ExperimentalConfig } from "../../config"
import type { DeduplicationConfig } from "./pruning-deduplication"
@@ -6,6 +7,8 @@ import { executeDeduplication } from "./pruning-deduplication"
import { truncateToolOutputsByCallId } from "./pruning-tool-output-truncation"
import { log } from "../../shared/logger"
type OpencodeClient = PluginInput["client"]
function createPruningState(): PruningState {
return {
toolIdsToPrune: new Set<string>(),
@@ -43,6 +46,7 @@ export async function attemptDeduplicationRecovery(
sessionID: string,
parsed: ParsedTokenLimitError,
experimental: ExperimentalConfig | undefined,
client?: OpencodeClient,
): Promise<void> {
if (!isPromptTooLongError(parsed)) return
@@ -50,15 +54,17 @@ export async function attemptDeduplicationRecovery(
if (!plan) return
const pruningState = createPruningState()
const prunedCount = executeDeduplication(
const prunedCount = await executeDeduplication(
sessionID,
pruningState,
plan.config,
plan.protectedTools,
client,
)
const { truncatedCount } = truncateToolOutputsByCallId(
const { truncatedCount } = await truncateToolOutputsByCallId(
sessionID,
pruningState.toolIdsToPrune,
client,
)
if (prunedCount > 0 || truncatedCount > 0) {