ns-ui

Refusal Negotiation

A refusal that negotiates instead of stonewalling: the offending span of a blocked request is echoed back struck through, with narrowing-lever toggle chips that rewrite it and unlock resend the instant a recheck passes.

Use when The counter-offer that appears *after* a guardrail already blocked a request: the flagged span struck through inline, a one-sentence reason, and toggle-chip levers that rewrite the span and unlock resend once a recheck passes — an editable negotiation surface for turning a refusal into a one-flip repair. Reach for approval-inline-diff instead when the request hasn't been decided yet and a human needs to approve or deny an agent's proposed, already-permitted tool-call arguments with an audit receipt — approval-inline-diff is the pre-decision approval row; refusal-negotiation is what a human (or the requester) sees once the gate has already closed.

Install

npx shadcn add https://design.helpmarq.com/r/refusal-negotiation.json
  • guardrail
  • refusal
  • negotiation
  • toggle
  • diff
  • accessibility

ns-ui / refusal-negotiation — negotiated refusal

Board note — refused

The draft tripped a data-handling guardrail. Flip a lever to see the flagged clause rewrite itself and the send button unlock.

Could you draft a note to the board that includes the customer's full name, account number, and home address from the complaint so they have full context before Friday's meeting?

Contains a customer's personally identifying details, which can't leave this workspace as free text.

Blocked

Roster export — refused

A second, independent negotiation over a different clause and a smaller lever set.

Export tonight's roster with each nurse's home phone number and address attached for the shift supervisor.

Home contact details for staff can't be included in an export outside the scheduling system.

Blocked

Props

PropTypeDefaultDescription
spanRedlineSpan
reasonstringone-sentence explanation of what tripped, shown under the echoed prompt
remediesRedlineRemedy[]
recheck?(span: RedlineSpan, activeRemedyIds: string[]) => booleandecides whether the rewritten span now clears the guardrail. Default: passes once at least one remedy is active — a real integration should pass its own check against the actual guardrail instead.
onResend?(resolution: RedlineResolution) => void
className?string