51 lines
2.2 KiB
TypeScript
51 lines
2.2 KiB
TypeScript
/**
|
|
* Pure status derivation for the `edit_interactive_html` tool card — extracted
|
|
* from the tool-UI render so it can be unit-tested without React.
|
|
*
|
|
* The authoritative success signal is the tool's OWN result: `details.html` is a
|
|
* string when the str_replace edits applied (the client then writes it to the
|
|
* scene). A successful apply must never render as "failed" — not even when the
|
|
* assistant message ends with status `incomplete`, which a reasoning model can
|
|
* trigger (it streams reasoning, calls the tool, then the wrap-up turn leaves the
|
|
* message `incomplete` even though the edit already landed).
|
|
*/
|
|
|
|
export interface EditInteractiveHtmlResult {
|
|
content?: { type: string; text?: string }[];
|
|
details?: { sceneId?: string; html?: string | null; editCount?: number };
|
|
}
|
|
|
|
/** True when the edits applied (the tool returned a concrete HTML string). */
|
|
export function isEditApplied(result?: EditInteractiveHtmlResult | null): boolean {
|
|
return typeof result?.details?.html === 'string';
|
|
}
|
|
|
|
/** True only when the tool explicitly refused / could not apply (html === null). */
|
|
export function isEditRefused(result?: EditInteractiveHtmlResult | null): boolean {
|
|
const d = result?.details;
|
|
return !!d && 'html' in d && d.html === null;
|
|
}
|
|
|
|
/**
|
|
* Whether the edit-tool card should show its "failed" (not-fixed) state.
|
|
*
|
|
* Bias to success: a card only fails on an EXPLICIT failure signal — an
|
|
* `isError` result, or a result whose html came back `null` (refusal /
|
|
* unappliable edit). A successful apply, a missing/unpropagated result, or an
|
|
* `incomplete` message status are NOT failures — pi-agent-core's result
|
|
* propagation is lossy and the slim persisted result drops the html payload, so
|
|
* treating "no positive signal" as failure wrongly showed ✕ on edits that
|
|
* actually applied. `running` and `stopped` are their own states.
|
|
*/
|
|
export function deriveEditFailed(args: {
|
|
running: boolean;
|
|
stopped: boolean;
|
|
isError: boolean;
|
|
result?: EditInteractiveHtmlResult | null;
|
|
}): boolean {
|
|
const { running, stopped, isError, result } = args;
|
|
if (running || stopped) return false;
|
|
if (isEditApplied(result)) return false;
|
|
return isError || isEditRefused(result);
|
|
}
|