import type { BlokkliApp } from '#blokkli/editor/types/app'; import type { FullBlokkliAdapter } from '#blokkli/editor/adapter'; import type { ApprovalItem } from '#blokkli/editor/components/DiffApproval/types'; export type RejectedSegment = { tag: string; beforeHtml: string; afterHtml: string; status: 'matched' | 'inserted' | 'deleted'; reasonForRejection: string; }; export type FieldRejection = { reasonForRejection: string; /** * Present when the user evaluated a segmented field chunk-by-chunk. When * `accepted > 0` the field was updated with a hybrid value; when * `accepted === 0` every chunk was rejected and the field stayed at its * original value. */ partial?: { accepted: number; total: number; rejectedSegments: RejectedSegment[]; }; }; /** Map of paragraph UUID → field name → rejection details. */ export type RejectedByUser = Record>; /** * A field reference (uuid + field name) that was dropped before applying, * because the paragraph or the field does not exist. Reported back to the agent * so it can correct the reference instead of silently getting no change. */ export type SkippedField = { uuid: string; fieldName: string; reason: string; }; /** * Build the agent-facing note listing skipped field references. Returns * undefined when nothing was skipped. Shared by `update_text_fields` and * `delegate_text_rewrite`, which both drop references that don't resolve. */ export declare function skippedFieldsMessage(skipped: SkippedField[]): string | undefined; /** * Append a secondary note to an agent message, tolerating undefined on either * side. Used to add the skipped-fields note to every terminal `agentMessage`. */ export declare function appendAgentNote(message: string | undefined, note: string | undefined): string | undefined; export type DecidedUpdate = { itemId: number; uuid: string; fieldName: string; fieldValue: string; }; export type FieldDecisionResult = { /** * One entry per accepted item, with the value that should be written. For * segmented items this is the reassembled hybrid (accepted chunks + original * chunks for rejected ones); for unsegmented items it's `item.value`. */ updates: DecidedUpdate[]; rejectedByUser: RejectedByUser; /** * Number of accepted toggle units across the whole batch. For unsegmented * fields this is "field accepted" / "field rejected"; for segmented fields * each changed chunk counts as one unit. */ acceptedCount: number; /** Total number of toggle units the user could have selected. */ totalCount: number; }; /** * Walk the approval items and decide, per field, what gets written and what * gets reported as rejected. Pure: does no IO and does not depend on the * adapter. The caller picks the mutation strategy (entity vs. batch update, * translation import, …). * * `selected` and `reasons` are keyed by `ApprovalUnit.key` — the stringified * item id for unsegmented items, `${itemId}:${segmentId}` for segmented. */ export declare function decideFieldUpdates(items: ApprovalItem[], selected: Record, reasons: Record): FieldDecisionResult; export type FieldDiffApplyResult = FieldDecisionResult & { label: string; /** * The value that was actually written for each accepted item, keyed by * `ApprovalItem.id`. Used by the caller to build the `_details` panel * (agent-facing audit log). */ appliedByItemId: Record; }; /** * Apply the user's accept/reject decisions for a batch of field diffs through * `updateFieldValueBatched`. Shared by `update_text_fields` and * `delegate_text_rewrite`. The translation tool calls `decideFieldUpdates` * directly because it imports through a different adapter method. */ export declare function applyFieldDiffs(app: BlokkliApp, adapter: FullBlokkliAdapter, items: ApprovalItem[], selected: Record, reasons: Record): Promise; /** * Inline guidance the agent should follow when ANY field in this result came * back with `partial` set AND at least one chunk was accepted — i.e. the * field was updated with a hybrid value. Returns undefined when there were * no such hybrids. * * Scoping a follow-up to the rejected chunks (instead of rewriting the field * whole) is non-obvious — without this hint the model tends to re-propose * the entire field and clobber the accepted chunks. The guidance only * appears when a hybrid was actually written, so it costs nothing on the * normal "all accepted" or "all rejected" paths. */ export declare function partialRejectionGuidance(rejected: RejectedByUser): string | undefined; /** * The follow-up instruction to give the agent when the user rejected fields * or chunks without a reason. Returns undefined when every rejection had a * reason (or there were none). * * Partial rejections are surfaced at chunk granularity so the agent knows to * offer alternatives for the specific paragraph or list item, not the whole * field. */ export declare function rejectedWithoutReasonMessage(rejected: RejectedByUser): string | undefined;