Commit graph

6122 commits

Author SHA1 Message Date
CREDO23
b90bed2dbd chore: drop local design plan 2026-05-28 15:38:57 +02:00
CREDO23
91962ba879 fix automation run inputs, hitl routing, and detail UI polish 2026-05-28 02:48:47 +02:00
CREDO23
ed8d56aa16 feat(web): create automation via raw JSON 2026-05-28 01:44:13 +02:00
CREDO23
4625bd937e feat(web): run history section on automations detail page
Recent runs card under triggers. Each row expands lazily to fetch the
full run (step results, output, artifacts, error). 20-row cap for now;
real pagination lands if usage demands it.
2026-05-28 01:35:48 +02:00
CREDO23
2e572d7818 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.
2026-05-28 01:32:04 +02:00
CREDO23
c0a9ea368f feat(web): automations detail page (definition viewer + trigger manager)
Vertical slice at /dashboard/[id]/automations/[automation_id]. Branches
in the orchestrator are: perms loading → skeleton, no-access → access
denied panel, bad id → not-found, fetch loading → skeleton, fetch
error → not-found, loaded → header + definition + triggers.

Route:
- page.tsx — server boundary; extracts both ids.
- automation-detail-content.tsx — client orchestrator.

Header:
- automation-detail-header.tsx — back link, name, status badge,
  description, pause/resume + delete actions. Delete navigates back to
  the list via a new onDeleted hook on DeleteAutomationDialog so the
  list page (where the row just vanishes) stays unaffected.
- automation-not-found.tsx — 404/403/NaN-id panel. We don't
  distinguish missing vs. forbidden in the UI.

Definition (read-only in v1):
- automation-definition-section.tsx — wrapper Card; renders goal +
  tags + execution defaults + inputs schema (if present) + plan.
- plan-step-card.tsx — one step (when, output_as, retries, timeout,
  params JSON).
- execution-summary.tsx — timeout / max_retries / backoff /
  concurrency + on_failure step count.
- inputs-schema-preview.tsx — formatted JSON of inputs.schema; only
  rendered when the definition declares inputs.

Triggers:
- automation-triggers-section.tsx — wrapper Card, "Add via chat" CTA
  (creation is intent-driven, same philosophy as automations).
- trigger-card.tsx — schedule + timezone + cron, last/next fire
  hints, static_inputs JSON, enable Switch and remove button.
- delete-trigger-dialog.tsx — confirm + mutation atom.

Shared:
- lib/describe-cron.ts — moved out of automation-triggers-summary.tsx
  so both list and detail can describe schedules consistently
  (daily/weekdays/weekly/monthly/hourly, raw cron fallback).

Loading:
- automation-detail-loading.tsx — same shell as the loaded view so the
  layout doesn't jump on data arrival.

RBAC: each interactive surface is independently gated
(canUpdate/canDelete/canCreate) so the orchestrator stays thin and the
component tree is self-documenting about what each action requires.

Out of scope (later PRs):
- Editing definition / trigger params (raw-JSON path) — PR5
- Run history — PR6
2026-05-28 01:21:54 +02:00
CREDO23
bc3c2fd515 fix(web): hide header Create CTA on the automations empty state
The empty-state card already hosts the primary "Create via chat" CTA;
keeping the header button on the same screen showed two identical
buttons. Adds an optional ``showCreateCta`` prop to AutomationsHeader
(default true) and turns it off only in the empty branch so the card
stays the focal point.
2026-05-28 01:14:10 +02:00
CREDO23
7bc52dcdc0 feat(web): surface Automations in the sidebar under Inbox
Adds an "Automations" nav entry rendered explicitly between Inbox and
(on mobile) Documents, mirroring how those two are pulled out of the
nav list and rendered above the chat sections. The icon is Workflow
to match settings/RBAC labelling.

LayoutDataProvider:
- Adds the entry to navItems pointing at /dashboard/[id]/automations.
- Marks isActive via pathname so the row highlights on the route.
- Tags /automations as a workspace-panel page so it renders in the
  centered settings-style viewport (same chrome as Team / settings).

Sidebar:
- Pulls out automationsItem alongside inboxItem and documentsItem.
- Renders it between them.
- Excludes its URL from footerNavItems so it doesn't double-render.

Page-level RBAC still gates the actual view; the sidebar entry is
always visible (consistent with Inbox/Documents which are also not
gated at the nav layer).

Anonymous (FreeLayoutDataProvider) intentionally not touched —
automations is an authenticated feature.
2026-05-28 01:11:20 +02:00
CREDO23
fe28833ad4 feat(web): automations list page with status, pause/resume and delete
Vertical slice at /dashboard/[id]/automations. The page is read-only by
default; every action gates on backend automations:* permissions via a
co-located permissions hook so adding/removing surfaces stays a
one-file change.

Route:
- page.tsx — server boundary; extracts search_space_id.
- automations-content.tsx — client orchestrator (loading / no-access /
  error / empty / table branches).

Components (one concern per file):
- automations-header.tsx — title + count + "Create via chat" CTA.
- automations-table.tsx + automation-row.tsx — name/status/updated
  columns; row name links to detail (PR4).
- automation-status-badge.tsx — active / paused / archived pill.
- automation-row-actions.tsx — ⋯ menu with pause/resume + delete,
  gated on canUpdate / canDelete. Archived rows hide the toggle.
- delete-automation-dialog.tsx — destructive confirm; mentions FK
  cascade explicitly so users know triggers/runs go too.
- automations-empty-state.tsx — zero-state pointing to chat (creation
  is intent-driven via the create_automation HITL tool, not a form).
- automations-loading.tsx — skeleton rows in the same shell so the
  layout doesn't shift on data arrival.
- automation-triggers-summary.tsx — small cron-describer (daily,
  weekdays, weekly, monthly, hourly) + timezone for the detail page.
  Kept inline since v1 only registers schedule.

Hooks:
- use-automation-permissions.ts — single source of truth for the
  slice's canCreate/canRead/canUpdate/canDelete/canExecute gates,
  backed by myAccessAtom.

Pause/resume and delete reuse the PR2 mutation atoms, so list +
detail caches stay coherent without bespoke invalidation.

Out of scope (later PRs):
- detail route (definition viewer + triggers manager) — PR4
- raw JSON editor — PR5
- nav entry / sidebar wiring — small follow-up PR
2026-05-28 01:02:48 +02:00
CREDO23
b18a5fdca9 feat(web): automations contracts, API client, atoms and hooks
Foundation for the v1 automations UI. Mirrors backend Pydantic schemas
into Zod and wires the data layer end-to-end so feature surfaces can
be built on top.

contracts/types/automation.types.ts:
- AutomationStatus, TriggerType, RunStatus enums.
- AutomationDefinition envelope (PlanStep, TriggerSpec, Execution,
  Metadata, Inputs).
- AutomationCreate/Update/Detail/Summary/List + listParams.
- TriggerCreate/Update/Detail.
- RunSummary/Detail/List + runListParams.

lib/apis/automations-api.service.ts:
- list/get/create/update/delete automations.
- add/update/remove triggers (sub-resource).
- list/get runs (read-only sub-resource).
- safeParse on every write, 204-safe deletes.

atoms/automations/:
- automationsListAtom (active search space, first page).
- 6 mutation atoms with toast + cache invalidation.

hooks/:
- use-automations.ts wraps the list atom.
- use-automation.ts: parameterized detail by id.
- use-automation-runs.ts: useAutomationRuns + useAutomationRun.

lib/query-client/cache-keys.ts: automations namespace (list, detail,
runs, run) keyed by (id, limit, offset) where relevant.

Smoke: zod round-trip OK on backend-shape payloads (Automation,
AutomationCreate, Trigger, Run); typecheck clean for new files;
biome clean.
2026-05-28 00:55:57 +02:00
CREDO23
d48bb2033b fix(web): handle 204 No Content responses in base API service
DELETE endpoints in the automations API return 204; calling .json() on
an empty body throws SyntaxError. Treat 204 as data=null and skip
schema validation so callers can opt out of response bodies without
errors or spurious schema-mismatch warnings.

Also drops a pre-existing 'unknown → BodyInit' type error on the
non-JSON body branch via a narrow cast (caller is responsible for
passing a real BodyInit when Content-Type isn't application/json).
2026-05-28 00:55:46 +02:00
CREDO23
79f0218360 rbac: surface automations permissions in the UI
Backend already defined automations:create/read/update/delete/execute and
seeded them on Owner/Editor/Viewer roles, but the Settings → Roles UI was
missing the metadata to render them properly.

- backend: add PERMISSION_DESCRIPTIONS entries for the 5 automations perms so
  the role editor stops falling back to "Permission for automations:create".
- frontend: add automations to CATEGORY_CONFIG (Workflow icon, slotted between
  podcasts and connectors) so the role editor groups them as a real section.
- frontend: extend the three ROLE_PRESETS — Editor and Contributor get
  create/read/update/execute (mirroring backend Editor); Viewer gets read.

Prep work for the automations frontend; canPerform/usePermissionGate already
handle the runtime gating, so no new hook is needed.
2026-05-28 00:30:40 +02:00
CREDO23
2b7d91aa03 feat(automations): add create_automation HITL tool (NL → draft → approve → save)
Single tool exposed to the main agent. The main agent passes a natural-language
`intent`; a focused drafter sub-LLM turns it into a full AutomationCreate JSON;
that JSON is surfaced via request_approval (action_type "automation_create") so
the user can edit/approve it on a frontend card; on approval the tool persists
via AutomationService. Three phases, one tool call.

Scope split:
- main agent sees only `intent: str` (no schema knowledge leaks into the calling
  graph) — prompt fragments scoped accordingly.
- drafter sub-LLM owns the schema + few-shot intent→JSON examples — lives in
  the generating graph's prompt (tools/automation/prompt.py).

Files:
- main_agent/tools/automation/{create.py, prompt.py, __init__.py}: new tool
  + drafter system prompt with two few-shot intent→JSON examples.
- system_prompt/prompts/tools/create_automation/{description.md, example.md}:
  intent-only guidance for the main agent.
- main_agent/tools/index.py: add create_automation to the main-agent allowlist.
- new_chat/tools/registry.py: deferred-import factory to break the
  multi_agent_chat ↔ registry cycle; one ToolDefinition entry.
2026-05-28 00:12:02 +02:00
CREDO23
c0232fdcfe refactor(automations): park manual trigger pending Run-now redesign
Manual-as-a-standalone-trigger conflates "user clicks Run now" with the
trigger model and forces ad-hoc input plumbing on the caller. Remove the
unreachable surface so the tree reflects reality (schedule is the only
v1 trigger).

- Unregister `manual`: drop import from triggers/__init__.py
- Delete `app/automations/triggers/manual/`
- Drop `RunService.dispatch_manual` (RunService is now read-only)
- Drop `POST /automations/{id}/run` and `RunDispatched` schema
- Keep `TriggerType.MANUAL` Python + PG enum value (reserved, documented)
  to avoid an Alembic round-trip when Run-now is redesigned
2026-05-27 22:29:51 +02:00
CREDO23
8fb65d7188 fix(automations): use enum values not names for postgres enum columns 2026-05-27 21:53:07 +02:00
CREDO23
27ab367a13 feat(automations): static_inputs on triggers + vertical-slice api/services 2026-05-27 21:21:43 +02:00
CREDO23
84d99f19a2 automations(api): API request/response schemas 2026-05-27 19:10:20 +02:00
CREDO23
dd6bc30f98 move automations api into vertical slice with service layer 2026-05-27 18:56:16 +02:00
CREDO23
d84240a630 add schedule tick task and beat entry 2026-05-27 17:56:07 +02:00
CREDO23
3b1d7c4389 add cron-based schedule trigger 2026-05-27 17:56:02 +02:00
CREDO23
f08b316441 add next_fire_at to automation_triggers and croniter dep 2026-05-27 17:55:58 +02:00
CREDO23
861b91004d refactor(automations): extract dispatch_run; move manual adapter under triggers/manual/dispatch.py 2026-05-27 17:20:23 +02:00
CREDO23
8c32455818 refactor(automations): vertical-slice actions and triggers by domain 2026-05-27 17:07:20 +02:00
CREDO23
ce45e11009 feat(automations): wire agent_task to multi_agent_chat with auto-approve loop 2026-05-27 17:02:44 +02:00
CREDO23
7ec3468113 refactor(automations): bind action handlers via ActionContext factory 2026-05-27 16:29:32 +02:00
CREDO23
f646b5cbab feat(rbac): backfill automations permissions on existing roles 2026-05-27 15:37:25 +02:00
CREDO23
cfbe2a7fe0 feat(automations): expose POST /automations/{id}/run 2026-05-27 15:30:45 +02:00
CREDO23
3bb02d8889 feat(automations): add manual dispatch service 2026-05-27 15:30:41 +02:00
CREDO23
1366c8a711 feat(rbac): add automations permission family 2026-05-27 15:30:34 +02:00
CREDO23
b26bf0bbcf feat(automation): register automation run celery task 2026-05-27 15:02:36 +02:00
CREDO23
273b98f350 feat(automation): expose runtime package surface 2026-05-27 15:02:36 +02:00
CREDO23
d3cda12191 feat(automation): add automation run executor 2026-05-27 15:02:36 +02:00
CREDO23
0a329e5a69 feat(automation): add per-step execution 2026-05-27 15:02:36 +02:00
CREDO23
f71a02db2f feat(automation): add automation run repository 2026-05-27 15:02:36 +02:00
CREDO23
924a82c0b1 feat(automation): add retry policy helper 2026-05-27 15:02:36 +02:00
CREDO23
8b87d179e9 feat(automation): add recursive render_value to templating 2026-05-27 15:02:36 +02:00
CREDO23
cb42b3a84f feat(automation): add template run context builder 2026-05-27 14:23:18 +02:00
CREDO23
de6da1b775 feat(automation): add template render and predicate evaluation 2026-05-27 14:23:17 +02:00
CREDO23
8345e79f6d feat(automation): add sandboxed template environment 2026-05-27 14:23:17 +02:00
CREDO23
08e94ac5ca feat(automation): add custom template filters 2026-05-27 14:23:17 +02:00
CREDO23
b4e5bf95a4 feat(automation): add template filter and test allowlist 2026-05-27 14:23:17 +02:00
CREDO23
99fd1a1338 feat(automation): register agent_task action and schedule/manual triggers 2026-05-27 13:58:57 +02:00
CREDO23
56b3e1bfc4 refactor(automation): drop Block suffix from definition components 2026-05-27 13:48:41 +02:00
CREDO23
7f4c1c25ab feat(automation): wire SQLAlchemy relationships on both sides 2026-05-27 13:45:32 +02:00
CREDO23
7ac99b89a0 refactor(automation): drop Capability registry 2026-05-27 13:29:30 +02:00
CREDO23
9fa35f21cf refactor(automation): rename schema config to params, drop dead fields 2026-05-27 13:29:26 +02:00
CREDO23
c8a89ccac8 refactor(automation): rename trigger model config to params 2026-05-27 13:29:22 +02:00
CREDO23
fe32cd35ed refactor(automation): rename trigger config column to params 2026-05-27 13:29:18 +02:00
CREDO23
a4fbfd8c0d chore(automation): tighten run.py + envelope.py docstrings
Re-apply the trim style after the prior refactor commit re-introduced
a multi-line docstring on AutomationRun.

- AutomationRun: drop the four-line docstring explaining where
  per-step session ids live; move the note to a single-line inline
  comment right above ``step_results`` where it's actionable.
- AutomationDefinition: drop the design-plan cross-reference; the
  module docstring already establishes what the file is.

No behaviour change.
2026-05-27 11:45:04 +02:00
CREDO23
35117a952d refactor(automation): drop agent_session_id from AutomationRun
A run can contain zero, one, or N agent_task steps. A single
agent_session_id at the run level holds at most one of them, so the
column is the wrong shape for the data.

Per-step session ids (LangGraph thread/checkpoint reference for an
agent_task step) live inside step_results[i] alongside the rest of
the per-step bag (status, timings, output). Each agent step records
its own; non-agent steps record nothing. Run-level "primary session"
is a UI concern, not a schema concern.

Trade-off: trace -> run reverse lookup is now a JSONB query, not an
index hit. Usually traversal goes run -> trace; if the reverse
becomes hot we add a GIN index on step_results or a generated
column — both additive.

Changes:
- AutomationRun: drop the agent_session_id column; module docstring
  notes where per-step session ids now live.
- Migration 144: drop the column from the CREATE TABLE; downgrade
  unchanged.

Safe to edit migration 144 in place (vs. add 145 with ALTER ... DROP):
this branch has not shipped and the table has never existed in any
deployed database.
2026-05-27 11:41:32 +02:00