feat(web): create_automation HITL approval card in chat

Closes the create loop in chat: the agent describes user intent → the
drafter sub-LLM produces an AutomationCreate JSON → this card surfaces
a structured preview → approve persists; reject cancels. Edits flow
through chat refinement (re-call with a refined intent), not in-card,
so the card stays simple and the multi-turn checkpointer carries the
context.

Tool UI (components/tool-ui/automation/):
- create-automation.tsx — entry dispatcher + ApprovalCard chrome
  (pending/processing/complete/rejected via useHitlPhase) + SavedCard
  (links to the detail page) + InvalidCard (lists drafter validation
  issues) + ErrorCard (verbatim message). Rejection result is hidden
  because the approval card itself shows the rejected phase inline.
- automation-draft-preview.tsx — structured preview body: name +
  description + goal, triggers (humanised cron + tz + static-input
  keys), plan steps (step_id → action), and a collapsible raw JSON
  for power users.

Wiring:
- components/tool-ui/index.ts — re-export.
- features/chat-messages/timeline/tool-registry/registry.ts —
  register create_automation → CreateAutomationToolUI (dynamic import,
  same pattern as other connector tools).
- contracts/enums/toolIcons.tsx — Workflow icon + "Create automation"
  display name so fallback chrome (and timeline headers) are honest.

Shared util:
- lib/automations/describe-cron.ts — lifted from the route slice's
  lib/ folder since both the dashboard slice and the new approval card
  now render schedule descriptions. Slice imports updated; the now-
  empty slice lib/ folder is gone.

Backend prompt fragments:
- main_agent/system_prompt/.../create_automation/description.md and
  the tool's docstring no longer promise in-card edits. They make the
  refinement path explicit: if the user wants changes after seeing the
  draft, they reply in chat and the agent calls the tool again with a
  refined intent.

v1 deliberately excludes:
- In-card edit form / right-side edit panel — defer until we see real
  demand. The chat refinement loop covers the common case.
- approve_always / persistent allow rules — automations are a single
  artifact, not a repeated mutation, so the "trust this kind of call"
  affordance doesn't apply.
This commit is contained in:
CREDO23 2026-05-28 01:32:04 +02:00
parent c0a9ea368f
commit 2e572d7818
11 changed files with 541 additions and 11 deletions

View file

@ -1,7 +1,7 @@
- `create_automation` — Draft and author a new automation. You describe the
user's intent; a focused drafter inside the tool turns it into the full
automation JSON; the user reviews and edits it on an approval card; on
approval it's saved. All three phases happen in a single tool call.
automation JSON; the user sees a preview on an approval card and chooses
approve or reject. All three phases happen in a single tool call.
- Call when the user wants SurfSense to do something on its own: anything
recurring or scheduled ("every morning…", "each Monday…", "weekly
recap…").
@ -17,13 +17,16 @@
explicitly ("the Notion parent page id was not specified") so the
drafter leaves a placeholder.
- Do NOT prompt the user to confirm before calling — the approval card
IS the confirmation. The user can edit any field on the card.
IS the confirmation. The card shows a structured preview plus the raw
JSON; it offers approve/reject only. If the user wants changes after
seeing the draft, they reply in chat and you call this tool again with
a refined `intent` — that's the edit path.
- Returns:
- `{status: "saved", automation_id, name}` — confirm briefly to the
user ("Saved as automation #N — runs <when>."). Don't dump JSON back.
- `{status: "rejected", message}` — the user declined on the card.
Acknowledge once ("Understood, I didn't create it.") and stop. Do
NOT retry or pitch variants.
NOT retry or pitch variants without a fresh user request.
- `{status: "invalid", issues, raw?}` — drafting/validation failed
before the card was shown. Read the issues, refine your `intent`
with the missing details, call again.

View file

@ -66,9 +66,11 @@ def create_create_automation_tool(
names, ) it needs.
The tool drafts the full automation JSON internally, shows the user
an approval card for review, and persists on approval. Do NOT
prompt the user to confirm before calling the card IS the
confirmation. The user can edit any field there.
a structured preview on an approval card, and persists on approval.
The card supports approve/reject only if the user wants edits
after seeing the draft, they say so in chat and you call this tool
again with a refined intent. Do NOT prompt the user to confirm
before calling the card IS the confirmation.
Args:
intent: Concrete restatement of the user's request. Include