import { controllerLiveToolPayloadNotice, controllerRuntimeIdKey, type IControllerRuntimeId, type IControllerToolCall, type IControllerToolExecution, } from './interfaces.js'; /** * Whether a value can be compared as a qualified runtime ID at all. * * A durable tool call arrives from a harness transcript projection, so a value violating the * contract is conceivable here. `controllerRuntimeIdKey` would throw on it, and throwing is the * one answer this decision must never give: its documented failure mode is to keep the live * snapshot, not to abort the caller's render or message-page assembly. */ const controllerRuntimeIdIsUsable = (valueArg: unknown): valueArg is IControllerRuntimeId => ( typeof valueArg === 'object' && valueArg !== null && typeof (valueArg as IControllerRuntimeId).harnessId === 'string' && typeof (valueArg as IControllerRuntimeId).nativeId === 'string' ); /** * Structural equality for two JSON values. * * Tool payloads are JSON on both sides of the comparison, so key order carries no meaning and * reference identity carries none either. `JSON.stringify` would be wrong for the same reason — * it makes key order significant — and Node's `isDeepStrictEqual` is unavailable in the browser, * where the same rule has to hold. */ export const controllerJsonValuesEqual = (leftArg: unknown, rightArg: unknown): boolean => { if (Object.is(leftArg, rightArg)) return true; if (Array.isArray(leftArg) || Array.isArray(rightArg)) { return Array.isArray(leftArg) && Array.isArray(rightArg) && leftArg.length === rightArg.length && leftArg.every((value, index) => controllerJsonValuesEqual(value, rightArg[index])); } if ( !leftArg || !rightArg || typeof leftArg !== 'object' || typeof rightArg !== 'object' ) return false; const left = leftArg as Record; const right = rightArg as Record; const leftKeys = Object.keys(left).sort(); const rightKeys = Object.keys(right).sort(); return leftKeys.length === rightKeys.length && leftKeys.every((key, index) => ( key === rightKeys[index] && controllerJsonValuesEqual(left[key], right[key]) )); }; /** * Whether one payload of a live snapshot is already contained in the durable payload beside it. * * `prefixAllowedArg` marks a payload the live side may legitimately hold only the beginning of: * the two text streams, which grow while the tool runs and which the transfer bounder truncates * to a marker-free prefix. Every other payload has to match exactly — a live value that * disagrees with the durable one is a disagreement, not a bound. */ const controllerLiveToolPayloadIsCovered = ( liveValueArg: unknown, durableValueArg: unknown, prefixAllowedArg = false, ): boolean => { if (liveValueArg === undefined) return true; if (durableValueArg === undefined) return false; // An elided payload says nothing about the real one, so any durable payload contains it. if (liveValueArg === controllerLiveToolPayloadNotice) return true; if ( prefixAllowedArg && typeof liveValueArg === 'string' && typeof durableValueArg === 'string' ) return durableValueArg === liveValueArg || durableValueArg.startsWith(liveValueArg); return controllerJsonValuesEqual(liveValueArg, durableValueArg); }; /** * Whether a durable tool call from the transcript already carries everything a live snapshot of * the same call carries. This is what lets a receiver drop the live snapshot and render the * transcript alone; while it is false the snapshot has to stay, because dropping it would lose * state the transcript has not caught up with yet. * * Both the controller — deciding whether a message page already represents a live execution — * and the web client — deciding whether a live overlay may retire — ask exactly this question, * so they ask it through one implementation. The rule is deliberately conservative: an unproven * difference keeps the live snapshot rather than dropping observed state. */ export const controllerLiveToolExecutionIsCovered = ( executionArg: IControllerToolExecution, toolCallArg: IControllerToolCall | undefined, ): boolean => { if ( !toolCallArg || !controllerRuntimeIdIsUsable(toolCallArg.id) || !controllerRuntimeIdIsUsable(executionArg.callId) || controllerRuntimeIdKey(toolCallArg.id) !== controllerRuntimeIdKey(executionArg.callId) || toolCallArg.name !== executionArg.toolName || toolCallArg.status !== executionArg.status ) return false; return controllerLiveToolPayloadIsCovered(executionArg.input, toolCallArg.input) && controllerLiveToolPayloadIsCovered(executionArg.output, toolCallArg.output, true) && controllerLiveToolPayloadIsCovered(executionArg.errorText, toolCallArg.errorText, true) && controllerLiveToolPayloadIsCovered(executionArg.exitCode, toolCallArg.exitCode) && controllerLiveToolPayloadIsCovered(executionArg.childSessionId, toolCallArg.childSessionId) && controllerLiveToolPayloadIsCovered(executionArg.model, toolCallArg.model) && ( executionArg.finishedAt === undefined || ( toolCallArg.finishedAt !== undefined && toolCallArg.finishedAt >= executionArg.finishedAt ) ); };