Exclusivobeta

Run Contract <mv-run-contract>

Um contrato de execução para tarefas longas de IA que vira o dashboard ao vivo da mesma tarefa: um card, duas vidas. Antes: objetivo, janela de tempo desenhada como uma faixa em um eixo temporal, teto de gastos ajustável, critérios de conclusão, limite da delegação (permitido ✓ / não permitido ⊘) e perguntas em aberto a resolver antes do lançamento; você assina segurando o botão enquanto uma assinatura manuscrita é traçada sob o seu dedo, e ela se desfaz se você soltar antes da hora. Depois: o card se transforma no lugar (FLIP), um marcador "now" avança pela faixa e a estica em caso de estouro, o teto vira um pavio aceso que pausa para pedir aprovação ("Allow +$5" / "Stop"), e os checkpoints aparecem como nós, com resumos legíveis das decisões tomadas e "Resume from here".

CategoriaFeedback
TipoWeb Component (<mv-run-contract>)
Statusbeta
KitIA que você pode verificar
Keywordsexclusive, ai, agent, long-running, slow-ai, contract, consent, budget, cost-cap, eta, checkpoint, breadcrumbs, progress, operator, dashboard, hold-to-confirm, signature, human-in-the-loop

When to use

  • A long AI task needs agreed terms before launch: objective, time window, spending cap and allowed actions
  • The same card should become a live dashboard with elapsed time, budget burn, pauses and checkpoints
  • A run must pause for approval when it hits its budget and allow resuming from a checkpoint

Avoid when

  • The task is short and a simple progress indicator is enough → use Progress instead
  • Many agents run in parallel and need a shared overview → use Agent Lenses instead
  • A plain hold-to-confirm action is needed without contract terms → use Hold Button instead

Instalação

node scripts/add.mjs run-contract --out ./src/marvelous

Agente de IA com o servidor MCP do Marvelous UI: install_components({ slugs: ["run-contract"], target_dir: "<absolute path>/src/marvelous", framework: "react" }).

Arquivos copiados (dependências incluídas): tokens/tokens.css, core/base.css, core/canvas.js, core/dom.js, core/element.js, core/motion.js, core/observe.js, components/run-contract/run-contract.js, components/run-contract/run-contract.css.

Uso

Início rápido, a menor marcação que funciona:

<mv-run-contract eta="25-40" budget="12">
  <p slot="objective">Compare 20 product sheets on price, shipping and reviews.</p>
  <ul slot="done"><li>A comparison table across 18 criteria</li></ul>
  <ul slot="allow"><li>Browse public websites</li></ul>
  <ul slot="deny"><li>Send emails</li></ul>
</mv-run-contract>

Marcação de referência, para usar como ponto de partida e personalizar com atributos, data-* e variáveis CSS:

<div id="rc-demo" style="width:min(100%,42rem);margin-inline:auto">
  <style>
    #rc-demo .rc-bar { display:flex; align-items:center; justify-content:space-between; gap:.75rem 1rem; flex-wrap:wrap; margin-top:.875rem }
    #rc-demo .rc-hint { margin:0; color:var(--mv-fg-muted); font-size:.75rem }
  </style>

  <mv-run-contract id="rc-watch" eta="25-40" budget="12" budget-max="30" extend="5" speed="60">
    <p slot="objective">Competitive watch: 20 product sheets compared on price, shipping and customer reviews.</p>
    <ul slot="done">
      <li>20 product sheets collected from dated public sources</li>
      <li>Comparison table across 18 criteria, prices normalized with tax</li>
      <li>One-page summary with the 3 biggest gaps</li>
    </ul>
    <ul slot="allow">
      <li>Read your files in the “Market watch” folder</li>
      <li>Browse public websites</li>
      <li>Create a results spreadsheet</li>
    </ul>
    <ul slot="deny">
      <li>Send emails</li>
      <li>Create accounts or pay for access</li>
    </ul>
    <p slot="question" data-name="market" data-options="United States, International" data-answer="United States">Which market should we compare?</p>
    <p slot="question" data-name="shipping" data-options="Yes (delivered price), No (list price)">Should prices include shipping?</p>
  </mv-run-contract>

  <div class="rc-bar">
    <p class="rc-hint">Hold <kbd class="mv-kbd">Space</kbd> or the button to sign · accelerated demo: 1 s = 1 min</p>
    <button class="mv-button" data-variant="outline" data-size="sm" type="button" id="rc-replay">Replay demo</button>
  </div>

  <script type="module">
    const rc = document.getElementById("rc-watch");
    await customElements.whenDefined("mv-run-contract");

    // Scripted research agent: breadcrumbs are decisions, not logs.
    const PLAN = [
      { at: 4, label: "Scope set", summary: "20 products kept out of 26 candidates, 6 out-of-range dropped", detail: "Exclusion rule: discontinued products and quote-only listings." },
      { at: 11, label: "Sources vetted", summary: "14 sources kept, 3 dropped (paywalled)", detail: "Subscription comparison sites are outside the delegation: no paid access was created." },
      { at: 20, label: "Sheets extracted", summary: "20 sheets collected, 2 incomplete ones retried", detail: "Two sheets missing shipping costs were completed from the retailers’ terms of sale." },
      { at: 29, label: "Prices normalized", summary: "All prices converted to delivered price with tax, 18 criteria aligned", detail: "Assumption: standard ground shipping within the contiguous United States." },
      { at: 38, label: "Summary drafted", summary: "3 major gaps found, table ready for review", detail: "The draft summary is in “Market watch / 2026-09”." },
    ];
    const END = 43;
    const cost = (m) => (m <= 33 ? m * 0.366 : 12.08 + (m - 33) * 0.2);
    let timer = 0;
    let next = 0;
    let offset = 0; // minutes replayed after a "resume from"
    let extra = 0;  // money already spent before that point

    const tick = () => {
      if (rc.state !== "running") return;
      const m = rc.elapsed;
      const work = m - offset;
      while (next < PLAN.length && work >= PLAN[next].at) rc.checkpoint({ ...PLAN[next++], at: m });
      const done = Math.min(20, Math.floor((work / END) * 20));
      rc.progress({ spent: extra + cost(work), percent: Math.min(0.99, work / END), note: `${done} of 20 sheet${done === 1 ? "" : "s"} compared` });
      if (work >= END) {
        clearInterval(timer);
        rc.complete({ summary: "20 sheets compared across 18 criteria. Report ready: 3 major price gaps, 2 stock-outs to watch." });
      }
    };
    const run = () => { clearInterval(timer); timer = setInterval(tick, 200); };

    rc.addEventListener("mv-start", () => { next = offset = extra = 0; run(); });
    rc.addEventListener("mv-resume-from", (e) => {
      // The agent restarts from the chosen checkpoint: later breadcrumbs are redone from now on.
      const cp = e.detail.checkpoint;
      const i = PLAN.findIndex((p) => p.label === cp.label);
      const workAt = i >= 0 ? PLAN[i].at : 0;
      next = i + 1;
      offset = rc.elapsed - workAt;
      extra = rc.spent - cost(workAt);
      run();
    });
    rc.addEventListener("mv-budget", (e) => console.info("mv-budget", e.detail.type, e.detail.spent.toFixed(2), "/", e.detail.cap));
    document.getElementById("rc-replay").addEventListener("click", () => {
      clearInterval(timer);
      rc.reset();
    });
  </script>
</div>

API

Attributes

NameTipoDefaultDescription
etastringTime window in minutes, e.g. "25-40" (read on mount when the terms property is not used).
budgetnumber10Initial spending cap.
budget-maxnumbercap × 2.5Upper bound of the cap slider.
extendnumber5Amount offered by "Allow +…" when the cap is reached.
currencystringUSDISO 4217 currency (en-US formatting).
speednumber1Simulated minutes per real minute for the internal clock (60: one second = one minute, handy for demos). Irrelevant when the host passes elapsed to progress().
holdnumber (ms)1200How long the button must be held to sign.
warnnumber (0-1)0.8Budget warning threshold (fraction of the cap).
data-state / data-phasereflectedCurrent state (contract | running | paused | complete | failed | stopped) and phase (contract | run), for host styling.

Properties

NameTipoDescription
terms{ objective, eta: { min, max }, budget: { cap, max, min, step, extend, currency, editable }, done: string[], allow: string[], deny: string[], questions: { id, label, options?, answer? }[] }Contract terms (replaces the markup). Reading returns a copy, including a cap the user may have changed. Can be set before define().
statestringCurrent state (read-only).
answers{ [id]: string }Answers to the clarification questions (read-only).
elapsednumber (min)Running time elapsed, pauses excluded (read-only).
spent / checkpointsnumber / object[]Current spend and a copy of the checkpoints (read-only).

Methods

NameDescription
sign()Signs like a completed hold: refused (false) while a question is open; emits mv-sign (cancelable), then calls start().
start()Turns the contract into the tracker and starts the clock (no signature when called directly).
checkpoint({ label, summary, detail?, at? })Adds a checkpoint: a knot on the axis plus a conceptual breadcrumb. at in minutes (default: now).
progress({ spent?, percent?, note?, elapsed? })Updates spend, progress (0-1 or 0-100), a short note ("9 of 20 sheets") and, optionally, the real elapsed time. Crossing the warning threshold or the cap triggers the warning or the pause.
pause(reason) / resume()Host-driven pause (clock stopped) and resume.
extendBudget(amount?)Raises the cap (default: extend) and resumes if the cap had paused the run.
complete(result) / fail(error) / stop(reason?)Ends the run: success (result.summary), failure (error.message, can resume from the last checkpoint) or stop.
reset()Back to the unsigned contract with the original terms and answers (reverse morph).

Events

NameDescription
mv-signContract signed, cancelable. detail: { terms, answers, signedAt }.
mv-startTracker started. detail: { terms, answers, signedAt }.
mv-checkpointCheckpoint added. detail: { index, label, summary, detail, at, spent }.
mv-budgetBudget threshold. detail: { type: "warning" | "cap" | "extend", threshold?, amount?, spent, cap }. On "cap" the run is already paused: the host must suspend the agent.
mv-pause / mv-resume / mv-stopRequested by the user (or by the cap for mv-resume, source: "budget"): the host must act on the agent. Method calls do not emit these events.
mv-resume-from"Resume from here": detail { index, checkpoint }, cancelable. Otherwise later checkpoints are marked discarded and the run restarts.
mv-completeDone. detail: { result, elapsed, spent, checkpoints }.

Content structure

NameDescription
objectiveElement whose text is the objective (one sentence).
done<ul>/<ol> of done criteria (or one element per criterion).
allow / deny<ul> of actions the agent may / may not take.
questionA question to settle before signing; data-options="A, B" for choices (otherwise a text field), data-name for the id, data-answer for a default answer.

CSS classes

NameDescription
mv-run-contract-cardThe generated card (an article labelled by the objective).
mv-run-contract-axis / -band / -over / -nowTime axis: estimate band, hatched extension on overrun, "now" marker.
mv-run-contract-fuse / -emberBudget fuse (role=meter) and its ember.
mv-run-contract-sign / -inkHold-to-sign field and the handwritten stroke.
mv-run-contract-crumbs / -crumbCheckpoint list (conceptual breadcrumbs).
mv-run-contract-alertState panel: paused for approval, done, failed, stopped.

CSS variables

NameDefaultDescription
--mv-run-contract-accentvar(--mv-accent)Action color (slider, latest checkpoint, primary button).
--mv-run-contract-bandvar(--mv-accent)Tint of the estimate band.
--mv-run-contract-emberwarning / danger mixEmber and spark color (artistic effect).
--mv-run-contract-ink-colorvar(--mv-accent-fg)Signature ink.
--mv-run-contract-bgvar(--mv-surface)Card background.

Accessibility

Terms are a real description list (dt/dd); allowed and not-allowed actions are two labelled lists where every line has its icon and the group title carries the label (never color alone). Questions are fieldset/legend groups of native radios. The sign button is held with a pointer or Space/Enter; aria-describedby explains the hold and, while a question is open, why it is blocked (aria-disabled: it stays focusable and says why). A plain click never signs. While running, the budget is a role=meter and progress a role=progressbar, both with plain-language aria-valuetext; the time text gives elapsed time, remaining estimate and overrun (icon + label); checkpoints are a list of aria-expanded buttons revealing details and "Resume from here" (the axis knots are decorative duplicates). A polite live region announces signing, checkpoints, budget thresholds, time overrun, pauses, completion and failure. After signing, focus moves to the Pause button. Reduced motion: no animated morph, no sparks or flicker, markers step instead of gliding; the signature stays because it is the hold gauge. A single frameLoop is suspended offscreen, in hidden tabs and when idle; nothing keeps running once the element is removed.

Esta página foi traduzida com IA. Informar um problema de tradução