export interface SemanticCompletionResult { toolActivityStalled: boolean; hasAssistantMessage: boolean; hasFileChanges: boolean; isComplete: boolean; lastToolActivityAt: number | null; secondsSinceLastToolActivity: number | null; /** Cumulative wall-clock duration (ms) that tools were active */ totalToolActivityDurationMs: number; } export interface SemanticCompletionOptions { toolIdleThresholdMs?: number; now?: number; /** Minimum cumulative tool activity duration before completion (default 60000) */ minTotalToolActivityDurationMs?: number; } /** * Extract the role from an OpenCode session message object. * * Checks `info.role` first (canonical SDK location), then falls back to * top-level `role`. Returns `undefined` when no role can be determined. * * @param message - Session message object of unknown shape. * @returns The role string ("user" | "assistant" | "system") or undefined. * * @example * getMessageRole({ info: { role: "assistant" }, parts: [] }) * // "assistant" */ export declare function getMessageRole(message: unknown): string | undefined; /** * Extract the parts array from an OpenCode session message object. * * @param message - Session message object of unknown shape. * @returns The parts array, or an empty array if not present or not an array. * * @example * getMessageParts({ parts: [{ type: "text", text: "hi" }] }) * // [{ type: "text", text: "hi" }] */ export declare function getMessageParts(message: unknown): unknown[]; /** * Find the timestamp of the last `tool_use` part across all messages. * * Iterates through all messages and their parts in order, returning the * `timestamp` field of the last part with `type === "tool_use"`. Falls back * to the parent message `timestamp` if the part itself lacks one. * * @param messages - Array of session message objects. * @returns Unix timestamp (ms) of the last tool_use, or null if none found. * * @example * findLastToolActivity([{ role: "assistant", parts: [ * { type: "tool_use", name: "bash", timestamp: 1000 } * ]}]) * // 1000 */ export declare function findLastToolActivity(messages: unknown[]): number | null; /** * Compute the cumulative wall-clock duration (ms) that tools were active. * * Iterates all messages and their parts, collecting timestamps from tool_use * parts. Sorts them and sums the intervals between consecutive timestamps. * The final interval extends from the last tool_use timestamp to `now`. * * Returns 0 when no tool_use parts have timestamps. * * @param messages - Array of session message objects. * @param now - Current time for extending the last interval (defaults to Date.now()). * @returns Total cumulative tool activity duration in milliseconds. * * @example * computeTotalToolActivityDuration([ * { parts: [{ type: "tool_use", timestamp: 1000 }] }, * { parts: [{ type: "tool_use", timestamp: 5000 }] } * ], 10000) * // (5000 - 1000) + (10000 - 5000) = 9000 */ export declare function computeTotalToolActivityDuration(messages: unknown[], now?: number): number; /** * Check whether the last message in the array is from the assistant with usable parts. * * A usable message has role "assistant" and a non-empty parts array containing * at least one part with a truthy `text`, `type`, or `output` field. * * @param messages - Array of session message objects. * @returns true if the last message is a usable assistant message. * * @example * hasAssistantLastMessage([{ role: "assistant", parts: [{ type: "text" }] }]) * // true */ export declare function hasAssistantLastMessage(messages: unknown[]): boolean; /** * Detect file-change indicators in `tool_result` parts across all messages. * * Looks for two signals: * 1. Tool names associated with file mutation (`write`, `edit`, `bash`, etc.) * found in tool_use parts that precede tool_result parts. * 2. File-path patterns (strings containing path separators and extensions) * in the text content of tool_result parts. * * @param messages - Array of session message objects. * @returns true if at least one file-change indicator is detected. * * @example * hasFileChangeIndicators([{ role: "assistant", parts: [ * { type: "tool_use", name: "write", input: { filePath: "/src/a.ts" } }, * { type: "tool_result", output: "Wrote /src/a.ts" } * ]}]) * // true */ export declare function hasFileChangeIndicators(messages: unknown[]): boolean; /** * Evaluate whether a delegated session has semantically completed its work. * * Checks four independent conditions and returns a structured result: * 1. **Tool Activity Stall** — no tool_use parts for > threshold milliseconds * 2. **Assistant Last Message** — last message is from assistant with usable parts * 3. **File Changes Detected** — tool_result content suggests file mutations * 4. **Sufficient Tool Duration** — cumulative tool activity >= minimum duration * * Completion is declared when all four conditions are true. * * @param messages - Array of session message objects (OpenCode SDK shape). * @param options - Optional configuration for idle threshold, time injection, and min duration. * @returns Structured result with individual condition flags and aggregate `isComplete`. * * @example * checkSemanticCompletion(messages, { now: Date.now() }) * // { toolActivityStalled: true, hasAssistantMessage: true, hasFileChanges: true, isComplete: true, ... } */ export declare function checkSemanticCompletion(messages: unknown[], options?: SemanticCompletionOptions): SemanticCompletionResult; //# sourceMappingURL=completion-detector.d.ts.map