mirror of
https://github.com/windmill-labs/windmill.git
synced 2026-10-19 08:03:16 +00:00
b7b33061952fde247447fa652663ffd730990d5e
285
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
3dae553576 |
feat: pipeline editor: assets-only view, Fix actions and draft triggers (#11440)
* wip: one sidebar for operators and developers, with a detach mode Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * feat: snap-detach the operator sidebar, and join the handle to the picker Dragging the sidebar into the left snap zone detaches it for an operator, who has no icon-only rail to collapse into; the width the drag started from is what gets persisted, so re-attaching restores the sidebar's size. The handle's colour pastille slides onto the card's workspace pastille as the card opens, alongside the workspace name, and both buttons that attach or detach the sidebar carry a tooltip. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * feat: attach and detach from the sidebar header, open the card under its handle The button that swaps the sidebar between docked and detached moves to the header, next to the workspace name, so it stays in one place across the swap; the icon-only rail has no room for it and keeps the footer copy. The handle itself becomes a component of its own, carries the workspace icon its picker uses, and opens the card rather than docking — docking is the header button's job. The card is placed under the handle measured at open time instead of at a fixed offset. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * feat: one page header across routes, with the workspace picker in it Every route now wears the same bar above its content: the sidebar toggle, the workspace picker, and whatever the route registers — an item's breadcrumb and summary, or a section name — with the route's own buttons at the far end. The bar's row is level with the sidebar's own top row, which the workspace ⇄ sessions switch now owns, so the two read as one band. A route fills the bar by mounting PageHeaderContent, which registers a getter rather than a snapshot: the layout calls it while rendering, so a path or summary the page edits reaches the bar without an effect keeping two copies in step. Nothing registers yet; the routes follow. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * feat: detail pages fill the page header, which now spans above the sidebar A script or flow detail page no longer draws a bar of its own: its path becomes the header's breadcrumb, its summary keeps the rename-and-labels popover next to it, and its badges, menu and buttons ride along as the header's actions. The band runs the full width with the sidebar hanging below it. A snippet rendered in the header initialises its components under the header, not under the page that wrote it, so anything the page's tree provides is lost — the detail page's buttons read TriggerContext and threw. ContextBridge carries the entries a registration names back around the render. The floating handle is gone with it: the header's own toggle is the one control, hovering it peeks the sidebar in and clicking pins it. The workspace picker in the header is a denser variant of the sidebar's, and the card's outside-click catcher starts at the card rather than the viewport top, so it no longer swallows clicks meant for the toggle. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * feat: one breadcrumb in the page header, and the banners that used to sit under it The header band now carries a single breadcrumb — workspace, fork, then the item's path — built from one component, so every segment has the same size, weight and icon size, and slashes separate them. The item's kind icon rides with its summary, after a dot, rather than with the path. The fork and drafts banners move into the band as badges plus a subtle Review button: ahead/behind counts instead of a bare change total, and the per-kind breakdown stays on the compare page. The home hero's CLI, MCP and Hub links move into an ellipsis menu, alongside the toggle that pins the session chat to the page. The flow editor and the app viewer hand their bar to the band too, and a route can drop the band's bottom border when its own content draws one — the border stays in the box with a transparent colour, so contents never shift a pixel across a navigation. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * feat: the runs page's own header row moves into the page header The title, the queue counters, the kind and status filters, the schedule and future-job switches, the search field and the timeframe picker all ride the band now, and the page starts at the chart — one row of vertical space back. The two toggle groups appear from 1500px: below that the bar cannot hold them next to the search field, and the same filtering is reachable from the search field's own kind and status chips. The search field is what gives width back, and the breadcrumb yields last, so a page's own name stays whole while the workspace and fork names truncate. The queue counters keep their icon form at every width, since the bar has room for two counters and never for the two labelled blocks. Their counts hang outside their icons, so the group carries the margins that keep a badge off its neighbour, and the suspended counter answers a hover at zero rather than sitting there as a dead icon. The band is 44px rather than 40, and a page can hand the breadcrumb a hint — the documentation tooltip that belongs with the page's name rather than with its buttons. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * feat: no border under the page header, and the peek card closes on the way out The band draws no bottom edge and no page asks it to, so `barBorder` goes with it — a page that needs the separation draws its own line, as the detail pages now do above the run form and the tab strip. With nothing toggling a border, the band is a flat 44px on every route. The detached sidebar's card is a hover affordance, so it leaves when the pointer does: off the handle and off the card both, on the same debounce a hover menu uses, because the two do not touch and the leave of one fires before the enter of the other. The mobile drawer is opened deliberately and still stays until it is dismissed. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * feat: one band, one workspace part, and the pickers that hang off it The band is a single element whose placement is styled rather than branched: a page registering a side-panel inset used to swap it between two `{#if}` arms, destroying the header and rebuilding it a frame later — a blink of no header with the content sliding up into the gap. The workspace and its fork become one breadcrumb part: the name leads home (inert in a session, where the workspace is the session's scope rather than a place to go) and one chevron opens the picker, which already expands a family to reach its forks. The picker's panel hangs from the part's left edge, opens with the active family expanded, and closes before the switch runs — the switch renames the workspace, which moves the trigger the panel hangs from, and floating-ui was chasing it across the viewport. The item's path is a plain label rather than a row of pickers: same separators and weight, and a click copies it with its own confirmation. The kind icon goes, the page below says what kind it is. Around them: a "prod" badge for a root workspace, the session's acting fork beside the session's name rather than in the breadcrumb, the edit-in-dev affordance as a button in the header, the drafts count as a sentence, and a fade when the workspace changes under a page that stays mounted. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: keep a page's own controls when the workspace navigation is hidden `menuHidden` means "this is an embed, don't show the workspace's navigation" — but Runs, the detail pages and the flow editor now keep their controls in the band and nowhere else, so hiding it took the filters, the timeframe and the page's buttons with it. A session's preview iframe opens exactly that way. The band now renders for an embed too, without its breadcrumb, so the page keeps its controls and the embed still gains no way to navigate the host's workspace. The flow editor's autosave indicator moves into the header's actions with the rest of its bar: saving state, the autosave toggle and other people's drafts were left behind in the branch the full-page editor no longer takes. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: the header carries what it promised, and nothing it does not The registry's item described pickers the breadcrumb no longer has: nine fields — the editability flags, the change callbacks, the navigation hook — that nothing read, while the flow editor passed eight of them and quietly lost its inline rename. The type now says what the bar does: a path, and either a summary or the page's own control for one. The flow editor renames through that control, as the detail page already did. `barPlacement` went the same way: no page registered 'inline', so the layout's guard never fired. The sessions page registered an inset of 0 whenever its preview pane never mounted — the "no session selected" and opted-out arms — and 0 reads as "a page owns the right edge", floating the band over the page's first line. It registers an inset only once the pane has a width. The band's sidebar handle docks through `setDetached` like the card's own toggle, so docking still suppresses the rail's entry animation and closes the card; a summary without its breadcrumb no longer leads with a stray separator in an embed; a page's hint sits with its name whichever way the page named itself; and `Menu.closeInstantly` and `EditorHeader`'s `inline`/`hideSummary` go, their callers having been replaced. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * feat: a deployed app gets the viewport, and the header waits in the corner An app is the page, not a page inside Windmill's chrome, so the band leaves the flow and floats above the viewport until the handle in the app's corner calls it down. The handle is faded until the pointer nears it, hovering peeks the band over the app, and a click pins it — one flag for every deployed app, in this browser, because someone who wants the breadcrumb over a dashboard wants it over the next one too. Peeking overlays rather than pushes: the app is an iframe, and taking 44px off its box on every pass of the pointer would re-lay-out whatever it draws. Pinned, the band is in flow like any other route's and the app starts under it. The sidebar is untouched — docked stays docked, detached stays a peek — since the pin is about the header alone. A page says it wants the viewport with one registry field, so the layout keeps asking the registry rather than knowing about apps. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * feat: one corner control for the chrome an app page hides Hovering the button overlaid on a deployed app brings back whatever that page is hiding: the band always, and the sidebar card too when the sidebar is detached. The card hangs from this button rather than from the header's own handle, which is off-screen with the band. The handle in the band no longer attaches the sidebar — it reveals it and nothing more. A control that hides the thing it sits on cannot also be the way to bring it back, so attaching stays with the toggle in the sidebar's own footer, where detaching happens. The band's two buttons go in the order the things nest: the sidebar's handle, then the header's pin. The overlaid button stands where the pin will be once pinned — same 28px box, and a slot further along when the sidebar's handle takes the first — so pinning moves nothing. It wears the panel pair the sidebar's toggle uses: solid while the band is away, dashed while it is shown. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * feat: the access point sits in the corner, and the header covers it The button is in the page's top-left corner — 8px in, or just past the rail when the sidebar is docked — rather than shifted along to where the header's pin would land. Hovering brings the header down over it: an access point that the regular view covers once it arrives, so there is nothing to line up and nothing to move. Because the header lands on the button, the pointer leaves it the instant it arrives. The band holds both itself and the sidebar card open while the pointer is anywhere on it, or the card would retract under a header that stayed. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * feat: on an app page the floating button owns both, and they move together The band drops its sidebar handle there: the floating control in the corner reveals the sidebar along with the band, and two handles for one gesture is one too many. The two are then linked — the pointer resting on either holds both, and leaving either collapses both — so they behave as the single thing the one button revealed. The card meets the header in a line: it hangs from the header's bottom edge rather than from whichever control opened it, which had it starting a couple of pixels high. With no header to sit under — an embed — it still hangs from the control that reached for it. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * feat: the revealed sidebar is a panel under the header, not a card over the page No rounded corners, no inset from the window: it starts at the header's bottom edge and runs to the left and bottom edges, with one border down its right side and a shadow to lift it off the page. A card floating in from nowhere read as a separate thing; this reads as the sidebar the header sits on top of. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: only an app page gets the flush panel; elsewhere the card still floats Over an app the sidebar reads as the panel the header sits on — flush left and bottom, square, one border down its right side. On every other page it is what it was: a card inset from the window with rounded corners and a border all round. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: an app opens with the header already away Opening an app showed the header and then slid it out: the page claimed the viewport on mount, and the band animated from where it had been rendering. The slide belongs to the hover, not to arriving, so it is armed a frame after the claim — the first hide is a cut. The claim moves to the route, which mounts before the viewer waiting on the workspace to resolve. A cold load now paints the band away from the first frame instead of showing a header that leaves again. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * feat: an app's Edit sits with its name At the far end of the bar it was a journey across the window from the thing it edits — on a page whose header is only there while the pointer holds it, a journey with a time limit. It goes beside the app's path instead. The slot it uses is the one Runs' documentation tooltip already had, renamed from `hint` to `afterName` and documented for both: what belongs to the page's name, whether that is a mark or a control that acts on what the name points at. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * feat: developers collapse, operators detach One control each, rather than three for everyone. A developer switches the sidebar between icon-only and full width and never detaches it; an operator, who has no icon-only rail to collapse to, hides it instead — by the button in its footer or by the same drag that collapses it for a developer. The way back survives either way: a detached sidebar keeps its "Show sidebar" button for anyone, so a developer who detached before this was so is not left with a sidebar they cannot return. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * feat: configure pipeline triggers and outputs as drafts in the editor Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * feat: one card for pipeline nodes, and the pipeline pages in the page header Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * fix: drop a removed node's trigger drafts, and confirm triggers when leaving Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * feat: show pipeline assets red when unused or awaited but never produced Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * fix: route long pipeline edges around nodes in the target column, and flag scripts waiting on unproduced assets Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * fix: a page is as tall as it is given, not as tall as the screen The band takes 44px off the top of every route, so a page sized to the viewport overflows by exactly that much: h-screen inside a column that already lost the band's height. These pages measure the box they are in instead. CenteredModal gains `inPage` for the five pages that render it inside the layout rather than over it — the same modal, centred in what is left of the page rather than in the window. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * feat: the band narrows, wraps, and draws its own edge The band publishes its width, so the pages filling it can answer it. Two tiers: under 1000px the breadcrumb keeps the workspace disc and its env badge and drops the name, and under PHONE_BAR (800) the trail stops yielding at 10rem — that floor is what makes the bar wrap, so a page's buttons take the line below rather than squeezing the name to an ellipsis. The band also draws the line between itself and the page, and only while something is scrolled under it. One capture listener on the window sees every scroller, since most pages scroll inside their own box and never move the layout's. An inset shadow, not a border: a border would move every page down a pixel the moment the line appeared. DetailPageLayout and InWorkspaceAppViewer drew that first line themselves; two lines would stack, so theirs go. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * feat: the script, app, runs and audit pages fill the band Each of these kept a header of its own above the page. They register with the band instead: the breadcrumb names what the page is on, and the page's buttons sit at the far end of the one row. They answer the band's width rather than the window's, since the buttons share that row with the breadcrumb. The script editor folds Diff and Settings into the menu it already shows when compact, the app editor drops the panel buttons, Awareness and Export and goes icon-only on Deploy and the mode switch, the flow editor menus its diff, and runs hides its counters. Runs also declares `actionsFlexible`: its search is the one control here that can give width back, and a box that refused to shrink would make it take its maximum instead. The run detail page loses its ActionRow, and the audit log its big title — the breadcrumb says where you are, and the page keeps its tooltip. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * feat: one sidebar column, shown as a rail or as a panel The rail and the drawer held two copies of the same column — the same sections, in the same order, in two pieces of markup, so a change to one silently skipped the other. Both now render `sidebarColumn`, and the shells keep only what differs: the rail its width, resize handle and collapse button, the panel its outside-click catcher and its transform. A phone gets that panel rather than a modal. There was a width test deciding between two presentations; the card under the band's handle works at any width, so it goes. What is left of the width test is the choice between a rail and a panel, plus a `(hover: hover)` test — the old `innerWidth >= 768` was standing in for "has a pointer", which is what decides whether the panel closes when the pointer leaves it. With the card everywhere, the backdrop, the `aria-modal` (nothing dims and nothing traps focus) and the drawer's close cross all go: the band's handle opens the panel and a tap outside closes it. The burger row goes with them. Entering panel width now collapses the rail transiently, so coming back to a wide window does not land on a rail the page was resized away from. The band also stops easing its right edge. That transition belongs to the rail, which moves the band's left; its right follows a splitter the page owns, and easing it left the band lying over a session's side panel — a blank strip across that panel's own header for 200ms after every drag. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * feat: the home composer flies to the menu that restores it Removing the composer puts it away rather than throws it out, and the way back is one item in the band's menu — easy to miss on a page the composer has just vacated. A mark flies from the control that removed it to that menu, and the menu answers with one ring as the mark dissolves, so where it went is witnessed rather than explained. The cross and the menu item now read "Remove session chat", one name for one thing whichever a reader reaches for. Reduced motion skips both. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: give pipeline asset nodes the trigger nodes' background again Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * fix: taller pipeline nodes, with the asset + back on the node's edge Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * fix: judge dbt relations by provenance, keep dynamic_skip on reopen, refresh saved scripts' titles Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * feat: label the pipeline + buttons: add data source, add downstream step on hover Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * feat: name a schedule node's cadence, like "Every day at 12:00" Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * fix: keep the downstream-step pill open while its menu is, without flicker Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * fix: room between pipeline node chips and the node's edge Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * fix: refuse renaming a pipeline draft out of the pipeline's folder Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * feat: title pipeline schedule nodes with the schedule's summary Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * revert: keep operators out of AI sessions That change is its own PR; this one is about the navigation. `prefersSessionHandoff` takes the role again and every entry point passes it, the sessions page refuses an operator arriving by URL, and the layout leaves them on the docked chat. Two clauses are new rather than restored, because the nav rework is what gives an operator a sidebar at all: the Workspace/AI Sessions switch and session mode are both hidden from them, since the page behind them declines. `askAiShown` gains the operator case for the same reason — they keep the docked pane whatever the beta gate says, so the sidebar has to offer a way into it. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * feat: assets-only view of a pipeline, with producer and trigger chips Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * fix: default schedule handlers, unique trigger draft paths, zoned cadence, valid script names Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * fix: setup banner without icon, button actions, plainer activity rows Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * feat: assets-only trigger chip under the title, editable and selectable Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * fix: await schedule defaults before confirming, refuse colliding trigger renames Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * feat: size assets-only cards to their content Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * feat: pipeline draft sync status beside the folder name in edit mode Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * fix: autosave edits to a deployed pipeline script from the first keystroke Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * fix: show schedule handlers once their defaults load, draft suffix on static chips Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * fix: keep the pipeline folder while the page tears down on leaving Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * fix: discard the open pane's autosaved edits with Discard all Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * feat: pipeline node context menus, add-at-cursor, and assets-only delete Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * style: borderless pipeline cards on the main surface, like flow steps Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * feat: remember which pipelines are in the assets-only view Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * feat: edit an asset's producing script from its pane and multi-script chip Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * style: more room between pipeline layers for the bottom + button Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * style: background on the trigger chip only when it opens an editor Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * feat: assets-only delete in both modes, why it is blocked, and a Show scripts toggle Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * fix: remove the script before its trigger, archive it for non-admins Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * fix: scope assets-only memory by workspace, no delete for operators, flow reason Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * style: fly in the pipeline node menus Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * style: size the Show drafts toggle like the other header buttons Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * feat: a No asset node for scripts that build nothing, in the assets-only view Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * feat: describe a pipeline edge's relationship on hover Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * fix: name assets-only edges by what is built from what Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * feat: open an asset's upstream trigger from its pane header Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * fix: reopen the edit-mode pane when coming back from View Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * style: no red border on errored pipeline nodes Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * feat: Fix actions on misconfigured pipeline nodes, and trigger toggles on edges Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * feat: folded errors and edge toggles in assets-only view, preset writer wizard Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * feat: flag pipeline scripts nothing starts, with schedule/webhook/remove fixes Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * fix: an unwritten subscription is fixed on its script only, by removing it Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * fix: hide subscribed-only unwritten assets, review fixes for the edit pane and edge actions Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * fix: an unwritten subscription is the subscriber's error, not the asset's Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * fix: a script only started by reads of unwritten assets is flagged too Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * feat: no add-downstream + on assets nothing in the workspace writes Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * fix: Save all treats a draft identical to the deployed script as saved Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * fix: remove-from-View opens its dialog, error chip fits, no link to an undrawn asset Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * feat: drag a script's dot onto an asset to subscribe it; unbuilt asset opens its script Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * feat: toggle to hide reads that don't trigger runs in the pipeline graph Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * feat: drag an asset's + onto a script or the canvas; tell reactive assets-only edges apart Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * fix: a programmatic on/mute line joins the existing ones in the header Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * fix: address review — live-version save check, bounded writer lookups, script-only trigger writes, dbt sources, hidden pane Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * fix: review — compare every deployed field, passive-read filter only with its toggle, drag cancel, asset escape hatch Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * fix: keep every control the band took over reachable Four controls the page-header conversion could put out of reach, each found by a review pass and reproduced in the browser: - The flow editor's preview buttons. `topbarWidth` is bound only in the branch a full-page editor does not render, so `compactTopbar` was permanently false there; below the 800px phone bar `phoneTopbar` dropped the buttons inline and the graph overlay never took them, leaving FlowPreviewButtons mounted nowhere and step testing, whole-flow testing and "Test flow & record" no-ops through optional calls. It now measures the header the way ScriptBuilder and AppEditorHeader do, and the inline and overlay conditions are exact complements. - The pin on a deployed app. The band lands over the corner handle that called it down, so the pointer that arrives there hits the band. The band carries the pin itself now, on the same pixels, in place of the sidebar handle it hides. - The detached sidebar's own menus. They portal to `body`, so moving into one left the card and closed it 200ms later, sliding it out from under the menu being read. The card holds while the pointer is in a menu and takes the close from the leave of that. - A deployed app's name for a read-only viewer. The breadcrumb was registered behind write access, so without it the trail fell back to the section name "Apps"; and the Edit button rode `afterName`, which the band drops for an embed along with the trail. The name is registered for whoever opened the app, and what sits after it survives `navHidden` as the page's own control. navPageFor gets a table test: it answers both the sidebar links and the breadcrumb label, and its longest-prefix and first-segment rules are what made the "Apps" fallback look like a correct answer. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * docs: drop what the operator revert and this refactor left behind The operator tour's last step named AI sessions among the pages the sidebar opens, which operators have no way to reach. The nav handle's comment named the AI chat layout's menu button as a second way into the card; that button and its prop are gone, and the corner control on a page that hides the band is what stands in for the handle now. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * style: prettier the three files this branch left unformatted `prettier --check` fails on all three at the previous head. Whitespace only, apart from one Button tag that fits on a line. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * feat: assets-only nodes name their script in a header tab instead of a side chip Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * fix: no loading spinner in the pane while a clicked script loads Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * fix: no subscribe drag dot in view mode Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * fix: opening a draft no longer autosaves; header tab styling, selected edge, taller cards Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * revert: clicking an unbuilt asset opens the asset again, not its script Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * fix: header tab sets card width, edit icons on script header and trigger chip, no pane header shift on open Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * fix: no trash in the pane header; card width ignores the run chip so a click never re-lays the graph Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * fix: taller trigger chip; node menu and guard badge on the card corner, below the header Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * fix: give a page without the band's chrome what the band was carrying Second review round, three reachable defects plus one decision: - A public raw app was 150px tall. The bundle's iframe is `h-full`, and dropping its `min-h-screen` left nothing to resolve against on the share, embed and custom-path routes — none of which has a layout above them. Measured: 150px in a 900px viewport. The floor goes back for those routes and stays off inside the workspace, where the layout hands a height down and `min-h-screen` would overflow it by the band. - The band retracted out from under its own open menu on a deployed app. Last round taught the sidebar card to hold while the pointer is in a portaled menu and left its sibling alone, but the band opens menus too — the workspace disc, the fork family, every path level. One helper now, used by both closers. - `bandPeeked` outlived the page it belonged to. Clicking a control in the band navigates away, and the next page may not be one the band floats over, so the hover handlers that would clear it are gone — leaving the band already down when a full-bleed page came back. `beforeNavigate` clears it. - An embed has no band to carry a control, so the app's Edit floats over the canvas there, where it sat before the band existed. Registering it as the band's `afterName` under `navHidden` instead would have cost the app 44px of the iframe for a row holding one button. Reading "is the workspace navigation hidden" now has one definition (`isMenuHidden`), since a page has to answer it too: the flag is sticky inside an iframe, so the raw query param is the wrong thing to read. Also inset the band by the rail only when there is a rail — an embed reserved its width and crowded its own controls into a compact layout early. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: a path that names nothing yet has no breadcrumb leaf `splitItemPath` documents that it gives up on a path still being typed, but `f/demo/` is three parts and returned a leaf with an empty name — a blank segment in the trail. The editor binds the path live, so the breadcrumb sees every keystroke. Tested here rather than `navPageFor`'s sort: no two `NAV_PAGES` paths nest, so the longest-prefix case that test claimed to pin has only one candidate. Renamed it to what it actually checks. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * style: prettier the four remaining files this branch left unformatted All four fail `prettier --check` on the branch and pass at the merge base. `raw_apps/utils.ts` also fails but already did at the base, so it is left alone. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * feat: pipelines open in the assets-only view by default Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * feat: a No asset node per script, banner-only when writes start it; no On asset change chip Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * feat: delete a node's script, trigger, or both from its menu; red header for a script with errors Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * fix: an errored script header stays red when selected Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * fix: coloured run badge border; per-script delete when no combined delete; run button centred on the card Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * fix: Add data source pill sits one small gap above the graph Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * feat: Multiple triggers chip picks the trigger to edit; each folded trigger deletable from the node menu Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * fix: add-step menu labels its path field Path Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * fix: iterate NodeLists with Array.from so svelte-check passes Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * fix: no trigger delete for flow-built assets; Multiple triggers chip shows the one being edited Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * fix: Archive button for archive-only deletes, single delete doc, inert Multiple triggers label in View Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * feat: the raw app editor fills the band like the other three It was the one editor route still rendering its own bar under the band, so it showed two header rows and the band named the app "Apps raw" — `navPageFor`'s first-segment fallback, because nothing on the route registered an item. Its top bar now becomes the page header the way the script, flow and low-code app editors' do: the path and summary are the breadcrumb's, the file-sidebar toggle, autosave cloud, presence mark, menu, Diff, Jobs, export, AI and Deploy are the header's actions, and the path is a plain label since this editor renames from its deploy drawer. The actions render under the band, outside the subtree `RawAppEditor` declares the operating workspace in, and `OpenInSessionButton` asks that context who the acting user is — so the workspace travels with them. `operatingWorkspaceContextEntry()` hands it over without exporting the key. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: keep the folders a half-typed path already names The trailing-separator guard gave up on `f/demo/` entirely, which dropped the whole trail to the kind chip and brought `f/demo` back on the first character of the name. The levels the path does name come back now; only the leaf waits. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: pin holds the first slot, and the nav table says what it shares Pinning brings the sidebar's handle back, and from behind it the unpin button sat one slot over from where the pin had just been clicked — so a second click in the same place opened the sidebar instead. An operator is detached by default, which makes that the default state of the feature rather than an edge case. `NAV_PAGES` claimed one table stops a page being called one thing in the nav and another in the header, which holds for the seven entries the sidebar's main group is built from and not for the four grouped separately — `/routes` was "Triggers" in the header and "HTTP" in the nav. The comment now says which is which, and that entry is named for the page rather than its group. `sidebarPageAllowed` gets a table test: it decides what an operator sees, and its `=== true` is what a future `Option`-style default would silently change. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: the band names the path Deploy will create, and keeps the summary readable A brand-new app is parked at a `draft_<uuid>` placeholder, and the band named that rather than the path its Deploy will create — `newEditedPath` refuses the placeholder for exactly this reason, and the editor's own bar read it. Both app editors register it now. Verified: the trail reads `u/admin/gentle_app` while the URL is still the draft. The band's summary gets the `title` the editor's own bar had, so one the bar truncates can still be read on hover. The wrapper that hid AppExportButton on a phone never hid anything: the component draws no trigger — it is the export drawer, which portals to `body` — so the class toggle was inert in both states and the comment read as if something moved. Dropped from both app editors. Two comments corrected: `NAV_PAGES`' `icon` does reach the breadcrumb for all eleven entries (`NavBreadcrumb` renders `routePage.icon`), so only `operatorKey` goes unread for the four the sidebar groups separately; and the raw editor's phone note described folding that does not happen — the file-sidebar toggle stays in the band, Jobs and the export are already in the menu, and AI is what stands down. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: an item the picker files under no kind keeps its name in the band The merge brought main's agents detail page, which reaches DetailPageHeader with no `errorHandlerKind` — and the band's item required one. `WorkspaceItemKindIcon` falls through to the script glyph for anything it does not know, so defaulting would have labelled an agent a script; the kind is optional now and the trail names the item without claiming it is one of the three. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: the file sidebar's toggle leaves the band The band is the workspace's header, not the raw editor's layout controls. ⌘B still folds the file sidebar, and the editor's own bar keeps the button where it draws one — a session pane. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: the scroll edge stops measuring, and the comments describe the code The band's edge listener captures every scroller in the app — Monaco, the audit table, a run's logs — about once a frame while any of them moves, and it took two `getBoundingClientRect()` reads before looking at `scrollTop`. It now answers from `scrollTop` first and only measures when that answer differs from what the band draws, which is the transition rather than the steady state. The rect check still authorizes every change, so a scroller that does not start at the content's top still cannot claim the edge. The two agent routes main just added size themselves to the viewport, which is 44px more than the box the band leaves them. They measure 856 either way — the layout's `min-h-0` column clamps them — so this is the sweep the rest of the branch already had, making the height follow the box rather than depend on a parent's clamp. Six comments described the conversion rather than the code, which AGENTS.md calls out by name. Each now states the constraint a reader could break: why the summary keeps its popover here, why the audit hint is `afterName` and not an action, why a run registers a `section` rather than an item, why the Runs filters are `actionsFlexible`. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * Revert "fix: the file sidebar's toggle leaves the band" This reverts commit |
||
|
|
a85d0b76cc |
feat: add Pi template to the AI sandbox picker (#11619)
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
c75113a235 |
capitalize AI Decision labels to match AI Agent (#11583)
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
3cba8a7e4c |
feat: add an AI decision flow step (TypeSafe's Jev, Cloudflare's Clef) (#11474)
* feat: add an AI decision flow step on TypeSafe's Jev An `aidecision` step asks TypeSafe's Jev typed questions (choice, score, yes/no) about a state and returns calibrated answers. It is a plain step: a flow routes on the answers with a Branch to one after it, which the editor builds and keeps in step with the questions. It can also be an AI agent tool, where the calling model supplies the state. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix: read single-quoted branch conditions and flag branches on a removed question Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix: route decision tools by their tag and keep structured questions as JSON The questions editor writes only on an edit, so opening a step leaves its value untouched, and questions the cards cannot hold stay in a JSON editor. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix: re-pick the questions editor mode when the value is replaced from elsewhere Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix: keep the questions JSON editor's text in step with the value Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix: recreate the questions JSON editor when the value is replaced from elsewhere Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * feat: run AI decisions on Cloudflare's Clef as well as TypeSafe's Jev A `cloudflare` provider kind reads the hub's `cloudflare` resource (token and account id), calls the model's Workers AI URL, and unwraps Workers AI's `result` envelope. Like TypeSafe, it serves decision steps only. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019sEUVZVYBjkzkaVkjbFeAL * feat: branch from each AI decision question, and align its editor with the brand guidelines "Branch on this question" now sits in each choice question's card, which also links to the Branch to one that routes it and flags options it misses or branches it no longer matches. Labels, errors, cards and icons follow the form guidelines and the Branch to one's cards. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019sEUVZVYBjkzkaVkjbFeAL * feat: branch on an AI decision from its graph node A decision with a choice question nothing branches on yet shows a button beside its node that inserts the Branch to one, as its question card does. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019sEUVZVYBjkzkaVkjbFeAL * fix: resolve Cloudflare resources in the AI proxy, and use the design-system button on the graph Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019sEUVZVYBjkzkaVkjbFeAL * fix: put the decision_inputs test's doc comment back on it Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019sEUVZVYBjkzkaVkjbFeAL * chore: regenerate the flow schema in prompts and the chat after the AiDecision description edit Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019sEUVZVYBjkzkaVkjbFeAL * feat: switch AI decision questions between the form and JSON JSON is always available; the form is offered whenever its cards can hold the questions, and a value they cannot hold still opens in JSON. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019sEUVZVYBjkzkaVkjbFeAL * fix: show step ids as badges and use the JSON toggle of the run forms Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019sEUVZVYBjkzkaVkjbFeAL * fix: quote option names in the AI decision branch alerts Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019sEUVZVYBjkzkaVkjbFeAL * feat: remove stale branches from the AI decision question card An empty branch is removed directly; one with steps asks first, naming how many steps go with it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019sEUVZVYBjkzkaVkjbFeAL * feat: branch on yes/no AI decision questions, and test a decision step from the AI chat A yes/no question branches like a choice: "Branch on this question" writes one "yes" branch on `noul >= 0.5`, with the default as "no", and the helper still reads it once the threshold is tuned. The AI chat's step test runs a decision alone as a one-step preview, taking the state the chat passes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019sEUVZVYBjkzkaVkjbFeAL * fix: record removing several stale branches as one undo step Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019sEUVZVYBjkzkaVkjbFeAL * fix: name the typesafe resource type TypeSafe Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019sEUVZVYBjkzkaVkjbFeAL * fix: store TypeSafe as the typesafe resource type's display name, not in the word map Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019sEUVZVYBjkzkaVkjbFeAL * fix: leave the typesafe and cloudflare resource types to the hub instead of seeding them Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019sEUVZVYBjkzkaVkjbFeAL * docs(AGENTS): resource types ship through the hub, not migrations Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019sEUVZVYBjkzkaVkjbFeAL * fix: show the questions JSON format beside the JSON toggle Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019sEUVZVYBjkzkaVkjbFeAL * fix: give the questions JSON format in the field's description Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019sEUVZVYBjkzkaVkjbFeAL * fix: style the decision's graph branch button like Add branch Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019sEUVZVYBjkzkaVkjbFeAL * fix: show the questions JSON format only in JSON mode Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019sEUVZVYBjkzkaVkjbFeAL * feat: show each question's branching under the questions JSON editor Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019sEUVZVYBjkzkaVkjbFeAL * fix: drop the redundant In JSON prefix from the questions format Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019sEUVZVYBjkzkaVkjbFeAL * fix: shorten the decision state's description and show an example as its placeholder Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019sEUVZVYBjkzkaVkjbFeAL * fix: escape a schema placeholder before the JSON editor renders it as HTML Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019sEUVZVYBjkzkaVkjbFeAL * fix: give the decision state's placeholder a text and an object example Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019sEUVZVYBjkzkaVkjbFeAL * chore: update ee-repo-ref to 154cbccb6b8d47bf662b5507882917b5933d5a45 This commit updates the EE repository reference after PR #839 was merged in windmill-ee-private. Previous ee-repo-ref: eaf38c1388f3cc5bece163404fffa959ede8cae0 New ee-repo-ref: 154cbccb6b8d47bf662b5507882917b5933d5a45 Automated by sync-ee-ref workflow. --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> Co-authored-by: windmill-internal-app[bot] <windmill-internal-app[bot]@users.noreply.github.com> |
||
|
|
47525b211a |
perf: shrink the module graph that gates first paint in dev (#11373)
* perf: shrink the module graph that gates first paint in dev * docs: drop the stale synchronous-icons claim on the import card * fix: replay search opened before its modal loads, guard lazy icons * fix: only intercept search before load where the modal mounts * perf: mount app-shell modals on first open and keep monaco off the shell * perf: load the icon map on first read, not at module evaluation * fix: report stale chunks with a reload toast, guard the home page against monaco |
||
|
|
6186a0645d |
feat: edit variables, resources and triggers in their own session tab (#11206)
* feat: edit variables, resources and triggers in their own session tab Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: take a trigger's flow kind from its config and name the written trigger Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * refactor: one operating-workspace context for editors acting on a session's workspace Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: reload page item tabs only in sessions acting on the tool's workspace Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: resolve open in workspace for every preview tab kind in one place Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: guard every component under a session editor against the navigation workspace Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: show a page item tab whose item is gone instead of mounting its editor Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: follow a saved page item in the tab's own workspace and restore in-frame rows Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * feat: close a page item tab from its editor header Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: judge trigger permissions by the user acting in the session workspace Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: judge every session-editor permission by the user acting in that workspace Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: keep session permissions reactive to the acting role and restore tabs as last seen Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: default Path's owner controls to the user acting in its workspace Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com> Co-authored-by: Ruben Fiszel <ruben@windmill.dev> |
||
|
|
08d876aebf |
fix(frontend): recompute dataflow edges when selecting a step (#11070)
Claude-Session: https://claude.ai/code/session_01Vk3d9DpuPuV8C8nKSeGCqC Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com> |
||
|
|
b4be8bc535 |
fix(frontend): clear the flow graph selection through xyflow's store (#11056)
Selecting a step in the flow editor sometimes opened the Settings panel instead of the step that was clicked. SelectionManager.selectId() clears xyflow's own selection before setting ours, and that clear was wired to clearFlowSelection(), which resets offsetNodeCache and reassigns nodes. That hands xyflow node objects it does not recognise, which is what makes it drop the flag — but it also makes it re-create every node's DOM: 126 elements on a 25-node flow, on every selection. Graph nodes select on pointerdown. A click is dispatched on the closest common ancestor of its pointerdown and pointerup targets, so when the release lands in that teardown gap the browser hit-tests to the pane, the click addresses the pane, and onpaneclick clears the selection back to the settings sentinel. Clear through store.unselectNodesAndEdges() instead, so no node object changes identity and there is no gap to fall into. clearFlowSelection keeps its two group-creation callers, which rebuild the graph anyway. Claude-Session: https://claude.ai/code/session_01R7caEKonPr2DmvsWRR6bCK Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com> |
||
|
|
e63072c216 |
fix(frontend): restore heading sizes in note markdown and keep group notes on id change (#11047)
* fix(frontend): restore heading sizes in note markdown and keep group notes on id change Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0182GroR5mvi9ksRTMmBT7nE * fix(frontend): scope the note cleanup deferral per note Address local review nits: the header comment overstated the heading ramp (h3 sits at body size in the xs and sm scales), and the mid-update deferral bailed out of cleanup for every group note rather than the one holding the unrendered module. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0182GroR5mvi9ksRTMmBT7nE * perf(frontend): traverse modules without collecting a discarded array Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0182GroR5mvi9ksRTMmBT7nE * test(frontend): show the three markdown prose presets in the kitchen sink The Markdown tab rendered only the default preset, so a change to the shared heading scale could not be compared across the surfaces that use it. The chat sample gains headings for the same reason: it is the only place the assistant bubble renders at panel width without an AI provider. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0182GroR5mvi9ksRTMmBT7nE * refactor(frontend): validate group notes against the flow, not the render A group note's members are module ids, so the flow's own module list decides whether one still exists. Validating against the rendered nodes instead needed a special case for collapsed groups, and still dropped a live module in the pass after its id changed. Both cases are the same mistake, and checking the source of truth removes them together with the collapsedModuleIds parameter. Path completion keeps working off the rendered graph, since it needs the edges, and now skips a note whose members it cannot all see rather than dropping them. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0182GroR5mvi9ksRTMmBT7nE * fix(frontend): name a new note "Note", not after its internal type The prefill lands inside the user's own note, and "Free note" / "Group note" are the serialized type, not words anyone says about a note they just drew. The menus that create them already say "Add note". The heading goes to h2 as well: h3 computes to the body size in the note scale, so the prefill's own title did not read as one. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0182GroR5mvi9ksRTMmBT7nE * docs(frontend): describe what collapsedModuleIds is still for Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0182GroR5mvi9ksRTMmBT7nE --------- Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com> |
||
|
|
519a5c8bc7 |
fix(frontend): stop hover flicker on asset nodes shared with an overflow popover (#10996)
Claude-Session: https://claude.ai/code/session_01HNugALVxFkkAeM5mce4CFQ Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com> |
||
|
|
a0295b20c4 |
fix(frontend): render ordered lists in markdown descriptions (#10973)
* fix(frontend): render ordered lists in markdown descriptions `GfmMarkdown` defaulted to `prose-xs`, which Tailwind Typography does not define — the class only ever matched four hand-rolled rules in app.css, all scoped to `ul`. Every surface on that default (script and flow descriptions, flow-graph notes, markdown job results) therefore rendered `<ol>` with Preflight's `list-style: none` and no typography at all: no numbers, no heading or paragraph rhythm. Route the default through the shared `markdownProse` stacks instead, and cut the app.css list rules down to the dash glyph so ordered and unordered lists share Tailwind Typography's indentation and rhythm. Fixes #10971 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01S6G5gDXJnm6uqch4uCPkPE * fix(frontend): address review nits on the markdown prose fix - default `GfmMarkdown` to the `sm` stack rather than `xs`: the AI-agent tool Message pane takes the default and has no ancestor font size, so `xs` left it smaller than its own label. The group note, whose wrapper is `text-2xs`, opts down explicitly. - regenerate `static/tailwind_full.css`, which raw apps are served and which still carried the deleted list rules. - correct the marker-color rationale: the typography config already maps markers to tertiary, so the rule steps them up rather than rescuing them. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01S6G5gDXJnm6uqch4uCPkPE * fix(frontend): make the note color override an arbitrary value `text-inherit` is not generated: this config replaces the Tailwind color palette outright and defines no `inherit` key, so `[&_*]:!text-inherit` compiled to nothing and notes still rendered in the prose stack's `text-primary`. Verified in the browser: a yellow note's list items now compute to `text-yellow-900`, matching the wrapper and the edit-mode textarea, in both themes. Also drop the `static/tailwind_full.css` regeneration. That file was generated with tailwind 3.4.1 against a config predating the typography theme overrides; rebuilding it today sweeps in 250KB of unrelated churn and would flip every raw app's `.prose` palette from stock gray to Windmill tokens. Its staleness predates this PR and is its own change. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01S6G5gDXJnm6uqch4uCPkPE --------- Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com> |
||
|
|
9c557859c5 |
feat: AI agent evals: datasets, scored runs and comparison (#10633)
* feat: eval datasets and standalone runs for reusable AI agents Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * feat: agent eval drawer with case editor, runs and capture entry points Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * docs: document AI agent eval datasets and standalone runs Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: say how many eval cases the list is not showing Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: address review findings on eval datasets - keep an edited case's conversation and tool inputs: serde(flatten) silently drops Box<RawValue> fields, so the update payload is spelled out - remount the case editor per case so one case's turns cannot leak into another - require jobs:read / flow_conversations:read on the capture endpoints, which UserDB does not gate by token scope - take the dataset lock in create and update so a delete cannot be undone by a concurrent metadata write, and delete cases before metadata - load more cases beyond the first page, and stop capping the agent picker - record that the version stamp is taken at enqueue, not at resolution Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: address round-2 review findings on eval datasets - block operators from dataset and case writes - pass the editor's operating workspace through the drawer and the capture request, instead of assuming the navigation workspace - discard superseded case-list responses so switching datasets cannot land the previous dataset's cases - reject a dataset without a case_id (or vice versa) rather than running an inline case under a dangling association - run unsaved edits inline instead of silently running the stored case - surface the API error body on a failed run - fetch dataset metadata concurrently when listing - $bindable() without a default on the optional open prop - correct the permission and enqueue-time-version wording in the docs Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: run an untouched saved case by reference again The editor writes back keys the stored case omits, so comparing the raw objects reported every unedited case as edited: the run went inline and lost the dataset/case stamp its history depends on. Compare a normalized form, and pin it with a test. Also scope the history query to the drawer's workspace and drop superseded responses. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * feat: show a dataset's cases as a table, and fix round-4 review findings The case list showed one case at a time with no overview. It is now a table with the case, where it was captured from, and its last run — the last-run column is a single jobs query on the path stamp rather than a request per row. Review fixes in the same file: - keep the edit baseline on the selected case rather than looking it up in the loaded page, so a case beyond page 1 is not treated as unedited and run stale - release the loading state when a superseded case load returns early - reload every loaded page after a write instead of collapsing to page 1 - last remaining 'resolved to' wording in the version tooltip Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * feat: run a dataset as an experiment, with scorers as runnables An experiment runs every case of a dataset against one subject and records the exact case set it executed, so a result set stays reproducible while the dataset keeps changing. Each case runs as its own small flow — the agent, then a step per scorer — so a case keeps the run stamp, history query and trajectory view a single run already has, and scorers need no orchestration of their own. Results are read back per step by node id rather than by walking a nested loop's status. A scorer is any runnable taking (input, output, expected): a script, a flow, or a reusable agent used as a judge. A judge is prompted with the case and the answer as one JSON message; a script or flow receives them as named arguments. Scores accept a bare number, a boolean or {score}. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * feat: results table for an experiment, with scorer columns One row per case: status, the agent's answer, and a column per scorer, with the mean per scorer above the table and a link into each case's run for its trajectory. Averages skip cases a scorer produced no number for — counting a missing score as zero would read as a regression. The drawer's left pane becomes Cases / Results, and Results carries the scorer picker and Run dataset. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * feat: compare an experiment against a baseline Per-scorer deltas on each row and on the mean, and a filter down to the rows that regressed. Rows join by case id, so a case added after the baseline ran has no delta instead of counting as a change. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: address round-5 review findings on experiments - match scorers by label when diffing two experiments; joining by array position subtracted one scorer from another whenever the scorer sets differed - report a row's status from the case job, not the agent step, so a case whose scorer failed no longer reads as a success - delete a dataset's experiments with it: they hold copies of its cases, and a recreated dataset of the same path would have exposed them - select the experiment that Run dataset just started instead of leaving the table on the previous one - expected is scored now, so stop describing it as having no consumer Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: address round-6 review findings on experiments - hold the dataset lock across an experiment launch, so a delete landing between reading the cases and writing the experiment cannot recreate the deleted dataset's inputs - match scorers between experiments on kind and path, not on label: labels default to a path's last segment, so f/a/quality and f/b/quality compared against each other - average mean deltas over the cases both runs scored; comparing each run's own average reported a regression from a case the baseline never ran, with no regressed row to point at - openapi: the row status is the job's, which is also canceled/skipped; runEval takes scorers; the update-case body no longer advertises source, which the handler deliberately ignores - record why the experiment prefix cannot reach a sibling dataset Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: address round-7 review findings on experiments - release the dataset lock for the push loop and retake it for the write, re-checking the dataset still exists: holding it across the whole launch made every capture and case edit on that dataset 409 until the last job queued - assemble experiment results with bounded concurrency; a 100-case, 3-scorer experiment was 400 sequential lookups, each itself several queries - clear the baseline when it becomes the selected experiment, which was comparing a run against itself and reporting zero deltas - take the header mean over the same cases as its delta while comparing, so the two numbers beside each other describe the same set - a canceled or skipped case is no longer the same grey dot as a running one Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: address round-8 review findings on experiments - verify the dataset's identity, not just its existence, before recording an experiment: the path can be deleted and recreated during the push loop, and the experiment holds copies of the old dataset's cases - give the recording lock a longer budget than a case edit, since its jobs are already queued and giving up strands them, and say so when it fails - keep score lookups sequential within a case: nesting two bounded streams multiplied into 32 in-flight queries against a 50-connection pool - clear a baseline that no longer belongs to the loaded experiments, so switching datasets does not leave comparison mode on with nothing to compare - keep a scorer's own mean when the baseline never ran it, instead of blanking a column full of numbers - EvalCaseDraft.expected no longer claims nothing scores it Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: do not trust an experiment's job ids, and require write to record one Experiment objects live in workspace object storage, which a script can write directly, and results are read on the unrestricted pool — so a forged experiment naming another flow job returned output the jobs API would have refused. Only jobs this server stamped with that experiment's id are read now. Also from round 9: - recording an experiment requires write on the dataset, not read: it persists into the dataset's namespace and its shared list - clear the results table when the selection changes and surface a failed load, instead of labelling the previous experiment's numbers as the new one's - a storage fault is no longer reported as a deleted dataset - the lock-timeout message at the recording site no longer says to retry, which would run the whole dataset again on top of the jobs already queued - ExperimentRow.status documents canceled and skipped Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: bind the experiment trust check to the requested dataset The previous check matched jobs on the experiment id alone, which the stored object supplies — so copying another dataset's experiment JSON under a readable key carried its jobs' output along with it. A job is now only read if it was stamped for this experiment *and* for the dataset the caller's read access was checked against, and an experiment that names a different dataset is not served from this key at all. Also from round 10: - add the .sqlx entry for that query; without it every SQLX_OFFLINE build failed - serve results over GET: as POST the route-scope middleware classified a read as ai_evals:write, locking read-only tokens out of their own results - clear the selected and baseline experiments synchronously when the dataset changes, so the previous dataset's id is not requested under the new one Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: address round-11 review findings on experiments and scorers - give scorers the whole case input, not just the message: an answer that came from attachments or a replayed conversation could not be judged on it - accept a judge's boolean and structured {score} answers, including stringified ones, and pin every documented scorer shape with a test - record an experiment for the cases that did launch when a later push fails, instead of leaving those jobs running with nothing to attribute them to - do not capture a preview parent's synthetic runnable_path as a host flow; the saved case could not be rerun - clear the case table before loading a dataset and surface a failed load, so a failure cannot leave the previous dataset's cases under the new name - keep the results table through a refresh of the same experiment - exclude flow-step jobs from the per-case last-run lookup - drop case sets from the experiment list, which is only used to pick a run - report a database failure at the recording lock as itself, not as contention Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: address round-12 review findings on capture and run history - load flow_node.flow for flownode parents: an agent inside a deployed branch or loop captured without its agent, host flow or tool bindings - decide host_flow_path by whether the path resolves to a flow, not by job kind: excluding previews wholesale also dropped the flow editor's step test, whose path is real - page the per-case last-run lookup by created_before until the loaded cases are covered; one page of 200 reported older cases as never run - do not record an experiment when nothing launched - only attach the case input to a job when a scorer will read it - keep the case table through a save; only a different dataset clears it - drop the superseded duplicate comment on the score parser Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: stop refetching run history on every case write Reading the case list before the first await made the whole job-history query a dependency of it, so every save, delete and Load more refetched up to 1000 job rows and blanked the column. Read untracked instead. - an empty Last run cell now distinguishes never-ran from not-found-within the page bound, which the comment already claimed and the cell did not - reloading a dataset no longer replaces a populated table with a skeleton - keep the score-parser comment that describes every shape it handles Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * refactor: keep eval datasets in Postgres instead of object storage Datasets, cases and experiments become rows (`eval_dataset`, `eval_case`, `eval_experiment`, `eval_experiment_case`) rather than objects under a `wmill_eval_datasets/` prefix. What a run produced is still the job's: only case inputs and an experiment's case snapshot are stored. This removes the machinery the object store needed: - The advisory lock and the read-modify-write of a per-dataset JSONL. A case is a row, so there is nothing to serialize. - The launch-time identity check on the dataset. The foreign key makes a concurrent delete fail the transaction instead. - The trust guard on an experiment's job ids, which existed because a script can write workspace object storage directly and could forge an experiment naming somebody else's job. An experiment now chooses every job id and records itself before pushing anything, so a launch that dies partway leaves a recorded case whose job is missing rather than a running job nothing accounts for; cases that never reached the queue are removed again. Row-level security on `eval_dataset` is the authority on who may read or write a dataset, so `extra_perms` grants work and the rule is not mirrored in Rust. Cases and experiments carry a read policy derived from their dataset and no write policy: they are written on the unrestricted pool after the dataset row itself has been asked, with `SELECT ... FOR UPDATE`, whether the caller may write it. Cases are capped at 256 KiB each and 10 000 per dataset, refused rather than truncated. Attachments are S3 references, not inline bytes, so a case that approaches either cap is a mistake rather than a use case. Evals no longer need the `parquet` feature or a configured workspace object storage. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * style: align the eval drawer with the design system - Scorer chips are `Badge`s rather than a hand-rolled bordered span, and the section header is a `Label` with its tooltip, as are the case editor's fields (which also gets the label colour right). - The results table showed status as a coloured bullet, which says nothing to a colour-blind reader. It now carries the same icons the runs table uses, with the status as its accessible name. - Feedback colours move to the `-500` shades the brand guidelines name. - The conversation JSON error uses `TextInput`'s `error` prop for the border and the caption style for the message, as elsewhere. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * feat: author an expected answer, tags and attachments on a case Every scorer is handed `(input, output, expected)`, but nothing could produce an `expected` except a conversation capture: the case editor had no field for it and a captured run left it empty. So: - The editor gains Expected, Tags and a read-only list of the attachments a captured case carries. Expected is plain text, or JSON when the answer has structure. - Capturing from an AI agent run keeps what that run answered, which is the only moment a reference answer exists for free. The results table also laid itself out by content, so a long answer pushed the scores — the numbers the table exists for — off the edge of the pane. It is fixed-layout now, with the text columns bounded. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * docs: expected is captured from a run and can be authored Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * feat: link a saved agent when inserting an ai agent step "AI Agent" in the step picker was a leaf that always created a blank step, so reusing a saved agent meant inserting a blank one, opening its step input and linking it there. It is a category now, like Flow and AI Sandbox, listing the workspace's `ai_agent` resources next to a blank option, filtered by the picker's own search. A picked agent produces a step that is already linked rather than one linked afterwards: `agent` set, no tools, and only the flow-local `user_message`/`user_attachments` transforms. Seeding the brain keys there would leave transforms a linked step never reads and that `AgentResourceBar` strips on its next link change. Each `on:new` forwarder rebuilds the insert detail field by field instead of spreading it, so a new field is dropped unless the forwarder names it. `agentPath` is typed on both `GraphEventHandlers.insert` and `FlowGraphV2`'s `onInsert` so the next one to forget it fails the check. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * feat: restore the link on cancel and simplify the agent bar Cancel on an agent edit forked the step into a standalone copy, which is the opposite of what the word means and needed a paragraph under the card to explain. It discards the edits and re-links the step now, leaving the agent untouched; diverging from an agent is Unlink's job, on the linked card. This flow's `tool_inputs` survive the round trip as overrides, so Cancel no longer folds them into the tools the way Unlink does. Linking a step to a saved agent happens in the step picker at insert time, so the bar's own resource picker is gone and "Save as agent" is the one action left. Its `+` button was a trap besides: it opened the generic resource form, where an agent would have to be written as raw JSON. The card itself was `surface-secondary`, the sections token, so in dark mode it was darker than the pane and read as a sunken well rather than an elevated card. It uses `surface-tertiary` as the brand table prescribes, its tool chips are `Badge`s, and the editing card no longer overflows the pane and clips its own buttons. The remaining tooltip follows the inline `Label` convention rather than sitting in a flex row whose gap stacked on the trigger's own margin. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * feat: rework the AI agent evals surface into one table Evals become a single pane: a dataset of cases, one column per scorer, one row per case, with the run being looked at chosen from the toolbar. Runs are permanent. Running the whole dataset opens one; running a single case records nothing at all — it is a job, and looking at what it did is not a claim that it belongs in the history. Its result and its scores sit over the row until they are saved as a run, which carries the cases that were not rerun and the scoring jobs themselves, so the number that is saved is the number that was looked at. A scorer is a runnable: a judge agent or a script, created in one click and edited in place. Scores carry a reason and per-assertion checks, shown on hover with a rescore button. What ran is always named. A run records the agent version, or — for a configuration that is not deployed — a hash of it, so a table can say that its numbers describe an agent that no longer exists: those rows dim and the table offers to rerun. An agent's draft can be run directly instead of the deployed value, and once those edits are deployed the runs that made them are recognised as that version. A step with no agent of its own is evaluable too, and saving it as an agent moves its history onto it. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * feat: keep an agent's in-progress edits on the agent Editing a linked agent forks it into the step, which is what makes the edits runnable there — but the agent is what is being edited, so that is where the unsaved state belongs. The edit is mirrored into the agent's own resource draft as it is made. It then survives leaving the flow, shows the agent as drafted wherever it appears, and is what evals run when asked to run the draft rather than what is deployed. Deploying or cancelling clears it; opening Edit without changing anything does not mark the agent as drafted. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * feat: shape the evals surface around a saved agent Evals hang off an `ai_agent` resource, so the surface is now only ever about one: the `draft` subject kind, the standalone-step subject and the move that carried a step's history onto a newly saved agent are gone. - A run is permanent and numbered per agent. Running a single case is a trial: it answers in the panel and never touches the table. - "Run scorers only" opens a run of its own that reuses the answers of the run you are looking at, so a scorer added later measures what already ran without calling the agent again. - A draft run whose configuration is later deployed is stamped, once, to the version it became, so its label stops reading `v23 + edits` forever. - A scorer can carry a pass threshold, read off the scores already recorded. - The table is the case, its answer and one number per scorer; datasets are created and edited in a drawer; a run that executed an earlier state of the current draft says so above the table, in one line. - Which agent a step is, whether it is being edited, and which version it is on is a strip above the step's tabs, because it is true of every tab. - Capturing a case from a step test or a conversation is dropped, and with it the `memory` override on a linked step that nothing set. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * feat: run past versions of an agent, and number versions per resource The evals home becomes one table of every run of the agent, whichever dataset each is of, with one badge per scorer. A list spanning datasets cannot hold every dataset's scorers to look a name up, so a score carries its name and kind with its number, and thresholds are joined in per run and column. Run now asks what to run: the latest agent, resolved when the run executes as a flow step does, any past version, or the unsaved edits. Pinning is a subject kind of its own, since a linked step resolves the resource live and inlining is the only way to run a version that is no longer current. Scorers move into the edit-dataset drawer. The column header over a run reports and nothing else: a run is permanent, and a control there that changed the columns would edit the past from the one place that must not. Adding one offers four ways rather than two, writing and reusing being different jobs, and both new kinds open with a summary filled in. Versions are numbered per resource. `resource_version.id` is one identity sequence for the whole table, so an agent saved nine times read v4 ... v24, and the gaps counted writes in workspaces the reader cannot see. The id stays how a version is addressed; the new number is what it is called, in the resource history drawer as well as here. It is assigned on write rather than counted on read because trimming past the cap and clearing a history both take the oldest rows, and counting the survivors would renumber a version a run already names. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * fix: read the dataset a remembered selection names Reopening the evals modal restored the last dataset from storage as a bare path, without reading the row it names. Every "is this already the one?" test compared against that selection, so all of them short-circuited and the dataset was never loaded: editing it opened a drawer with no summary, no scorers and no cases. The remembered path is now brought into context the same way any other choice is, and the tests compare against the dataset that is loaded rather than the one that is selected, so a selection can no longer stand for a read that did not happen. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * feat: give dialogs a trail in their header A dialog deep enough to navigate had nowhere to say where you were: the header held a fixed title, and the way back was a control each body placed for itself, somewhere in a toolbar that moves with everything else the toolbar holds. The header is the one part of the surface that does not move, which is where the trail belongs. `Modal` takes an optional `trail` of levels below its title, rendered as a breadcrumb whose ancestors are the way back. Declarative on purpose: callers of this depth already hold the state that says where they are, so the dialog reads it rather than owning a stack they would have to push and pop in step with it. Escape follows the trail. Leaving a level is what someone deep in a dialog means by it, and closing the whole surface throws away the navigating they did to get there; at the root it closes as before. That only works if a dialog can tell it is the surface being addressed, so `Disposable` now answers `isTopmost()` and the dialog asks before acting: it keeps Escape for itself, so nothing else was arbitrating between it and a drawer opened from inside it, and both were acting on one key press. Evals is the first caller: its runs list is the root, a run is a level in it, and the back button that used to sit above the table is gone. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * fix: portal dialogs out of wherever they were opened from A dialog rendered in place inherits whatever the calling component happens to sit inside. One `transform`, `filter` or `overflow` anywhere above it makes its `fixed` positioning resolve against that ancestor instead of the viewport, and a surface meant to cover the app is then confined to a box it never asked for: the nav rail paints over it and its own edges are clipped. Drawers have always portalled for this reason. Dialogs only did so when an enclosing pane claimed them, and rendered in place otherwise, so the same screen could show a drawer over everything and a dialog trapped behind the nav. They now portal the same way: to the pane when one claims it, to `body` otherwise. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * fix: make the dialog's title the first step of its trail The trail listed levels below the title, so a dialog one level deep read "Evals > All runs > Run 20 · v6": three steps for two places, the first two of them the same place under different names. The title is the root, so it is the root's own segment, and the trail a dialog is given is now the whole path with that segment at its head. Its height stopped moving too. A heading carries a line-height of its own, so a header holding only an h3 stood six pixels shorter than one holding segments as well, and the dialog's whole top edge stepped as you navigated. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * fix: sharpen the evals controls around where you are standing Each screen now offers what belongs to it. The list starts runs; a run is a record, so it offers only the one thing that acts on the record itself, which is measuring the answers it already stored. Starting a fresh run from inside one asked which agent and which dataset from the screen least about either, and scoring an existing run was offered from the list, where there is no run to score. Which run and what it is read against are one question asked twice, so they sit together rather than at opposite ends of a row. Choosing what to run is now a toggle over the two states worth naming, the draft and the saved agent, with every earlier version one click further: running an old version is deliberate, and a list made all three look alike. The draft is read when the dialog opens rather than taken from the caller's polled copy, which could be seconds behind an agent edited a moment ago and would leave the option out exactly when it is the reason for opening the dialog. The dataset field carries its path under it and its edit button on hover, as a resource picker does, so the closed field says what the open list said. Edits waiting on an agent are a "draft" here as everywhere else in Windmill, rather than "+ edits". The dialog runs an evaluation rather than "the agent", which is what it was already called everywhere it is recorded. An agent being edited keeps its evals button on a line of its own, clear of the decision to save or discard. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * fix: settle the evals controls on the patterns Windmill already has The version choice uses ToggleButtonMore, as the AI provider picker does: the two states worth naming stay in the group, the rest are behind the overflow menu, and the one you pick joins the group rather than appearing in a second control below it. The deployed one says which version it resolves to. A run offers nothing to start. Scoring an existing run again was the last thing left there, and it was one button explaining a distinction that the run and the dataset already make between them. The warning that a run executed an earlier draft is about the run on screen, so it goes when the run does rather than following you back to the list, and it sits against the table instead of inside a frame of its own. A dataset just created stays open for its scorers and cases: those are what a dataset is, they can only be added to one that exists, and closing on create sent you to find it again to add them. Scorer settings are a cog rather than a word, now that the row holds three actions. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * fix: close the gap in the version toggle and say what naming a dataset does The overflow trigger is not a pill, so the room it reserves showed as a gap between it and the button before it; it is pulled in by that much. The dataset field gets its clear button, which is also the slot the edit button is positioned against, so the two now sit where a resource picker puts them. Naming a new dataset said nothing about what happens next, and the drawer looked like it was missing the rest of itself. It says so instead: a scorer and a case both belong to a dataset, so there is nothing to attach either to until this one exists, and creating it leaves the drawer open on them. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * feat: choose a dataset's scorers while naming it A scorer is a reference to a runnable, not a child of the dataset, so it needs the dataset's name but not its row. The list is collected in the drawer while the dataset is being named and sent with the create, which already accepts one, so a dataset arrives holding the columns that were chosen for it rather than being made empty and then edited to hold them. Cases stay where they were: a case *is* a row of the dataset, so there is nothing for it to be a row of until one exists. The drawer says which of the two is which instead of leaving the screen looking like it is missing the rest of itself. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * fix: level the version toggle and name the dataset in its own field The overflow trigger stands a row taller than a toggle button, so the group grew to its height and left the sunken background showing under every pill beside it. Every child of the group is the same height now, which is why the AI provider picker never had the band: it sizes them all alike. The dataset field says the summary with the path after it rather than carrying the path on a line below. The list stacks the two, which a one-line field cannot do, so it says both the other way round. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * fix: tidy the evals forms and the run's own controls Picking a scorer that exists chooses between two sources rather than showing both: the ones already measuring something, and everything else in the workspace. The first list says what each is called with its path under it and what it already measures on the right, instead of three columns that were the same path truncated three ways whenever a scorer had no name of its own. A dataset's drawer says what it is for on the page rather than under an icon, and its summary is sized like the field beneath it. The run's own row lines up with the table under it, the warning above that table is spaced off the rule rather than sitting on it, and adding a case is gone from a run: a run is a record of cases that were answered, so curating them from it is editing what it measured. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * feat: create a dataset holding the cases written for it Creating a dataset takes the cases to create it with, so one can be assembled in a single act instead of made empty and then filled in. The drawer holds them while the dataset is being named, gives them ids of its own to be edited by, and sends them with the create. Every case is checked before the dataset is written. `eval_case` grants users no write, so the rows cannot be inserted in the transaction that creates the dataset under the caller's own policies; validating first is what keeps "created holding these cases" from becoming "created, holding some of them", and the rows that do follow go in one transaction of their own. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * fix: name the button for what it opens, and say what each version is Starting an evaluation asks which state of the agent and which dataset, and both cost a provider bill, so a button that read as spending one on the way past was lying about the click. It opens something, and says so. Running one case from the panel keeps its own name and its play icon, because that one does run on click. The version options say what they are rather than what they are not: what a flow step would or would not run is a fact about somewhere else, and someone choosing what to evaluate is not standing in it. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * fix: give the editing card two rows and mark evals as beta At the width of a step panel the card's one row wrapped: the line naming the agent, the line saying what saving does, and the two buttons deciding the edits' fate all fought for it. Deciding gets a row of its own, and evals sits against the line it is about, since evals of an agent being edited run the edits. Evals is named wherever it is offered. It read as a word in one state of the card and as an icon in the other, which is two things to recognise for one door. The dialog carries a beta badge against its own name, before any level below it: every way in lands there, so it is said once and stays put as you navigate. The version toggle spells out which is which. Both are the agent at v2 and the difference between them is the whole choice, so it is worth the width. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * fix: name a new dataset, and lay the scorer's settings out like a step's inputs A new dataset arrives called "Dataset 1", which the path follows as it follows any summary: a dataset with none was one every table could only call by its path, and the two seeds are what the summary rule already produces. Scorer settings put each field's description between its label and its input, where a step's inputs put theirs, and its inputs are the size the rest of the drawer uses. The runnable behind the column is a link to it with its kind's icon, since it is a resource of its own and the one thing about it these fields cannot change. The line explaining that a pass line re-reads recorded scores went: the threshold is a number to set, and how it is applied is not a decision being made here. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * feat: curate a dataset in the drawer and save it in one act The drawer holds the cases while they are edited and writes them when it is saved: added, changed and dropped, whichever it is. Typing no longer writes, so a set is never half saved while someone is still deciding what is in it, and Save means the same thing whether the dataset exists yet or not. A case panel offers reading rather than acting. Running one case now and editing one from a run were the last two ways to change a record from the screen showing it, and the machinery behind the first went with it. The answer is rendered as the prose it is, under what it is: the case's result, whichever run is selected above it. The rest is what the run's table was doing to its own edges: a column name is clipped to its column rather than running into the next, the table squares off against an open panel, and that panel closes with the run it belonged to. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * fix: one border above a table, and a link to the run's job The row above the table drew a bottom border and the table draws its own top edge, so every table sat under two lines. The row keeps its spacing and the table keeps its edge. A column header no longer spins while its scores arrive: the cells under it are where the numbers are missing, and they say so themselves. The beta badge is the height of the word beside it rather than of the line it sits on. A run is one flow and therefore one job, so the run says where that job is: what it is doing, what it cost and what it logged are all there rather than reconstructed from the table. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * feat: stream scores as each scorer finishes, and show them per case A scorer runs after the agent inside the case's own iteration, so its verdict can be read as soon as its step is done. Waiting for the iteration to end held every column of a case back until the last of them finished, which is why answers arrived one at a time and scores all at once. Reading a job that is still running needs one guard: a module with nothing in it is a step that has not run, not one that produced nothing, and recording the second makes a failure that never goes away. The panel beside the table shows what each column made of the case and why. The reason a judge gave was stored and never shown, which is the half of a score that says anything. It stops repeating the question the header already asks, and a case still running reads as waiting rather than as an answer that says "Running". A run is a number beside a dataset, so the list puts the two together. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * feat: score a case with every scorer at once The scorers of a case read the answer and never each other, so they ran one after another for no reason: measuring a case now takes as long as its slowest column rather than as long as all of them. Each is a branch of its own, kept from failing the others, so a judge that errors costs its own column and no more. An iteration is three steps again — answer, payload, scores — rather than one per scorer, and each branch is named for the column it produces, so the graph of a run says which scorer did what instead of spelling out an id. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * fix: read a judge's score out of the JSON it nearly wrote A judge quoting the agent inside its own reason writes those quotes unescaped, which is invalid JSON and also the most ordinary sentence for it to produce. The whole verdict was being thrown away over it, so a column that had a number reported having none. The number and the reason are now read straight out of such text. Deliberately not a second JSON parser: it finds the two keys and takes what follows, which is what survives a quote in the middle of a sentence. A case still running says so with a spinner rather than with the word "Running" sitting where its answer goes. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * feat: ask a judge for a shape instead of trusting it to write one A new judge carries an output schema, so the provider holds it to `{score, reason}` rather than the prompt asking it to. Windmill already delivers a schema whichever way the model takes it, a tool for Claude and Bedrock and the native parameter elsewhere, so there is no list of models to keep here. An agent with no runs offers its first one where the first row would be, rather than from a toolbar above a table that has nothing in it. Starting a run no longer picks a dataset for you. It fell back to whichever came first, which on an agent that has never run means offering another agent's set as though it were the obvious one; and with no dataset at all it says so and offers the one move there is. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * feat: report a column that failed throughout, and hold the run dialog The runs overview dropped any column that produced no number, so a judge that failed on every case of a run vanished from the row and read as a column nobody had asked for. The aggregate now reports every column that has cells, with the count of the ones it failed on, and the badge says "failed" where there is nothing to average. A column with no cells at all is still left out: that one was added after the run and has nothing to say about it. Creating a dataset closes the drawer rather than turning it into an edit of what it just made: scorers and cases already ship with the create, so there is nothing left to stay open for. Reached from the run dialog, it gives the screen back with the new dataset selected, and the dialog keeps the version you had already chosen. Also: - the case panel's job link moves to the panel's own header, where its scope is: the job is the whole iteration, not the answer it sat over - one action in the scorer drawer's header, as its neighbours have. The reuse list picks rather than adds, and says which dataset each column already measures - adding a case is the last row of the list it lands in - the pane shows what it has read rather than an empty state it has not earned yet, and its rows say they open - the linked agent card loses a border it had inside another one * fix: keep the linked agent card's outline The card is a thing inside the step's inputs rather than a section of them, and the outline is what says so. Only the rule inside it goes: the detail it separates is already set apart by being detail. * refactor: fit the eval surface to the shipped design * feat: give a nested dialog a back control and the runs list its own moves Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * feat: put a dialog's description under its title Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * refactor: fold a dialog's back control into the crumb it returns to Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * feat: edit a dataset's cases as a table rather than a list beside a form Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * feat: edit a dataset's cases in the grid the data tables are edited in Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * feat: edit a grid cell of prose in place, and cap a dataset at one page Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * refactor: keep the cell editor's styles beside it, not in the vendored theme Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix: keep an empty cell empty and cap the editor's growth Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * feat: name the step that assembles a run for the scorers Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * feat: run the payload step natively, and say so when nothing serves that tag Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix: report an answer as answered while its scorers are still running Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * feat: let a scorer say a case is not one it measures Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix: score the answer, and leave a case with no expected answer unmeasured Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * refactor: split the evals backend into modules Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix: record what a run produced so it outlives its jobs * fix: read only the agent step's own tool jobs into the payload * fix: pin a run's configuration and give the judge the attachments * feat: write a dataset's cases in one transaction * chore: refresh the sqlx cache for the eval queries * fix: drop results a newer selection has superseded * fix: keep a draft the agent editor never opened on * feat: let a run record what it produced instead of waiting to be read * fix: serialize the replacements of a dataset's cases * fix: stop the poller from superseding a read slower than its interval * chore: refresh the sqlx cache * fix: keep a failed read from settling a cell as a case with no answer * fix: hold the case grid while its save is in flight * fix: keep a failed collect step from failing the run it recorded * chore: refresh the sqlx cache * fix: commit an open cell into the save that reads it * refactor: size the eval buttons with unifiedSize * docs: describe a run as the one flow it is * fix: show a run's recorded rows when part of it cannot be collected * refactor: size the remaining PR-added buttons with unifiedSize * fix: save the dataset name that was submitted, not the one typed after * fix: force an open cell into the save that was pressed for it * fix: refuse to score a run whose evidence could not be read * fix: hold one lock over a dataset's case count and its writes * fix: keep one unreadable run from costing the whole runs list * refactor: drop the banned bindable-default from the eval props * fix: hold the scorer controls while the dataset is written * fix: read only the caller's own draft of an agent * docs: say in the contract that a run pins its configuration * fix: say a scorer did not run rather than blaming a missing answer * feat: resume the agent draft you already had when you press Edit * refactor: build the trail and dataset controls from Button * fix: clear the open-cell flag when the drawer reopens * chore: refresh the sqlx cache * fix: read a run's configuration and its version from one snapshot * fix: refuse a dataset path or summary the column cannot hold * refactor: handle the agent draft the way the resource editor does * fix: run only a configuration the launch actually read * docs: bound dataset path and summary where they are submitted * fix: surface a stalled agent draft instead of claiming it is kept * fix: stop claiming a draft holds edits a failed write never sent * fix: word a missing score only once the run says whether the case answered * fix: let a breadcrumb crumb shrink so its truncation applies * docs: describe where an agent's unsaved edits live and what drops them * fix: keep harvesting scores when the run cannot yet word a missing one * fix: report a refused draft write the card was reading as a save * fix: drop the refused draft write when the server copy is taken instead * refactor: build the scorer and dataset pickers from the design system * fix: say what removing a scorer column actually does * fix: drop a refused draft write wherever the server copy is read * fix: let a picker row be as tall as the two lines it holds * docs: record what removing a scorer column does to recorded runs * fix: send a queued draft write before reopening, and drop only what it refuses * refactor: write the agent draft at commit points instead of mirroring keystrokes Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * refactor: run an agent's edits from the step instead of keeping them as a draft Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix: make the diff badge keyboard operable and refuse an edits run without its edits Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix: drop the dataset icon from the scorer picker rows Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix: size the evals buttons like the rest of windmill and call a run of edits edits Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix: count a brain expression as an edit of the linked agent * fix: cap scorers per dataset and report a launched run as launched * fix: harvest scores in one read, refuse duplicate case ids, allow group paths * fix: mint scorer ids server-side, save a dataset edit in one request, check attachments * fix: write a dataset edit and its cases in one transaction * fix: atomic dataset create/edit, reset eval pane per agent, stable pending scorer ids * refactor: govern eval_case writes by RLS so a dataset edit is one transaction * fix: pin launch snapshot, order case locks, cap dataset size, guard stale load * fix: cap dataset bytes on single-case writes, reset run-dialog flag on load failure * feat: migrate eval datasets on username change, settle unspawned cases, drop unused case endpoints * fix: resolve scorer scripts as the caller and pin their hash; migrate scorer paths on rename * fix: bound a failed tool call's error to the payload truncation cap * fix: pin scorer hash as a hex string, reject missing judges, migrate eval authorship * fix: record an out-of-range scorer result as an error, not a score * fix: resolve judges in one caller-scoped read, pin deployed scripts, bound pass_if * fix: settle unspawned cases only when the run completes, and their score cells too * feat: reassign eval datasets and their path references when offboarding a user * fix: use the regex backreference in offboarding eval path rewrites * fix: register eval datasets in offboarding registries, keep resource-version param name * refactor: name the resource-version path param id, since it is the row id not the version * fix: validate dataset paths canonically, clone eval data on fork, surface eval load and launch failures * docs: note MCP tool results are not yet surfaced to eval scorers * fix: show the eval error state on any load failure, not only an empty dataset list * fix: preserve eval case order across a batched save Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LVjewUvXFEjNLLw7kxz41h * docs: scope the eval launch delete-safety guarantee to the assembly window Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LVjewUvXFEjNLLw7kxz41h * fix: only offer deployed scripts as eval scorers, drop unbuilt rescore claim Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LVjewUvXFEjNLLw7kxz41h * fix: enforce 0-1 scorer threshold in the settings drawer and clear stale eval load errors Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LVjewUvXFEjNLLw7kxz41h * fix: scope subject version/hash reads to the caller and keep a 0 pass threshold Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LVjewUvXFEjNLLw7kxz41h * fix: select the saved dataset when creating or renaming from the Run dialog Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LVjewUvXFEjNLLw7kxz41h * fix: gate eval dataset rename on path ownership, not just write access Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LVjewUvXFEjNLLw7kxz41h * fix: tolerate a malformed agent config when resolving the deployed label Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LVjewUvXFEjNLLw7kxz41h * refactor: trim eval code and comments, fix shared select and modal paths Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix: drop the rename warning when editing an eval dataset path Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix: add eval dataset delete, keep summary on partial edits, settle resultless scorer cells Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * test: cover parseThreshold and subjectLabel Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix: hold dataset Save during a scorer write, derive draft_hash only from the carried draft Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com> |
||
|
|
2b4369d7cb |
fix: reject invalid AI agent tool names when the chat writes a flow (#10756)
* fix: reject invalid AI agent tool names when the chat writes a flow Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: address review nits on agent tool name validation Share one AI-agent walk between the providerless-agent and invalid-tool-name collectors, drop the unused validateToolName, and list every reserved id in the tool naming rules. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: describe an agent tool's summary as the name the agent calls it by The OpenFlow schema described `AgentTool.summary` as a short description of the tool, which is the same schema the flow write tools hand the model, so it pulled against the naming rules. Narrow those rules to flowmodule tools, since websearch and mcp tool names are never regex-checked, and let `kind` take either vocabulary its callers resolve. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: name-check only the agent tools whose summary the agent calls An mcp tool exposes the MCP server's own tool names and a websearch tool's summary is a plain label, so neither reaches the worker's name check. Both default to an empty summary in the editor, which the chat then refused to write back. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com> |
||
|
|
6749015fbf |
fix: audit the icon library against brand guidelines (#10722)
* feat: audit the icon library against brand guidelines
Every icon component checked against its brand's own published guidelines for
correct artwork, current colours, and readability on both app surfaces.
- 127 marks now carry a per-theme pair (text-[#light] dark:text-[#dark]), applied
only where the brand publishes a reversed or dark variant. twMerge where the
component exposes a class prop, so callers can still pass sizing.
- 296 of 304 brand icons record their source in a comment above the <svg>,
including the rule where the brand imposes one (Google forbids recolouring,
Cal.com is deliberately greyscale, Oracle reserves the MySQL dolphin).
- BRAND_COLORS.md is generated from the components, so the table cannot drift
from the code.
- Marks that were unreadable on a surface: 13 -> 1 on dark, 9 -> 4 on light.
The remainder are blocked by trademark terms, not unfixed.
- Wrong artwork replaced where a first-party or CC0 source existed: PayPal is
the real three-colour monogram, Stripe is the bare S rather than an app tile,
gcloud resolves to Google's mark instead of a generic hexagon.
- Concept icons (CACertificate, DbIcon, Webdav, Asset*, Bcrypt) inherit
currentColor instead of hardcoding a colour.
Fixes a cross-component CSS bug: ten icons embedded <style> inside their <svg>.
Svelte only scopes a component's top-level style block, so those were injected as
document-global rules under names like .st0 and .cls-2, which four icons each
defined differently. WindmillIcon renders from the root logged-in layout, putting
.st0 { fill:#ffffff } on every page. Class names are now namespaced per icon.
Adds /kitchen_sink/icons, a gallery rendering every icon on both surfaces at once.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* feat: render brand icons in the surrounding text colour in control strips
A trigger picker mixing lucide glyphs (Webhook, Route, Database) with brand marks
(Kafka, GCP, AWS) read as two sets of controls once the marks became coloured.
Adds an .icon-mono utility that redirects descendant fills to currentColor, applied
by the container rather than passed to the icon. That is what makes it work on every
icon: GoogleCloudIcon has four hardcoded fills, no currentColor and no class prop, so
nothing passed to it could change its colour, and gradient-based marks cannot express
a monochrome variant at all without being redrawn.
- ToggleButton takes a monochromeIcon prop, opt-in since it is used app-wide.
- TriggersBadge, SidebarContent and QuickMenuItem (which backs GlobalSearchModal)
apply it unconditionally: these are uniform lists where one coloured entry among
grey ones reads as an error.
- DropdownV2 gains menuClass, because it portals its menu and a wrapper around the
component cannot style it. CaptureButton passes icon-mono through it.
!important is required because a handful of icons paint through style="fill:…", which
no selector outranks. Stroke is redirected only where one is declared, so shapes
carrying stroke="none" do not sprout outlines. Wrappers use display:contents, so no
layout box is added.
RowIcon is deliberately untouched — table rows keep showing brand colour.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* docs: close out the icon provenance gaps
Sources the 8 icons that had none and settles the 54 records whose author rated
itself below "high" and which no verifier ever reached — the earlier run's
verification stage was killed by a session limit.
46 confirmed as already correct, 11 citations corrected, 3 colours corrected.
Two changes were refuted and reverted by the adversarial pass:
- Mysql: the comment had the colour-to-shape mapping inverted. Rasterising the
first-party asset shows #00758F paints the dolphin and "My" while #F29111 paints
"SQL", not the reverse. The mark renders monochrome here, so nothing on screen
was ever wrong — only the note. Also rescoped the trademark sentence to what the
page literally says.
- AdobeAcrobatSignIcon: a "corrected" citation was rejected on evidence. The agent
claimed the original URL 404s; three fetches returned HTTP 200 with a genuine
Adobe SVG whose stylesheet is .a{fill:#584ccc}. Reverted to the original comment,
which also resolves the one unverified colour change on this branch — #584CCC is
current and first-party confirmed.
AmqpIcon is deliberately left with no brand colour: AMQP is an OASIS protocol, not
a vendor, and amqp.org publishes no palette.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* feat: add icons for 11 resource types that had none
19 hub resource types fell back to a generic Boxes glyph. One agent per brand went
looking for a square vector logomark from a first-party source, with an adversarial
check on everything it produced; 11 landed and 8 correctly came back empty.
Added: beamer, campayn, codat, comapeo_server, klaviyo, matteroom, mollie, motimate,
paychex, terra, vectara. Each records its source, and the components follow the
library's conventions — no <style> block (Svelte does not scope those, which is what
made .st0 leak document-wide), gradient ids prefixed with the component name.
The other 8 keep the fallback, which is the right outcome rather than a failure:
- actimo, adrapid, aero_workflow, matteroom-adjacent niche products publish their mark
only as raster. Upscaled PNGs would look soft beside 300+ vector marks.
- gfw redirects to Global Nature Watch and publishes a wordmark, not a mark.
- leonardoai, localcontexts, weatherapi, webscrapingai serve nothing usable.
No hand-tracing: approximating a mark from a screenshot is invention, not sourcing,
and a wrong logo is worse than the tidy fallback glyph.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* feat: lettermark fallback for reserved marks, and fix the resources table rows
Icons
- Brands that reserve their logo for licensees no longer ship it. BrandLetterIcon draws
the initial in the brand's own colour instead: recognisable, not their mark, and not
invented artwork. Adobe Acrobat Sign and MySQL use it, plus the eight resource types
whose brands publish no vector mark at all.
Adobe: "does not allow the use of its product icons by third parties in their products
or related materials of any kind, except through an Adobe partnership agreement".
On dark the letter inverts to a filled rounded square, because a mid-tone brand colour
chosen to read on white goes dim as a foreground on #2e3441. Where white-on-tile is
also dim, the tile takes a near-black letter instead; light-mode letters are darkened
along their own hue until they clear 3:1. Every pair was measured, not eyeballed.
- Google Docs was drawing a generic monochrome document glyph while carrying a comment
claiming Google's colours. Replaced with Google's own 192px product icon.
- Azure was drawn monochrome, justified by a comment citing Microsoft's rule against
distorting the mark — which drawing it monochrome is. Replaced with Microsoft's own
logo_azure.svg. Their terms say to use the icons "as they would appear within Azure";
permitted use is diagrams, training and documentation, which is recorded in the file.
- Adobe Acrobat Sign's artwork was a geometric "A" plus a squiggle, not Adobe's ribbon
swirl. Moot now that it is a lettermark, but the mark was wrong.
- Gradient, mask and clip ids in the new artwork are namespaced per icon; ids are
document-global and collide the same way the .st0 class names did.
Resources tables
- Description cells are a fixed two lines: min-h floors short ones, line-clamp ceilings
long ones, so every row is the same height. Full text on hover via title.
- Widened to 30rem (84 chars/line) and vertically centred. The clamp needs
display:-webkit-box, which stacks lines from the top, so the span sits in a
flex items-center wrapper rather than carrying the height itself.
- w-full min-w-0 max-w-[30rem] instead of a fixed w-96, so a narrow viewport shrinks the
column and truncates rather than forcing the page to scroll sideways.
- The actions column loses its border-l separator and right-aligns the "Shared globally"
badge, matching the rows that show buttons.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix: icon-mono filled lucide outlines and missed currentColor brand marks
Two bugs in the monochrome utility, both from the fill rule being too blunt.
- Lucide icons are outlines: fill="none" with stroke="currentColor" and no fills on
their children. Forcing fill on every descendant overrode that none and turned each
glyph into a solid blob. The filled case is now scoped to svgs that do not declare
fill="none", and svgs that do only get children redirected if they declare a real
fill of their own — so a brand mark drawn as an outline still works.
- Brand marks that paint with currentColor carry their own text-[#hex] class, so
redirecting fills left them branded: MQTT stayed #660066, NATS #375C93. The svg now
inherits the container's colour, which is what actually makes them monochrome.
Also wires the sidebar's trigger section, which was never covered: those links render
through MenuLink, not the sub-item block that had the class.
Verified in the browser across all five shapes an icon can take — lucide outline,
hardcoded fill, currentColor plus brand class, outline root with filled children, and
inline style="fill:#..". Lucide keeps fill:none and a grey stroke; the rest follow the
container.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* refactor: dedicated monochrome trigger icons instead of a CSS override
Reverts the trigger surfaces to the icons that were there before the brand-colour
audit, as ./icons/triggers/ variants. A trigger picker lists brand marks beside lucide
glyphs (Webhook, Route, Database), so a coloured mark reads as a different kind of
thing rather than a peer.
Ten variants, restored from main where they were already monochrome: Kafka, NATS, MQTT,
AMQP, AWS, Azure, Nextcloud, Google, GitHub. Google Cloud is the exception — main's copy
is a greyscale rendition rather than currentColor, so it is rebuilt from the current
four-colour artwork with the fills dropped.
Separate files rather than the CSS override that was there, because coercion cannot work
in general: forcing fills to currentColor breaks lucide's outline icons, which are
fill="none" with a stroke, and marks that set their own text-[#hex] class ignore a fill
rule entirely. Both bugs were live. The .icon-mono utility, ToggleButton's monochromeIcon
prop and the DropdownV2 menuClass pass-through are gone with it.
index.ts documents which folder to use where: ./triggers/ for trigger surfaces, the
full-colour mark for the resource picker, AppConnect and docs, and keep the two in sync.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix: trigger pages and global search still used the colour brand marks
The ToggleButtonGroup on each trigger page pairs a brand icon with a lucide Code
glyph, so GCP Pub/Sub rendered Google's four-colour mark next to a monochrome one.
Kafka, NATS, MQTT and the rest had the same wiring; they were just less obvious
because their marks are near-monochrome already.
Repoints all seven trigger pages and the global search nav entries at the
./icons/triggers/ variants. RowIcon is left on the full-colour marks: table rows
show brand colour by design.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix: restore the greyscale GCP trigger icon, and show variants in the gallery
The trigger variant had been flattened to currentColor, which collapses Google's cloud
into one flat silhouette and loses the tonal steps that give it shape. The pre-audit
icon was greyscale, not monochrome — #B0B0B0 / #D0D0D0 / #E0E0E0 / #FFFFFF — so it is
restored verbatim from main.
Also globs icons/**/*.svelte in /kitchen_sink/icons so trigger variants render next to
the full-colour marks they shadow, labelled by folder. Comparing the two is the thing
this page was missing.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix: flow trigger dropdown rows use the desaturated marks too
The flow-graph badge menu still rendered the full-colour brand marks next to
lucide glyphs. Route both dropdowns through triggerIconMapMono: the badge
itself keeps the colour mark, only the rows it opens change.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* feat: rank resource-type search results by best match
Searching the description is what makes `gdrive` findable as "google", but it
also means "google" matches a dozen types that only mention the product in
passing. Rank a match on the type's own name above any description match, and
break ties on where the match starts, so `googleai` leads and a description
opening with "Google OAuth token..." beats one mentioning Google halfway
through.
Applied to all three resource-type searches: the Resource Types tab (whose bare
term also only searched the name until now), the add-resource drawer, and the
schema-narrowing picker.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix: trigger pages and global search show the full-colour marks
The desaturated variants belong to the two dense lists that sit beside lucide
glyphs -- the sidebar trigger list and the capture dropdown. Everywhere else a
brand mark stands on its own and should be the real one: the per-kind trigger
pages, the command palette, the capture table and the chat tool cards. Records
the rule in icons/index.ts so the next caller picks the right folder.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix: address review round on the icon and resource-type work
- AppConnectInner went back to listResourceTypeNames for the list: /resources/type/list
is not on the public app domain's route allow-list, so a published app's resource
picker 403'd and, because the throw left connectsManual unset, stayed empty on every
retry. Descriptions now load best-effort behind it.
- Dropped DropdownV2's menuClass: nothing passes it; the flow-graph badge menu styles
melt's Menu, which has its own.
- icons/index.ts named two surfaces for the desaturated variants; there are four, and
the flow-graph badge and the menu it opens differ. Dropped the stale GCloudIcon note.
- GoogleCloudIcon takes width/height again: generic call sites resolve it through
APP_TO_ICON_COMPONENT and pass no size, so gcloud rendered at 16px after the remap.
- The path explainer is one ResourcePathHint component instead of the same copy twice.
- BRAND_COLORS.md recorded Ansible, Datadog, Deno, DeepL and Toggl as fixed; each
publishes a second artwork swapped in by class, so their dark hex and ratio were
wrong. Header no longer claims a generator that isn't in the repo.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix: drop the duplicate gcloud icon and unblock the connect list
GCloudIcon.svelte was rewritten into the same four-colour mark as
GoogleCloudIcon.svelte and nothing pointed at it any more, so it was two files
drawing one logo waiting to drift apart.
The description fetch also sat on the critical path: the "Others" list showed
skeletons until a request for every type's full schema returned -- one that a
published app is guaranteed to get a 403 on. It now runs unawaited, and search
re-ranks when the descriptions land.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix: AwsIcon and GoogleIcon take size again
The audit narrowed both to width/height with a 24px default, but every dynamic
call site passes size — RowIcon, the flow trigger badges, ToggleButton, global
search, the chat tool cards, the native-trigger page — so the SQS and Google
marks rendered at 24px wherever a smaller size was asked for. Both take size
again, keep width/height for the call sites that use those, and accept a class
so RowIcon's grey still applies.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix: row-strip brand marks keep their colour
RowIcon greyed five of its seven brand marks with text-gray-400 while gcp and
azure rendered in colour. Now that AwsIcon accepts a class, the grey took its
wordmark but not its hardcoded #FF9900 smile, so the SQS row came out half
grey, half orange.
The rule this branch settled on is that only the four trigger menus desaturate;
a table is not one of them. Dropping the class from all five makes the strip
agree with the gcp and azure rows beside them, and with the lucide glyphs
staying grey since they carry no brand colour to keep.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
||
|
|
5ce29b3436 |
feat: add public sharing option for job pages (#10573)
* feat: add public sharing option for job pages Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: gate public run sharing and address review findings Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: address review nits on public run sharing Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: key public run view on workspace, job and token Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com> |
||
|
|
4c4387d52a |
feat(flow-editor): show an agent's tool-call status without moving the graph (#10557)
* feat(flow-editor): surface an agent's tool-call status without moving the graph Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: count only an agent's tool calls and key them in one place Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * feat: report an agent's replies alongside its tool calls Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * feat: break the agent summary down by action kind Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: key agent tool nodes by kind and keep the summary clear of the tool row Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * refactor: read agent action status from the run's success array Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * test: pin the tool joins a local run cannot reach Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: place the agent summary beside the step and match MCP paths bare Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: feed a single-step agent test's calls into the graph status Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com> |
||
|
|
b2d38e0391 |
perf: keep run status out of flow graph node and edge data (#10554)
* perf: keep run status out of flow graph node and edge data Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: key the ai tool node memo on the agent's actions Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * docs: state the edge-data and memo-key constraints as invariants Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: restore selection clearing and pin the zoom bar's border colour Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: show an agent's tool calls as they arrive instead of at step end Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * perf: stop editor runs from rebuilding on agent tool calls Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com> |
||
|
|
09c8f3b1f3 |
feat: redesign flow step, loop and branch settings panels (#10026)
* feat: responsive modal step panel for the flow editor in sessions On narrow layouts the flow editor's step-details pane opens as a modal (double-click a graph node) instead of a split pane, with a dock/float toggle. Scoped to sessions via allowModalPanel; the full-page editor is unchanged. - FlowEditor: modal/docked modes gated by mount width + allowModalPanel, small header (step-id Badge + subtle dock/close), standing double-click hint, and a per-step hint in the name tooltip - selectionManager: onSelectIntent hook so flow-level panels (settings, input, triggers…) open the modal on single click - PropPickerWrapper: collapse the prop picker until connect and animate it in via AnimatedPane (runs-page pattern), no blue connect ring in modal mode - StepInputGen: drop the TAB/Wand autocompletion button + spinner (feature still works via focus + Tab) - InputTransformForm: decouple the Help dropdown from the AI suggestion - FlowModuleHeader: move 'Save to workspace' into an ellipsis dropdown Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix: loop editor rendering and nested splitpanes splitters in the sessions modal - Loop iterator/parallelism: keep the picker split pane (forceExpanded) so the editor fills its box and the picker shows; the collapse-until-connect mode stays for the step inputs - Remove the intrusive AI TAB/Wand autocompletion button from IteratorGen (generation still runs headless via focus + Tab) - Size the iterator connect plug and restyle the loop header/labels/toggles - Scope the global `.splitter-hidden` splitter-hiding rule to direct children so it no longer leaks into nested Splitpanes under the sessions preview Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * feat: redesign flow step advanced settings as a single toggle-first column Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * feat: taller step test pane by default and restyle advanced section titles Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * feat: show flow run-settings params disabled when a setting is toggled off Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * feat: single-column for-loop panel reusing the run-settings accordion Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * feat: single-column while-loop panel reusing the run-settings accordion Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * feat: single-column branch panels reusing the run-settings accordion Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix: auto-open modal panel when creating an AI agent tool Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * feat: redesign branch panels with card layout and shared predicate editor Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * refactor: remove per-setting status badges from flow map nodes Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * chore: sync package-lock after windmill-utils-internal bump Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * style: polish prop-picker plug button and branch panel layouts * fix: persist skip-if-stopped toggles in early stop settings * fix: open the step panel modal on demand and cap its width * fix: restore graph step setting badges, strip panel header chips instead * feat: docked panel header with detach action and open-details step menu * feat: width-based panel mode on every surface with inline detach action * refactor: single source for flow step settings and their defaults * docs: pin flow editor vocabulary in CONTEXT.md * fix: open the trigger panel on double click or a specific trigger * fix: keep module pickers inside their pane and dismissable * fix: drop the misleading chevron on the MCP tool entry * fix: resolve flow approvals against the job's workspace, not the nav one * refactor: derive the approval workspace from the job, not from callers * fix: restore S3 snippets and gate params while their setting is off * fix: restore branch mock controls and address review findings * chore: drop stray debug log from the flow map item * feat: pinned output section for loop and branch panels * fix: open the panel for deliberate navigation from the flow header * perf: mount branch predicate editors on demand * fix: skip predicate picker previews the previous step's result * fix: flow-level graph nodes open their panel on a single click * fix: open the step panel for AI chat selections, not for undo * chore: drop dead console.log and duplicated modalPanel doc * fix: re-sync expression editors and scope error-handler settings * fix: match the failure module exactly and ignore unselectable nodes * fix: keep concurrency editable, honour module cache_ttl, tighten panel ids * fix: open panel from indirect selections, use presence for value-driven toggles * fix: don't open settings on error-handler delete, flush editors on unmount * fix: guard editor destroy flush, keep retry kind reachable * refactor: name the run settings panel after the domain vocabulary * fix: only write editor flushes to the step they belong to * fix: bind step panels by id so a delete can't retarget editor writes * fix: don't let the trigger picker's escape close the drawer beneath it * docs: condense two comments to the constraint they record * fix: arbitrate escape through the overlay stack instead of deferring to it * fix: key nested step blocks by identity so anchored bindings can't go stale * fix: untrack the overlay-stack push and drop the frozen branch binding * chore: state the escape rationale once, key branch lists, format * fix: let the topmost overlay own escape instead of the graph * fix: keep the dynamic-input help box out of static template fields * fix: restore the graph connect on the for-loop iterator * fix: end connect mode with the modal and keep it to docked panels * fix: never enter graph connect mode from the modal panel * fix: reveal inserted steps, restore editor pane size, unleak the drawer stack * fix: keep the enable-AI popover reachable in session panes * feat: add the connect policy and its single armed slot * refactor: one picker for every expression input * refactor: route every connect through one armed slot * fix: give every connect button the same footprint * fix: keep the connect ring from showing through the button * fix: keep flow card actions right-aligned beside the detach button * fix: give the connect ring an opaque ground to mask against * feat: dock the panel back without reopening it * feat: dock the panel from the graph control bar * style: round the graph control bar and size its glyphs * style: customize the graph controls through their supported api * style: build the graph control bar from lucide icons * fix: use the graph's tooltip component in the zoom controls * style: pad the graph controls and enlarge their glyphs * style: pad the graph controls and put dock at the bar's end * refactor: give settings rows the same popover picker as other expressions * fix: pass the wrapper's pickable properties to nested inputs * refactor: stack step settings and render every expression through the step input form * feat: split loop panels into tabs and rework the approval form * feat: anchor drawers to their host pane and give them a size floor * fix: mark the loop iterator expression as required * refactor: badge ee-only toggles instead of a warning line * fix: flag an empty loop iterator expression as an error * refactor: pick the early-stop flow status from one toggle group * fix: keep parallel loops uncapped unless a limit is opted into * fix: scope the overlay stack to its host and disarm connect on dismissal * fix: anchor the trigger picker to its host pane * feat: move diff into the menu when the top bar is narrow * fix: gate the result logs toggle to the graph popover * feat: raise the modal-panel breakpoint to 1280 * fix: anchor flow editor popovers and fullscreen to their host pane * fix: anchor overlays to their host pane and mute them when hidden * fix: portal hosted modals and menus into the pane they anchor to * fix: keep non-listening dialogs off the overlay stack * fix: drop the topmost gate from confirmation dialogs * fix: silence overlays in a collapsed preview panel * feat: rework the branch panels with tabs, reordering and add/delete * refactor: fold the detached-panel chrome into the card header * fix: give every flow panel a titled card header * fix: stop the step panel oscillating on an auto-height editor * feat: consolidate script panel actions and restore branch predicate AI * fix: restore the logs toggle on the flow result popover * fix: collapse the idle property picker in modal step panels * fix: stop the docked pane scrolling alongside its panel * fix: space the last settings row off the panel bottom * revert: always show the property picker pane in step panels * chore: keep the inline script AI button identical to main * fix: ask for AI input suggestions on click, not on hover * fix: keep graph connects armed and remount the parallelism input * style: reveal the predicate AI button on row hover * style: give branch cards a handle and delete column * refactor: arbitrate flow overlay escape through Disposable * fix: give the popover picker its results and re-narrow the EE badge * docs: correct loopSubset and guard the modal width measurement * fix: insert picked properties at the cursor in expression inputs * fix: give the expanded-subflow panel the shared header chrome * style: rename the suspend setting to Suspend until approval/resume * feat: open a step's modal when clicking the step already selected * feat: add an auto/attached/detached toggle for the step panel * refactor: pick the step panel's placement from one named menu * refactor: keep the panel-mode module's exports to what is consumed * feat: show each configured setting's value on its badge * fix: carry the suspend rename into the step settings registry * docs: name both gestures in the step explore hint * test: pin where the step panel goes for a given width and preference --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
0d1cb818ee |
feat: preview and edit steps inside expanded subflows (#10520)
* feat: preview and edit expanded subflow steps in the flow editor * fix: hide subflow edit button when no flow editor drawer is available * fix: address review findings on expanded subflow step panel * fix: base-prefix subflow links and bound the expanded subflow module cache * fix: do not let a pre-deploy response repopulate the invalidated subflow cache * fix: guard expanded subflow reloads against collapse and encode workspace in link * fix: commit an expanded subflow reload only onto the expansion it fetched for |
||
|
|
b718ea8495 |
fix: anchor overlays to their preview tab instead of the viewport (#10477)
* fix: anchor overlays to their host pane and mute them when hidden * fix: portal hosted modals and menus into the pane they anchor to * fix: keep non-listening dialogs off the overlay stack * fix: drop the topmost gate from confirmation dialogs * fix: silence overlays in a collapsed preview panel * fix: keep overlays live in a full-screen preview of a collapsed session |
||
|
|
39dd411481 | fix(frontend): add the preprocessor node before the error handler markers (#10395) | ||
|
|
7ac2909b30 |
fix: don't crash the flow editor when a step with an error handler marker is deleted (#10393)
* fix(frontend): don't anchor an error handler marker to a deleted step * test(frontend): pin that topologicalSort tolerates a missing parent node |
||
|
|
bff654596f |
fix: render the flow editor's error handler node as an inert run marker (#10391)
* fix(frontend): render the error handler as an inert run marker in the flow editor graph * fix(frontend): dismiss nested error handler markers via a dedicated handler * docs(frontend): note that error handler markers are keyed by failing step |
||
|
|
3b95a2d096 |
feat: reusable AI agent steps with rigid linking and edit/fork (#9825)
* feat: reusable AI agent steps with hybrid linking and evals Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * feat: make linked AI agents rigid (read-only) with unlink-to-fork Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * feat: show inherited agent config read-only on linked step Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * feat: edit/update a saved agent in place via upsert Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * feat: bind linked AI agent tool inputs to host flow context Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * feat: rebind linked AI agent tool inputs via graph tool nodes Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix: linked AI agent tool nodes, step test, and read-only card Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * chore: remove ai_agent resource type migration, sync from hub instead Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * chore: remove AI agent eval suite and run endpoint, defer to later Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * chore: unwire eval routes, types and UI (completes eval removal) Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * docs: update reusable AI agents guide for eval removal and tool rebinding Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * chore: regenerate system prompts for AIAgent agent/tool_inputs schema Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix: strip brain transforms on link, avoid dirtying flow on tool open Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix: flow-local test form and linked-agent marker in read-only graph Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix: store linked tool overrides as diff from resource base Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * feat: resolve linked agent tools in read-only viewer with fallback Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix: use operating workspace, block non-static provider, warn on unbound tool inputs Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix: resolve linked parent's tools from resource for nested agent tool lookup Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix: scope linked-agent tools by flow path, thread workspace to path check and embedded viewer Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix: strip flow-context tool inputs on agent save, drop unbound-inputs warning Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix: persist agent edit mode across tool selection, show linked tool code read-only Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * feat: show linked agent resource path in node definition panel Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * refactor: edit linked tool inputs in step panel, make tool nodes display-only Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * refactor: wire step-panel tool bindings (completes display-only pivot) Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix: single scroll for linked card, agent path as node label, drop fill-inputs in tool cards Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * style: align linked-agent UI with design tokens and components Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix: separate linked tool select target from module id to unbreak agent clicks Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@aanthropic.com> * fix: save agent tool inputs verbatim, host flows override via tool_inputs Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix: scope agent edit state by flow path, require linked-tools scope at init Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix: block saving an agent whose static provider is incomplete Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix: type errors in agent tool bindings and save drawer input Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix: key agent edit state by workspace, resync tool bindings on external changes Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix: include workspace in linked-tools scope and tool schema fingerprint Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix: remove unused workspace prop from FlowModuleSchemaMap Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * refactor: drop linked-agent placeholder tool node, path label suffices Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix: workspace-qualified resource links, guard stale tool schema loads Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix: keep flow tool overrides out of the agent on edit, fold only on unlink Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix: fold preserved tool overrides into the step on edit cancel Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix: refuse overwriting non-agent resources on save, show memory kind on linked card Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix: consume picker value, invalidate edit state on undo/reinit, cap nested agent tools Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix: guard in-flight edit fork against restores, migrate edit state on rename Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * refactor: validate agent edit state by fork identity instead of path keys Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix: key agent edit entries by fork marker alone, immune to editor nesting Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix: keep agent edit state across structural graph edits and flow renames Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01B6kq9PYqNdc5q7ubidBYAs * fix: centralize agent edit reanchor, guard in-flight saves, seed rename scope from flow path Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01B6kq9PYqNdc5q7ubidBYAs * fix: ancestry-keyed edit reanchor and doc-scope sweep for republished linked tools Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01B6kq9PYqNdc5q7ubidBYAs * fix: guard stale linked-tool fetches and resolve while-loop nested linked agents Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01B6kq9PYqNdc5q7ubidBYAs * fix: drop empty tool override entries on revert and correct stale viewer comment Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01B6kq9PYqNdc5q7ubidBYAs * docs: drop stale eval mention from the linked-agent comment Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: deploy linked agent resource, guard viewer fetches, align tools schema Address review findings on the reusable-agent branch: - Cross-workspace deploy never collected a linked step's `agent` resource, so the deployed flow failed at runtime unless the agent already existed there. - The read-only viewer published resolved tools without the generation guard flowState uses, letting a superseded link's tools win a race. Share one guarded publisher (`publishLinkedAgentTools`) between both call sites. - `tools` was still required in the OpenFlow AiAgent schema while the deserializer defaults it, rejecting hand-authored linked steps; make it optional and narrow the call sites. - Overlay `tool_inputs` in the non-linked branch too, so a flow persisted while a step sits in "Editing" mode still binds tools to this flow. - Cap the linked-tools store's scope map; nothing evicted it before. - Drop the orphaned `.sqlx` entry left by the eval removal, regenerate the copilot OpenFlow schema, and fix the generator's nested-`z.record` arity. - Move `refreshFlowStateStore` out of `agentEditStore` into its own module. - Document that linked agents' tool scripts are outside the lock pipeline. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * chore: regenerate system prompts for optional AIAgent tools Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: follow saved-agent deps on deploy, accept the linked shape in the schema Round-18 review findings: - Deploying a linked flow queued only the outer ai_agent resource. Follow `$res:` refs inside a resource value (every UI-saved agent has a provider resource) and the agent's own tools, which reference scripts, flows, MCP resources and nested linked agents by bare path. - The AiAgent input_transforms schema still required provider/output_type, so it rejected the very shape linking persists (brain transforms stripped, flow-local inputs kept). Only user_message is always present. - dfs traversed `value.tools` unconditionally through a cast, which throws on a linked module that omits it now that the field is optional. - Trim the flow-refresh invariant comment to the 4-line limit. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: recurse into inline nested agent tools on deploy, require provider when unlinked Round-19 review findings: - The deploy walk only inspected a saved agent's top-level tools, so an inline nested agent tool's own scripts, flows and MCP resources were skipped. Recurse into it; a linked one is still queued as a resource instead. - Normalize a `$res:`-prefixed MCP tool resource_path like other refs. - Dropping provider/output_type from the schema's required list also let a standalone providerless agent validate, which deploys clean and then fails on every run. The constraint can't go in the schema: an `anyOf` makes AiAgent a union, which breaks the FlowModuleValue discriminated union it belongs to (verified: zod throws "Invalid discriminated union option"). Enforce it in validateFlowModules instead, next to the other cross-module checks, via a shared collectProviderlessAgentIds. - Correct the deploy paragraph in the docs: provider resources are traversed now. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: follow linked tool_inputs overrides on deploy, untrack vitest artifact Round-20 review findings: - A linked step's `tool_inputs` override replaces the resource tool's default at runtime, so a static `$res:`/`$var:` override is the dependency the flow actually uses. The deploy walk queued only the saved agent, leaving runs in an empty target workspace to fail on the missing override target. It also never scanned an aiagent module's own input_transforms, since the scan was gated to script/rawscript/flow. - Extract the pure walkers to deployDependencies.ts and cover them: three rounds have each found a further gap in this one function. - Untrack a vitest cache artifact committed by accident, and ignore a repo-root node_modules/ (only per-package paths were listed). Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: collect inline agent provider and tool deps, correct tool_inputs docs Round-21 review findings: - An inline agent's provider credential sits inside an object-valued static transform, so the top-level string check missed it and such a flow deployed without its provider. Walk transform values instead of string-matching them. - An inline agent's own tools were only partly reachable: getAllModules drops MCP and websearch tools, so their resources were never queued. A standalone agent module now recurses through agentResourceDependencies, and the module's own input_transforms are scanned inside aiAgentModuleDependencies so one function owns the whole step rather than splitting it with the caller. - `tool_inputs` was documented as empty/absent for non-linked steps, which contradicts the runtime applying it when `agent` is unset so a flow persisted mid-Edit keeps its bindings. Describe that case in both the Rust doc and the OpenFlow description. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: keep linked steps brain-free on load, gate stale agent fetches, log linked tools Round-22 review findings: - loadSchemaFromModule filled every AI agent schema key with a placeholder transform, re-adding provider/memory to a linked step that deliberately carries none — persisted on the next save and rejected by the generated Copilot schema. Fill only the flow-local keys when the step is linked. - The linked-resource fetch was neither aborted nor tagged, so switching a step from agent A to B could publish A's tools under B and show A's brain next to B's link. Tag each result with the (workspace, path) it was fetched for and drop the ones that no longer match. - "Test this step" passed no tools for a linked agent, and the log viewer drops tool_call entries it cannot resolve to a definition, so the agent's invocations vanished from the log. Pass the resolved resource tools. - Correct the cancel-edit comment: the runtime does apply tool_inputs on an unlinked step, and folding is what leaves nothing for it to overlay. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: pin the edit session across saves, resolve linked tools in the run viewer Round-23 review findings: - Cancel stays enabled while a save awaits its requests, and it keeps the `tools` array identity, so the old guard passed and the completing save relinked the step and cleared the edits Cancel had just kept. It also accepted any replacement edit marker. Pin the path being saved and require the marker to still hold it, which still tolerates a content-preserving refresh re-anchoring the marker onto a clone. - Resolve linked agents' tools in the run/status viewer too: it reads module.value.tools straight from raw_flow, which is empty for a linked step, so AIAgentLogViewer dropped every tool_call it could not match and the graph drew the agent with no tool nodes. Same gap the previous commit closed for "Test this step" only. - Drop the overlay call-site comment: it claimed resource defaults are discarded and unmatched keys ignored, while overlay_tool_inputs preserves defaults and inserts new keys, as its own test asserts. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: scope linked tools without the trigger-node path, keep the standalone save guard Round-24 review findings, both regressions from the previous commit: - Passing `path` to the run viewer's graph also switched on its Trigger node (`triggerNode ? path : undefined`), which reads a TriggerContext that /run/[...run] does not provide — the page threw "Cannot read properties of undefined (reading 'triggersCount')". Give the graph a separate `linkedToolsPath` for the tools bucket so the two stay independent. - The rewritten save guard tracked only the edit path, so a plain "Save as agent" no longer noticed the step being replaced mid-request (undo, session sync): the replacement has no edit path either, so the stale completion relinked it and stripped its brain. Keep the array-identity check when there is no edit session, and use path re-anchoring only when there is one. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: keep recorded tool calls in run history, send tool_inputs from step previews Round-25 review findings: - The agent log viewer dropped any recorded tool_call whose definition it could not find among the supplied tools, so renaming or removing a tool — or losing read access to a linked agent's resource — erased calls that had actually run. Render the recorded call labelled by its function name; its args, logs and result come from the child job, not the definition. - "Test this step" sent tool_inputs only for a linked step, but a step forked for editing has no `agent` while still carrying the flow's bindings, which the runtime overlays. The preview ran resource-authored defaults instead of the bindings under test. Send them from both branches. - Polling a running flow replaces `job` every tick, so the run viewer re-read every linked agent's resource each time. Key the fetch on the set of linked steps instead. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: never discard edits made during a save, isolate the run viewer tools bucket Round-26 review findings: - The agent editor stays live while a save is in flight, so edits made after the snapshot were not in the resource yet linking stripped them from the step too, losing them outright. Compare the config against the snapshot on completion and, if it moved, leave the step alone and tell the user to save again. - The run viewer published into the editor's `${ws}:${flow path}` bucket, so opening an older run in the preview pane could flip the edited flow's tool nodes to that run's agent. Key it by job instead. - Drop the now-unreachable undefined filter in the agent log viewer. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: claim the linked-tools generation on direct publishes and clears Round-27 review findings: - The step editor wrote resolved tools (and cleared them on unlink) straight into the store, leaving the fetch generation untouched. An older in-flight load for the previous agent then still passed its own check and overwrote them, so the graph and binding editor could show agent A while the step links to B. Claim the generation before those writes. - Correct two comments that still described unmatched tool calls as dropped; they are kept and labelled by their recorded name. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: retain the loaded linked agent, rebuild run logs when tools resolve Round-28 review findings: - Rejecting a superseded resource response left the card with nothing: a late reply for a previous agent replaces `linkedResource.current` and no refetch follows, so the linked step lost its brain, tools and provider warning until remount. Retain the last response that matched the current link instead. - The agent log viewer built its module list on mount only, so a linked agent's asynchronously resolved tools never replaced the placeholders, and switching between completed runs reused the first snapshot. Rebuild on a value key — callers rebuild the agentJob object each render, so tracking its identity would reload in a loop. - Refresh a linked-tools scope's recency when it is read, not only when it is published: a run viewer opens one bucket per nested job, which could otherwise evict the bucket a still-displayed run is using. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: supersede stale log reloads and stale tools on a link change Round-29 review findings, both on the reloads added last round: - Every prop change starts another loadToolCalls, and it awaits child-job requests before writing the shared view, so a slower reload for a previous run could restore its logs and tool states over the run now selected — or replace newly resolved definitions with an earlier empty-tools snapshot. Build the states locally and let only the newest load publish, including the parent's index-keyed job cache. - While a newly linked agent resolves, the previous agent's tools stayed in the store, so its bindings were editable against a step already linked elsewhere, and a failed load left them indefinitely. Clear them once the link moves away from what this component published; tools resolved at flow load are untouched, so selecting a step still doesn't flicker. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: resolve a run's linked agents in the run's own workspace Round-30 review finding: the run viewer fetched linked agent resources with the navigation workspace, but session and fork previews render it with `workspaceId` pointing elsewhere. Those runs resolved nothing — or an unrelated resource sharing the path — losing tool nodes and log definitions. Prefer the explicit override, then the job's own workspace. The store scope stays keyed on `workspace` so it still matches what FlowGraphV2 reads; the job id in the key already makes the bucket unique. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: refetch a run viewer's linked tools if its scope is evicted Round-31 review nit: the viewer publishes one scope per mounted nested job, hidden ones included, so a loop with many loaded iterations can push a displayed scope past the store's cap. Nothing refetched it afterwards — the set of linked steps had not changed — leaving the run without tool nodes or log definitions. Track the store and republish when the bucket is gone; publishing always writes a key, so this settles instead of looping. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: retain in-use linked-tool scopes instead of refetching evicted ones Round-32 review findings. Republishing an evicted scope settles for one scope but not against the cap: with more than 32 mounted nested jobs holding linked agents, restoring one necessarily evicts another, and that mutation reran every viewer's effect — an endless round of resource requests. Hold a scope for as long as a viewer is mounted and skip retained scopes when evicting, so buckets in use are never dropped and nothing has to refetch. The cap yields to correctness when everything mounted is in use. Dropping the publish key also restores refetching when the fetch workspace changes for an otherwise unchanged job and link. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: guard non-static brain edits during save, retain every displayed scope Round-33 review findings: - The in-flight edit guard compared the saved config, which holds only static brain values. A computed system prompt, memory or temperature changed while the save was awaiting the API therefore compared equal, and linking stripped it with no warning. Compare what linking actually discards — every brain transform and the tools — leaving the flow-local inputs free to change. - Retaining run-viewer scopes made them fill the cap, and eviction then picked any unretained scope, including the editor bucket a user is looking at, with nothing to refetch it. Retain the scope each graph draws from for as long as it is mounted, so every displayed bucket is protected. - A failed agent job has no parseable action list; the loader returned early and left the previously selected step's tool tree under the new header. Clear the view instead. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: resolve only flow modules in viewer scans, prune scopes on release Round-34 review findings: - Both viewer scans used the default dfs, which descends into agent tools, and published each linked agent under its bare id. Tool ids imported from a resource are not flow-global, so a nested linked agent sharing an id with a top-level step superseded that step's fetch and showed its tools instead. Scan flow modules only — the graph resolves the store per module node. - Scopes skipped while retained were never reconsidered, so closing views left the store over its cap for the tab's life. Prune on release too. - Correct two comments that still argued the premises the retain mechanism and the read-recency policy replaced. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: don't report success when a save left the step unlinked Round-35 review nits: - persist warns that changes made during the save are not in the resource and leaves the step alone, but both callers then toasted success unconditionally, burying the only actionable message. Report whether the step was linked. - Condense the tool_inputs invariant to the four-line limit. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: seed the published link at mount, keep run history for toolless agents Round-36 review findings: - `publishedFor` started unset, but initFlowState has already published for the step's link by then. A link change landing before this component's own request therefore skipped the clear, leaving the previous agent's tools under the new link — indefinitely if the new one fails. Seed it from the link at mount. - A standalone agent that omits `tools` kept `undefined` here, and the gate downstream then hid the AI message and tool-call history behind the generic result view. Default to an empty list like the other consumers. - A save that lands after the step was replaced writes the resource but leaves the step alone; say so instead of closing the drawer with no outcome. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: qualify nested agent tool store keys, keep an empty tools identity stable Round-37 review findings: - The step editor keyed the linked-tools store by the bare module id for nested agent tools too. Those ids come from a resource and are not flow-global, so a nested linked agent sharing an id with a top-level step read that step's tools — then overwrote them once its own fetch landed. Qualify the key by the parent agent, as the edit store already does; flow modules keep the bare id the graph looks up. - The `tools` binding handed the editor a fresh [] on every read when the module omits the field — a shape this PR made valid — so the save guard's identity check never matched and such a step could never link. Read through one shared empty array instead. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: accept the first tool on an agent module that omits tools Round-38 review nit: the graph's tool insert required an existing `tools` array, so a module authored without the field — valid since `tools` became optional — swallowed the insert while still pushing history and dispatching a change. Create the array on first use. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: don't evict a scope on the write that created it, and cover the store Round-39 review findings: - A rename removed the retained old key from the order but the new one is not retained until readers re-run, so eviction deleted the fresh bucket immediately. Reorder without evicting; the next publish or release enforces the cap, by which point the new key is held. - Writing the test for that surfaced the same shape in touchScope: it evicts right after appending, so once every older scope is retained the scope just published was the only eligible victim and was dropped at once. Exclude the scope being written. Add the store's first test: retention, eviction past the cap, pruning on release, and the rename handoff — four rounds landed fixes here with nothing pinning the behaviour. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: re-resolve linked agents when a wholesale edit changes the links Round-40 review findings: - Undo/redo, YAML apply, AI apply and session restore swap a step's `agent` without re-running initFlowState, and the step editor only watches the step it is mounted on — so an unselected step kept showing, and binding against, the previous agent's tools. Re-resolve from the editor whenever the set of links changes. - Document that linked resolution is live rather than pinned: an edit landing mid-run affects steps that have not started, and a nested agent tool looks its definition up by id when its own job starts, so it can run a changed definition. Pinning would mean carrying the resolved definition into the child job instead of its id; inline agents are unaffected because their tools are snapshotted with the flow value. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: per-module empty tools identity, invalidate tools when a link is replaced Both findings are over-corrections in the two preceding commits: - The shared empty-tools array made identity stable, but stable everywhere: a wholesale edit that keeps the module id reuses the component, so when both the old and the replacement module omit tools the save guard saw no change and could link and clear the replacement. Hand out one empty array per module value, which a replacement always renews. - The editor's link watcher resolved the replacement agent without dropping the previous one's tools first, so a step selected before the fetch landed still showed agent A under link B — and the freshly mounted editor seeds itself from B, so it could not tell. Clear the entry when the link for a module changes, seeding the map from the graph so the first run doesn't refetch what initFlowState just resolved. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: reserve graph space for linked tools, re-resolve only changed links Round-41 review nits: - The layout reservation read the module's own `tools`, which is empty for a linked agent, so its display-only tool nodes were drawn over the node above in read-only viewers. Count the resolved tools for a linked step. - The editor's link watcher refetched every linked agent on each run. Resolve only modules whose link actually changed, and skip the pass entirely on a rename, where the scope sweep has already carried the buckets over. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: protect a renamed scope until it is retained, drop the phantom tool row Round-42 review nits: - Readers release the old scope before retaining the new one, so a migrated bucket is unretained in between and, over the cap with everything else held, was the only thing eviction could take. Protect a just-migrated scope until a reader retains it, and cover that release/retain order in the store test. - The layout reserved an add-tool row for linked agents, which have no add-tool node, leaving dead vertical space. Match computeAIToolNodes. - Re-resolving links no longer short-circuits on a rename: comparing each module still costs nothing when only the path changed, and a restore that renames and relinks in one tick now gets both. - Hoist the duplicated linked-tools lookup in the graph's store update. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: kill a scope's in-flight fetches before migrating it Round-43 review finding: fetch generations are keyed by (scope, module), so a resolution still running against the pre-rename scope keeps a valid generation there. It publishes into the old bucket after the rename, and the doc-scope sweep — which gives the source precedence — carries it forward over a link resolved since under the new scope, leaving the graph and binding editor on the previous agent's tool ids with nothing to refetch them. Invalidate the source scope's fetches before each migration, and pin the behaviour: the new test fails without the invalidation. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: re-resolve links a scope sweep cancelled, and only sweep a real bucket Round-44 review findings, both on the previous commit: - Invalidating the source scope killed fetches that were perfectly current — a link still loading when the rename landed — and nothing restarted them, because the watcher already records that link. Resolve again, in the destination, every link the migration left without tools. - The doc-scope sweep ran on every store version bump, so during a draft refresh the first completed fetch cancelled the others mid-flight. Skip the sweep entirely when the source scope holds nothing. - Condense a six-line invariant to the four-line limit. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: split rename from doc sweep, hide brain fields of nested linked agents Round-45 review findings: - Two reviewers disagreed about invalidating a scope whose bucket is empty, because the two callers differ. A rename is a cut-off: every fetch still running against the old scope is stale whether or not anything resolved there, so it always invalidates. The doc-scope sweep has no cut-off — those fetches belong to the refresh in progress — so it still waits until that scope holds something. - Recording the swept links as published undid the rename+relink fix: a restore that renames and swaps a link in one tick would keep the previous agent's tools with nothing to refetch them. Leave that comparison to the watcher, which compares links rather than presence. - A nested agent that is itself linked was offered the whole agent schema in the tool bindings, but the runtime overlays only its flow-local inputs, so the rest were collected and dropped. Show what actually applies. - Condense the hybrid-linking comment to the constraint. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: don't resolve a shared agent's tool defaults when loading it Round-46 review finding: the whole agent resource was interpolated before tool_inputs was overlaid, so each tool's default `$res:`/`$var:` resolved first. A host flow overriding a default that points at the author's resource still had to resolve that resource, and an unused tool whose default is unreadable in the consumer's permission context failed the agent outright — defeating the point of sharing an agent across contexts. Read the resource raw, overlay the host's overrides, and interpolate only the brain; each tool resolves its effective inputs when it executes. The nested tool lookup reads raw too, since it only needs definitions. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: interpolate the brain before overlaying caller inputs Round-47 review findings, all on the previous commit: - user_message and user_attachments were inserted before interpolation, so they went through it a second time: a user message of `$WM_TOKEN` expanded to the job token and was sent to the model provider. Interpolate the resource first, then overlay the already-resolved flow-local inputs. - The relink watcher skips tool nodes, so a linked agent nested as a tool kept the previous agent's entry through undo, YAML/AI apply or a session restore, and the step editor seeds itself from the new link and cannot tell. Emit the ancestry-qualified key for those too. - Correct the guide, which still named the interpolation path this branch replaced, and condense two invariants to the four-line limit. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: deploy $jsonvar deps, key run logs by tool identity, seed only top links Round-48 review findings: - The deploy walkers recognised `$res:` and `$var:` but not `$jsonvar:`, which the worker resolves too, so a secret referenced that way by an agent brain, a saved tool default or a host override never reached the target workspace. - The run log rebuilt only when a tool's name or the tool count changed, so a refreshed resource that altered a tool's path, code or id behind the same name kept showing the old definition. Key on the array identity instead: the store swaps it exactly when the contents differ. - Nested linked agents were seeded as already published, but initFlowState resolves only top-level links, so their tools never loaded until their editor was opened. Seed what initFlowState actually publishes. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: let the watcher's fetch survive the step editor's stale-clear Round-49 review nits: - On a relink the step editor claimed the fetch generation before clearing the previous agent's tools, which discarded the watcher's already-running fetch for the new link. The tool nodes then only appeared if the step stayed selected until the editor's own refetch landed. Clear without claiming: the watcher superseded the old fetch when the link changed, so nothing stale can return. Unlink still claims, since no watcher fetch covers it. - Condense the store's opening invariant to the four-line limit. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * docs: condense the stale-clear invariant Round-50 review nit. Also records why the branch deliberately doesn't claim a fetch generation: a reviewer asked for the opposite this round, but writing `agent` re-runs the editor's watcher, which supersedes the old fetch and starts one for the new link — claiming here would discard it. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: guard Edit/Unlink by step identity, not just the link path Round-51 review finding: forkFromResource compared only the agent path after its fetch, so a module replaced mid-request while keeping the same link passed the check — the stale continuation then wrote the fetched brain and tools into the replacement and unlinked it. Compare the step's own `tools` array too, which is one instance per module value and so identifies the step. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: report an Edit or Unlink abandoned because the step changed Round-52 non-blocking note: forkFromResource returns undefined when the step was replaced mid-request, and both callers treated that as do-nothing, so the click looked ignored. Say what happened, as the save path already does. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Co-authored-by: hugocasa <hugo@casademont.ch> Co-authored-by: Claude Opus 4.8 (1M context) <noreply@aanthropic.com> |
||
|
|
68debab877 |
feat(triggers): add AMQP (RabbitMQ) trigger via lapin (#10230)
* feat(triggers): add AMQP (RabbitMQ) trigger using the lapin library Fixes WIN-2214 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * chore(triggers): defer AMQP cross-workspace deploy pending utils-internal publish Revert the amqp_trigger additions to the shared windmill-utils-internal TriggerDeployKind and the frontend cross-workspace deploy adapter: the frontend installs the published npm package, which lacks the new kind until a release is cut. AMQP create/edit/delete/list/sync/capture are unaffected (they use local types); only cross-workspace deploy/merge of AMQP triggers waits on the package bump. Also document the at-most-once ack in the consumer loop. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(triggers): address AMQP review — at-least-once ack, workspace cascade, contracts - ack AMQP deliveries only after successful dispatch; nack+requeue on failure - add ON DELETE CASCADE workspace FK so amqp_trigger rows are cleaned on workspace deletion (and the listener stops) - fix the /amqp_triggers/test OpenAPI body and add amqp_trigger to WorkspaceDiffRow.kind - register AMQP in the generated workspace trigger tool (create_trigger) - drop banned $bindable defaults on optional props in the config section - add build_uri unit tests (encoding, ports, vhost) Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(triggers): stop AMQP poison-message loop and reconnect on transient drops Chaos testing against a live RabbitMQ broker showed the previous nack(requeue) + immediate re-poll spun a tight redelivery loop (~1000 critical-error reports/sec) on a poison message, and any connection blip permanently disabled the trigger (lapin has no built-in reconnect). - on dispatch failure: nack+requeue then stop consuming; the listener framework re-lists the trigger after its ping goes stale (~15s), backing redelivery off to that cadence instead of a tight loop (verified: rate dropped from ~1000/s to ~1 per ~26s, message preserved) - on connection/stream error: stop and let the framework reconnect instead of disabling; persistent failures are still disabled via get_consumer (verified: a forced connection close now auto-reconnects and resumes) - finish the AI create-trigger action wiring for AMQP: add amqp to CreatedResourceTriggerKind, the action-card registry, and the drawer registry so the result card renders and its "Open" action works Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(triggers): complete AMQP frontend registries and defer merge rows - add amqp to capturableTriggerTypes (so AmqpCapture mounts), the Runs jobTriggerKinds filter, and CLOUD_DISABLED_TRIGGER_TYPES - wire AMQP into global AI chat mode: TRIGGER_KINDS, the request union, writeTriggerSchema, triggerServices, and the draft adapter - stop emitting actionable AMQP fork-comparison rows (revert amqp_trigger from TRIGGER_OR_SCHEDULE_TABLES) since cross-workspace deploy is deferred until windmill-utils-internal is published — avoids a deploy that fails with "Unknown kind: amqp_trigger" - use design-system TextInput instead of raw <input> in the config section Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(triggers): complete AMQP session/draft registries and constrain prefetch - add amqp to the session-deploy, draft-compare, preview-router, and copilot workspace-item registries so AMQP drafts/deploys/nav/path resolution work - include amqp_count in the MoveDrawer attached-trigger rename warning - replace the raw prefetch <input> with a design-system TextInput bounded to an integer 1-65535 (backend u16) and block save on invalid values Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(triggers): make AMQP disconnect/reconnect consistent with the Kafka trigger lapin, like rdkafka, has no transparent reconnect, so the AMQP listener now mirrors the Kafka trigger's explicit reconnect loop instead of relying on the framework re-list (which disabled the trigger once get_consumer failed on a sustained outage): - get_consumer returns cheaply; consume owns a (re)connect loop that retries with a 30s backoff, reports a critical error every 10 failed attempts, and reports a recovered critical error once it reconnects — never disabling the trigger on a connectivity failure - a consumer/stream error breaks out to reconnect rather than disabling - dispatch failure still nacks+requeues (at-least-once) with a short backoff to avoid a tight poison-message loop, keeping the connection alive Verified against a live RabbitMQ broker: killing the broker keeps the trigger enabled and retrying (attempt N), and restarting it auto-reconnects (logs "reconnected after N attempts") and resumes dispatch. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(triggers): complete AMQP capture registries and constrain prefetch contract - add the 'amqp' case to triggerKindToTriggerType so opening the AMQP editor from a capture button no longer throws "Unknown TriggerKind: amqp" - register AmqpIcon in CaptureTable's icon map and add an AMQP entry to the script/flow CaptureButton menu - bound the OpenAPI prefetch_count to an integer 1-65535 (matches the Rust u16) and regenerate clients/prompts - require a non-empty exchange name when the exchange binding is enabled - build_uri: fall back to "/" on a blank vhost and bracket IPv6 hosts (+ tests) Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * feat(triggers): wire AMQP into pipeline graph, git-sync, and preprocessor types - asset_graph: discover attached amqp_trigger rows and emit an AMQP TriggerEdge so AMQP triggers render (and can be opened/deleted) on the data-pipeline canvas - frontend pipeline graph: add amqp to NativeTriggerKind, the add-trigger menu, node presentation, event-trigger set, annotation keywords, and the editor/service registrations - git-sync: add the amqp_trigger include pattern (+ test) so an AMQP git-sync deployment stages only its .amqp_trigger.* file, not an unrelated same-path object - preprocessor starters: add the AMQP event to the generated TS/Python/PHP trigger event types (kind/payload/exchange/routing_key/queue_name/redelivered/ delivery_tag) Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(triggers): finish AMQP pipeline/parser wiring, prefetch validation, source lists - fix a stray edit that corrupted the pre-existing MqttTriggerEditor import ($lib/... path) in PipelineTriggerEditors.svelte - reject prefetch_count = 0 server-side in validate_config (RabbitMQ treats 0 as unlimited) and defensively skip basic_qos(0) in build_consumer (covers the capture path that bypasses CRUD validation) - recognize `// on amqp` in the canonical parser (TriggerSpec::Amqp) and add amqp to the CLI non-autorun/event-trigger sets so a pipeline cascade never runs an AMQP-only node as a manual root without an event - add amqp to the preprocessor intro lists and both pipeline AI instructions Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(triggers): reject zero AMQP prefetch in all paths and finish guidance lists - extract a shared validate_amqp_options used by both CRUD validate_config and build_consumer, so capture configs (which bypass CRUD validation) also reject prefetch 0 instead of silently connecting with an unlimited buffer (+ unit tests for 0/1/65535/None) - add AMQP to the main script-writing preprocessor-sources prompt and the CLI triggers-skill guidance list Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * docs(triggers): de-duplicate AMQP prefetch comment and fix GET response text - keep the zero-prefetch rationale only on the shared validate_amqp_options doc; drop the redundant call-site comments - correct the getAmqpTrigger OpenAPI 200 description ("deleted" -> "retrieved") Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * chore: update ee-repo-ref to aaa6cb89b05b76139252c64f057e53b94d12ac60 This commit updates the EE repository reference after PR #680 was merged in windmill-ee-private. Previous ee-repo-ref: 5da5fd65aca9594b2611837a52e4677b544b0380 New ee-repo-ref: aaa6cb89b05b76139252c64f057e53b94d12ac60 Automated by sync-ee-ref workflow. * chore(migrations): consolidate the four AMQP migrations into one The table and the three enum ADD VALUE statements (trigger_kind, job_trigger_kind, draft_kind) are one atomic feature. ALTER TYPE ... ADD VALUE runs inside the migration transaction on PG >= 14 (Windmill's minimum) since the amqp_trigger table doesn't reference those enum types, so they can share a single migration instead of four. Verified applying cleanly in a single transaction on a fresh DB. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Co-authored-by: windmill-internal-app[bot] <windmill-internal-app[bot]@users.noreply.github.com> |
||
|
|
207ce8649c |
fix(ai-agent): don't mark repeated tool calls as failed in flow graph (#10075)
* fix(ai-agent): don't mark repeated tool calls as failed in flow graph Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * test(ai-agent): cover reporter's mixed repeated-tool-call scenario Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
c000bbca28 |
fix(frontend): scope raw-app, flow and script editors to the session workspace (#10015)
* fix(frontend): scope raw-app/flow/script editors to the session workspace Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(frontend): scope flow and script editor operations to the session workspace Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(frontend): scope flow preview, inline-script creation and datatable schema to the session workspace Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(frontend): address Codex review — thread session workspace through flow resource pickers, script fetch, preview cancel/recording and path collision check Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(frontend): address Claude review — pass session workspace to preview FlowStatusViewer and align FlowChatManager guards Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(frontend): address Pi review — show acting workspace in script-not-found message and fetch picked script from it in EditorBar Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(frontend): address Codex review round 2 — thread session workspace into flow step test, raw-app inline runnable, inline editor toolbars and MCP OAuth path Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(frontend): address Codex review round 3 — thread session workspace into dynamic-input helpers and the flow-preview argument side panel (history/saved-inputs/captures) Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(frontend): address Codex review round 4 — thread session workspace into nested flow/script drawers, flow chat inputs and the flow input side tabs Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(frontend): address Codex review round 5 — thread session workspace into script-module fork/reload and key the raw-app schema cache by workspace Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(frontend): address Codex review round 6 — key the DB manager schema cache by acting workspace Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(frontend): address Codex review round 7 — thread session workspace into resource-valued arg pickers and the editor variable/resource helper drawers Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(frontend): scope the flow asset explorer's ResourceEditorDrawer to the acting workspace Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix: thread acting workspace through flow asset explore controls Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix: thread acting workspace through SQL REPL, secret args, helper forms, S3 inputs, saved inputs Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
210ea3cc5a |
hide delete button on branchone default node (#9811)
The "Default" node of a branch-one is built with branchIndex -1 and is the structurally-required else branch (stored separately from the branches array), so it cannot be removed. Its delete button still rendered, and clicking it called deleteBranch with index 0, which in removeBranch became branches.splice(-1, 1) — destructively removing the LAST explicit branch. Gate the delete button on branchIndex >= 0 so it only appears on explicit branches. Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com> |
||
|
|
de6192bec1 |
fix(frontend): highlight the runtime-chosen branch in flow graph viewer (#9755)
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
24f32596e9 |
fix(apps): prevent decision tree graph editor crash on missing graph context (#9602)
NodeWrapper destructured `moveManager` from `getGraphContext()` unconditionally,
but FlowGraphContext is only set by the flow graph. The app decision-tree editor
reuses NodeWrapper without setting that context, so opening its Graph Editor threw
"Cannot destructure property 'moveManager' of getGraphContext(...) as it is undefined".
Guard the context with `?? {}` since `moveManager` is already used optionally.
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
||
|
|
eadeac248b |
feat: sessions page with isolated AI chat + flow editor (#9034)
* feat(sessions): chat + editor side-by-side with multi-session state
Introduces the Sessions feature: a workspace where the AI chat and an
editor (flow / script / app / raw-app) sit side-by-side, with each session
having its own AIChatManager instance, history, and target item. Sessions
are persisted across reloads and can be staged into forks for review.
Key pieces:
- sessions/ — SessionWrapper (the split-pane shell), SessionPicker
(sidebar list), SessionForkBar, SessionWorkspaceBar, FlowEditorView /
ScriptEditorView / AppEditorView / RawAppEditorView, ForkDiffDrawer,
sessionRuntime (per-session AIChatManager + draft state),
sessionState (in-memory + persisted index), sessionUnread, sessionScope,
appDraftCodec / flowDraftCodec, forkEditUrl, /sessions route.
- WorkspaceItemDrillPicker refactor — extracts WorkspaceItemRow + adds
surfaceAI drafts, stale-while-revalidate. workspacePicker.ts drops
explicit invalidate() in favor of always re-fetching in the background.
- ForkDiffDrawer + WorkspaceItemDiffViewer — per-kind diff bodies
reusable from the compare page. FlowGraphDiffViewer / FlowGraphV2 gain
inlineDiff forwarding + onHeight callback for equal-height layout.
- Global AI chat sessions plumbing — AIChatManager exports the class +
adds disabledModes, beforeSend hook, scoped instance context. AIChat /
AIChatDisplay accept session-only props (wideLayout, emptyHint,
inputPreface, hideHeader, hideModeSelector, forceDisabled). Chat
preserved across /flows/add → /flows/edit, /scripts/add → /scripts/edit.
- Draft-first loaders — sessions open drafts when present, otherwise
seed a draft from the last deployed value via globalDraftStore.
RawAppEditor / AppEditor / AppEditorHeaderDeploy get newApp prop +
fixes so draft-only apps can deploy.
- Compare page (/forks/compare) — bigger overhaul to plug into the new
drawer.
- Sidebar — Sessions entry + unread badge + status dot in
SidebarContent / MenuButton / SideBarNotification.
- Misc fixes — chat group color palette constraint, deploy_workspace_item
confirmation dropped, open_preview tool, picker drafts surfacing,
fork archive/delete buttons on compare page.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
* fix(sessions): bypass UserDraft inside session panes + sessionUnread crash
After merging main's UserDraft PR (#9121) into the sessions branch, two
integration issues surfaced:
1. AppEditor.svelte calls `UserDraft.use<App>('app', path)` at the
component level — keyed by ($workspaceStore, 'app', path). Sessions
that haven't materialized a fork yet stay at the user's main
workspace, so a session targeting an app at the same path as a
regular /apps/edit tab shared the same LS key. The session would
read the regular tab's autosave and write its fork-edits back over
it.
Gate UserDraft.use on `!getContext('aiChatManager')` — sessions
inject the manager via setContext, so inside a session pane the
handle is `undefined`, stateApp falls through to the `app` prop
the session loaded, and the auto-save $effect bails. Same gate on
the four UserDraft.remove call sites in AppEditorHeader and
RawAppEditorHeader so save/deploy from a session pane doesn't wipe
the LS draft of a non-session tab at the same path.
2. sessionUnread.svelte.ts called useLocalStorageValue at module
scope. Main's PR added a deep-mutation $effect inside that helper,
which now requires component-initialization context — every page
crashed at import time with `Svelte error: effect_orphan`.
Replaced with a plain module-level $state + manual localStorage
persist; same reactivity contract for callers.
3. ScriptEditorView.svelte was passing a `replaceStateFn` prop that
ScriptBuilder dropped on main. Removed.
Verified end-to-end with Playwright:
- /flows/edit/{path} regression: UserDraft handle still created, no
console errors
- /sessions loads, sessionUnread doesn't crash
- Session targeting non-raw app `u/admin/userdraft_collision_test`
displays the fork content (FORK_ONLY_MARKER) even with an LS
poison at `userdraft/w/local/app/{path}` containing a
POISONED_BY_REGULAR_TAB_AUTOSAVE marker; poison remains untouched
after the session loads and renders
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
* fix(sessions): stop fork-create retry loop on first user message
Removed the SessionWrapper $effect that retroactively committed the
session's workspace from the in-memory chat history. When opening a
session whose previous commit attempt had failed (or whose response was
lost) the effect ran in a tight retry loop, flooding the user with
`workspace_pkey` violations from `create_workspace_fork`.
The send path already commits through `AIChatManager.beforeSend` →
`commitSessionWorkspace`, which is the deterministic moment-of-action.
The $effect was a redundant reactive bridge that turned every backend
failure into an infinite retry.
Also hardens `materializeFork`/`commitSessionWorkspace` so the most
common cause of the duplicate-key error self-heals:
- `materializeFork` short-circuits when `fork.id` is already in
`$userWorkspaces` (the previous create actually succeeded, we just
lost the response). On a `workspace_pkey` catch, refresh the workspace
list and adopt the existing row instead of toasting an error.
- On a real `materializeFork` failure, `commitSessionWorkspace` now
drops `pending_fork` so the session falls through to the
workspace-pick fallback instead of looping on the same broken intent.
* feat(sessions): show EditorHeader breadcrumb in the not-found state
When a session's target item has been deleted or moved, the editor pane
used to render a bare "Script not found at path X" line — leaving the
user with no way to navigate to a different target without backing out
of the session.
Each editor view now renders a `SessionItemNotFound` shell instead: a
real `EditorHeader` (read-only summary, no pen popover) with a
breadcrumb keyed to the missing kind+path, plus the "not found" copy
below. Clicking any breadcrumb segment opens the workspace picker
scoped to that level — pick a replacement and the session swaps target
via the existing `onNavigate` callback.
`SessionItemNotFound` maps `raw_app` to `EditorHeader`'s `kind: 'app'
+ raw_app: true` so the picker routes through `/apps_raw/...`; the
local label still says "Raw app not found" (not "App not found") so
the user knows which surface is missing.
* fix(picker): stop self-feeding fetch effect that OOM'd the tab
The drill picker's $effect watched `scope` and called `ensureLoaded`
on every change. `ensureLoaded` reads `loaded[kind]` synchronously
(to decide whether to show a spinner), so the effect ended up
subscribed to the very signal it fills. Each fetch result wrote
`loaded[kind] = items`; Svelte 5's $state proxy notifies on every
property set even when the reference is unchanged from cache, which
refired the effect, which called `ensureLoaded` again, which awaited
the cached fetch, which wrote `loaded[kind]` again... runaway loop.
In `/scripts/edit/...` the picker's lifecycle stabilised quickly
enough to mask the loop, but in a session pane (multiple warm
sessions, picker kept alive by the surrounding state) the cycle
spun freely — 29.8 million iterations in <100 ms during testing,
enough to OOM Firefox / kill the Chromium tab.
Two changes:
- Replace the scope-watching $effect with an explicit `setScope()`
helper called from `drill()`, `goUp()`, and `onMount`. Fetch is
now a callback reaction to user navigation, never a reactive
consequence of one. No closed feedback cycle is possible.
- Untrack the `loaded[kind]` read inside `ensureLoaded`. The search
$effect (which loads every kind on first keystroke) is still a
reactive caller; the untrack stops it from subscribing to the
signal `ensureLoaded` fills, so the same loop can't form there.
* feat(script-editor): wire initialTestPanelCollapsed through ScriptBuilder
The `initialTestPanelCollapsed` prop was already declared on
`ScriptBuilderProps` (used by the session preview to start the editor
with the run/test pane closed) but never destructured in
`ScriptBuilder.svelte`, so the value silently dropped on the floor
and the test pane always opened.
- `ScriptBuilder.svelte` — destructure the prop and forward it to
`<ScriptEditor>`.
- `ScriptEditor.svelte` — accept the prop and seed `rawTestPanelSize`
to 0 when true, while keeping `storedTestPanelSize` at the default
30 so the user's first toggle expands the pane to a sensible width
rather than 0.
Regular `/scripts/edit/...` doesn't pass the prop → default `false`
→ panel still opens by default.
* fix(sessions): resolve aiChatManager via context in AskUserQuestionDisplay
Inside a session the chat uses a per-pane AIChatManager injected via context. AskUserQuestionDisplay imported the global singleton, so answers clicked in a session dispatched to the singleton's callback map and the AI loop stalled. Resolve via getContext with singleton fallback, matching ChatMode / ToolExecutionDisplay.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
* fix(raw_apps): let preview start in single-view on the preview tab
Add a defaultSplitWithPreview prop (default true). When false (session preview), the editor boots in single view with the preview tab selected: gate the onMount default-file activation, the setActiveDocument auto-activation, and iframeShouldMount so the UI Builder bundler iframe still mounts when preview is the active tab. RawAppEditorView passes defaultSplitWithPreview={false}.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
* feat(copilot): add get_preview_status tool and make open_preview idempotent
So the assistant can tell whether the session preview already shows the item it just edited, instead of re-opening or re-offering it. Mirrors the open_preview handler plumbing (setGetPreviewStatusHandler) and the session runtime registers it alongside open_preview. open_preview now returns 'already open' when the requested target matches the active session's current target. The system prompt steers the AI to check status before offering. Unit tests cover the no-arg schema, the session-only error, and handler dispatch.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
* fix(sessions): make script preview reactive to AI draft writes
ScriptEditorView read the draft via static UserDraft.get inside an effect, which only subscribes to UserDraft's reactive cell when a live entry exists. None did for the preview path, so the chat's writes (UserDraft.save) only touched localStorage and the open preview never updated. Hold a live handle via UserDraft.useMany (reactive getter so it re-acquires when open_preview swaps the path without remounting) and read inbound through handle.draft, materializing the shared $state cell that bridges the chat's writes to the editor.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
* fix(sessions): make raw-app preview reactive to AI draft writes
Mirror of the script-preview fix. RawAppEditorView read the draft via static UserDraft.get inside an effect, which only subscribes to UserDraft's reactive cell when a live entry exists. None did for the preview path, so the chat's raw-app writes (UserDraft.save / setDraftAndMeta, from write_app_file / patch_app_file / write_app_runnable) only touched localStorage and the open preview never updated. Hold a live handle via UserDraft.useMany (reactive getter so it re-acquires when open_preview swaps the path without remounting) and read inbound through handle.draft. Verified in-browser: an external UserDraft.save live-updates the bound summary in the open preview.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
* fix(sessions): make flow preview reactive to AI draft writes
Mirror of the script/raw-app preview fixes, completing two-way binding for all three session editor kinds. FlowEditorView read the draft via static UserDraft.get inside an effect, which only subscribes to UserDraft's reactive cell when a live entry exists — none did, so the chat's writes (write_flow / patch_flow_json / set_flow_module_code) only touched localStorage and the open preview never updated. Hold a live handle via UserDraft.useMany (reactive getter so it re-acquires when open_preview swaps the path without remounting) and read inbound through handle.draft. Verified in-browser both directions: an external UserDraft.save live-updates the flow header summary and rebuilds the module graph; a preview edit propagates through the debounced save to both UserDraft.get and the chat's getGlobalDraft adapter.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
* feat(sessions): surface local-storage drafts in fork diff & compare page
Augments the backend fork-vs-parent comparison with browser-local (UserDraft) drafts so a session's uncommitted AI/user changes are visible in the Fork Diff Viewer and the /forks/compare page. Adds forkDraftDiff.ts (augmentForkComparisonWithLocalDrafts + getForkItemValue), a 'local changes detected' / new-draft warning surface (checkbox-slot warning icon, no-op-baseline filtering, dedup), a 'Local draft <> fork' tab in DiffDrawer, and selectTooltip/nonSelectableTooltip plumbing in Row/WorkspaceDeployLayout.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
* Revert "feat(sessions): surface local-storage drafts in fork diff & compare page"
This reverts commit
|
||
|
|
9a659b636d | fix(frontend): prevent duplicate asset node ids crashing flow graph (#9367) | ||
|
|
0d0557fc9d |
feat: add wac ai context for frontend chat (#9021)
* feat: add wac ai context * fix: limit wac context languages * fix: pass wac auto kind in flow script drawer |
||
|
|
eebe24d8b0 |
feat(cli): wmill dev with per-flow proxy and responsive Dev UI (#8529)
* feat(cli): add `wmill flow dev` subcommand with per-flow reverse proxy and launch.json Also generates .claude/launch.json for existing flow folders during `wmill init`. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * feat: responsive dev layout and hide splitter for single-pane views Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * fix: clamp flow graph height between minHeight and maxHeight Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * feat(cli): enhance app new with Claude Desktop integration and better defaults - Add .claude/launch.json to generated app scaffold for Claude Code preview support - Add "Open in Claude Desktop?" prompt that creates a CLI session and opens it in Claude Desktop Code mode via the claude://resume deep link - Improve default CSS template with body background, system fonts, and padding Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix(cli): handle both .flow and __flow suffixes in wmill dev The flow detection in loadPaths only checked the configured suffix (dotted or non-dotted), so users with nonDottedPaths=true who had .flow folders (or vice versa) would see inline script edits treated as standalone script changes instead of flow changes. Now checks both suffix forms everywhere: type classification, folder path extraction, path stripping, and loadWmPath lookup. Also adds raw_app launch.json generation to init and sync pull. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * docs(cli): update generated skills with dev workflow and preview commands Update cli-commands, write-flow, and raw-app skills to document the new local dev workflow (wmill dev --path, --proxy-port, .claude/launch.json). Add wmill script preview and wmill flow preview to all script/flow skills so agents know how to test without deploying. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix(cli): include path in dev URL and use open.default for browser - Append &path= to the printed/opened URL when --path is specified - Use open.default(url) instead of open.openApp for more reliable browser opening Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * feat(cli): add Claude CLI/Desktop detection hints in wmill flow new Show contextual instructions for previewing flows based on available tools. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * chore: regenerate auto-generated CLI skills for new dev flags Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * fix(cli): handle mixed flow suffixes in dev file watcher The ignore() function uses isFlowPath() which only checks the configured suffix (__flow or .flow), causing files in the other variant to be silently ignored. Bypass the ignore check for any file inside a flow folder and force flow type detection regardless of suffix configuration. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * feat(cli): drop default proxy in flow folders, open browser, add --no-browser Manual `wmill dev` in a flow folder should not implicitly enable the reverse proxy. Both proxy and legacy modes now open the browser; the new --no-browser flag opts out. Claude Code launch.json templates pass --no-browser so the IDE preview doesn't fight a system browser window. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * feat(cli): gate dev broadcasts by --path and push currentLastEdit on connect When --path (or auto-detected flow path) is set, drop file events for any other path so the dev page stays locked to the requested resource and currentLastEdit can never reflect an unrelated edit. The connection handler proactively pushes currentLastEdit so the page renders without waiting for the first file change. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * fix(frontend): prefer WebSocket for flow round-trip when wmill dev is connected updateFlow used isInIframe priority, which routed Claude Code's iframe preview through postMessage (no listener) and silently dropped flow edits. Flip the priority: when the wmill dev WebSocket is open, use it (covers standalone tabs and Claude Code's preview); fall back to postMessage only when no WS is connected (the VS Code extension's iframe URL has no `local=true`, so it never opens one). Also stop assigning lastSent before a channel actually accepted the message, so a CONNECTING WS doesn't silently swallow the first change. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * feat(dev): url is source of truth for path; add workspace file picker Drops the server-side --path gate added in |
||
|
|
d6c642b170 |
feat: add Azure Event Grid triggers (#8888)
* feat: add Azure Event Grid triggers (EE)
Introduces a new enterprise trigger kind `azure` that supports three
modes via a single unified trigger type:
- basic_push: Azure Event Grid basic — custom topics, system topics
(Storage, Resource Manager, Key Vault, etc.), domains (push only)
- namespace_push: Event Grid Namespace topics (CloudEvents over HTTP push)
- namespace_pull: Event Grid Namespace topics (HTTP pull with lock-token
ack/reject for dead-lettering)
Auth uses a Service Principal resource (tenant_id, client_id,
client_secret, subscription_id). Subscriptions are created in
CloudEvents 1.0 schema so the push webhook handler and the pull listener
share one payload parser.
Backend
- New crate `windmill-trigger-azure` (OSS stubs + EE impl symlinked from
windmill-ee-private)
- Migration `azure_trigger` table with CHECK constraints enforcing
mode/columns coherence
- `TriggerKind::Azure`, `JobTriggerKind::Azure`,
`DeployedObject::AzureTrigger` variants
- Push route `/api/azure/w/{workspace}/*path` handles classic
Event Grid SubscriptionValidation handshake and CloudEvents 1.0
abuse-protection OPTIONS handshake
- Optional inbound JWT validation (audience check only for v1)
- Feature flag `azure_trigger` propagated through windmill-api,
windmill-store (resource helper), and added to ee_core
Frontend
- `triggers/azure/` editor with mode toggle (basic/namespace-push/
namespace-pull) and per-mode config (topic ARM id / namespace +
topic name / subscription / filters / push auth / pull options)
- Registered in icon map, display names, save functions, badge,
wrapper, editor, add-trigger menu
OpenAPI
- `AzureTrigger`, `AzureTriggerData`, `AzureMode`,
`AzureSubscriptionMode`, `AzureDeliveryConfig`, `TestAzureConnection`
schemas; `/azure_triggers/*` endpoints; client regenerated
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* chore: update ee-repo-ref to eaa7c3a9cb37a9ccc93f10a2535d929365acd2d8
This commit updates the EE repository reference after PR #541 was merged in windmill-ee-private.
Previous ee-repo-ref: 9689014e8c12c36c1059fd8fa5758d550b8b8bc9
New ee-repo-ref: eaa7c3a9cb37a9ccc93f10a2535d929365acd2d8
Automated by sync-ee-ref workflow.
* feat(azure-trigger): secret-auth push, ARM discovery, capture isolation, CLI + parity
Frontend:
- Split mode selector into Namespace/Basic + Pull/Push
- ARM resource dropdowns (namespaces, Basic topics, namespace topics)
populated from the service principal; cascade with stale-selection
reset on SP / edition change
- Remove stale authenticate toggle + audience input (server-managed
push_auth_config has replaced them)
- Azure listing page: "Create from template" button; "Also delete Azure
subscription" toggle in the delete modal; simplified trigger label
falling back to path
- AzureCapture.svelte: "Test subscription name" with -wm-capture suffix
- CompareWorkspaces.svelte: wire Azure for fork/compare
- Drop Trigger-deployed/event-loss warning (capture subscription is
isolated with -wm-capture)
Backend:
- Shared-secret push auth (see EE crate for detail)
- JSONB push_auth_config column (renamed from delivery_config), #[serde(skip)]
so clients/CLI/exports never see it
- Drop redundant enabled column; mode supersedes
- Azure capture infra: AzureTriggerConfig + set_azure_trigger_config +
azure_payload route + TriggerKind::Azure arm; PT15M queue TTL on
capture subscriptions so they bound storage after tab close
- Granular ACLs, users offboarding, trash, git-sync deployed-object:
all include azure_trigger
CLI:
- Add azure to TRIGGER_TYPES, pushObj dispatch, getTypeStrFromPath,
trigger commands (get/update/create/list/template), sync delete
switch + regex; e2e test for `trigger new --kind azure`
- system_prompts: SCHEMA_MAPPINGS + schema_names include AzureTrigger;
auto-generated/* regenerated
Skill:
- .claude/skills/adding-a-trigger/ checklist covering every file that
needs editing when wiring a new trigger type (learned from this PR)
ee-repo-ref bumped to b0e490cbf3724b7b64c6a5b010e3bdf24acd873c.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* fix(azure-trigger): ci — ShareModal Kind + regenerated system_prompts
- frontend/src/lib/components/ShareModal.svelte: add 'azure_trigger'
to the Kind type so the listing page's "Permissions" action compiles
(ts2345 — caught by npm_check on CI, missed by fast-check locally).
- system_prompts/auto-generated/: regenerate to drop the stale
delivery_config / AzureDeliveryConfig fields from the Azure schema
(check-freshness on CI).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* refactor(azure-trigger): use workspace constant_time_eq crate
Drop hand-rolled constant-time compare in favour of the workspace
constant_time_eq crate (same one used by http_trigger_auth).
ee-repo-ref bumped to 9659382d47286e7f7f66d01b6f5dd8d4ed34848b.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* fix(azure-trigger): pass placeholder + disabled via inputProps
`TextInput`'s `placeholder` and `disabled` go through its `inputProps`
prop — CI's `npm run check` caught the stale top-level passing that
`npm run check:fast` missed. Align with the DefaultEmailConfigSection
pattern.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* fix(azure-trigger): correct LATEST_GIT_SYNC_SCRIPT_PATH version to 28213
The hub deploy of the azure-aware sync-script is version 28213, not
28214. Backend was pinning a non-existent hub script, which broke the
git_sync_e2e suite (every deploy's sync step 404'd).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* fix(azure-trigger): add azure_triggers to token scope selector + skill
- windmill-api/src/token.rs: `build_trigger_scope_domains` was missing
`("azure_triggers", "Azure Event Grid")`, so the CreateToken UI's scope
selector didn't surface azure_triggers:read/write. Backend already had
`ScopeDomain::AzureTriggers` wired (scopes.rs), this just exposes it.
- .claude/skills/adding-a-trigger/SKILL.md: capture both scope-related
files under the hardcoded-arrays section so future triggers don't miss
the UI surface.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* docs(adding-a-trigger-skill): clarify token.rs scope effect
Not a regression — nothing was working before. Skipping TRIGGER_DOMAINS
just means the scope works via API/CLI but has no UI checkbox.
* docs(adding-a-trigger-skill): trim token.rs bullet
* fix(azure-trigger): regen openapi-deref + swap textarea for TextInput
- Run build_openapi.sh to regenerate openapi-deref.{yaml,json} with the
12 azure_triggers paths + schemas. These files are served by the
runtime (include_str! in windmill-api/src/lib.rs) to external SDK
consumers; without this regen the new endpoints wouldn't be advertised.
- Replace the raw <textarea> for event type filters with the
design-system TextInput in textarea mode (frontend/CLAUDE.md bans raw
HTML elements).
Addresses cubic + claude PR review items.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-authored-by: windmill-internal-app[bot] <windmill-internal-app[bot]@users.noreply.github.com>
|
||
|
|
4f998cc231 |
feat: add GitHub as a native trigger service (#8856)
* feat: add GitHub as a native trigger service Add GitHub webhooks as a native trigger, allowing users to trigger scripts/flows from repository events (push, PR, issues, etc.) via OAuth-based webhook management. Backend: - DB migration adding 'github' to native_trigger_service, TRIGGER_KIND, and job_trigger_kind enums - Full External trait implementation: create/update/delete/get webhooks, per-trigger sync verification, webhook payload preparation - Paginated repos endpoint (up to 1000 repos) - OAuth flow with admin:repo_hook and read:user scopes Frontend: - GitHub trigger form with repo picker and MultiSelect event selector - Workspace integration settings with setup instructions - Trigger badge, editor, and wrapper integration - GithubIcon updated to support size/class props (matching other icons) - Hub template reference for starter scripts Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix: show GitHub in sidebar when triggers exist Add github_used to the getUsedTriggers endpoint so the sidebar picks up GitHub as an active trigger kind. Also document this step in the native- trigger skill so future services don't miss it. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * feat: on-demand GitHub repo search instead of bulk fetch Replace the upfront pagination through all repos with a debounced search flow: load 30 most-recently-updated repos by default, then query GitHub's /search/repositories API (scoped to the authenticated user via user:@me and restricted to name matches via in:name) as the user types. Frontend uses runed's Debounced + resource to wire the Select's filterText to the backend query with 300ms debouncing. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix: request `repo` OAuth scope to list private GitHub repos `admin:repo_hook` grants webhook management but not repo listing — so /user/repos and /search/repositories returned only public repos. Switch to `repo` (full repo scope, which is a superset and also covers webhook management). Users who already connected GitHub need to disconnect and reconnect to pick up the broader scope. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * revert: fetch all GitHub repos upfront instead of searching on demand Revert the debounced search flow — paginate through /user/repos (up to 1000) on form open. Simpler UX: repos are all there from the start, the Select's built-in client-side filter handles finding one. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix: typed 404 detection + add GitHub flow template reference Replace fragile e.to_string().contains("404") matching with a proper http_error_status helper that downcasts through anyhow to the typed HttpRequestError and reads the StatusCode. Also wire the hub flow template (id 80) into NATIVE_TRIGGER_SERVICES. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix: update GitHub script template hub ID to 28202 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix: align GitHub trigger with Nextcloud/Google patterns Addresses review feedback from Claude and cubic. Backend: - `delete()` now only swallows NotFound (DB missing row) and 404 (API webhook already deleted); non-404/DB errors propagate so callers know cleanup failed. Matches Nextcloud's delete pattern exactly. - `get_owner_repo_from_db` returns `Result<Option<(String, String)>>` instead of an error on missing row (matches Google's delete flow). Frontend: - `loading: boolean` (required) + `$bindable()` with no default — matches Nextcloud, satisfies CLAUDE.md banned-pattern rule. - Wrap `loadRepos()` in `$effect` reacting to `$workspaceStore` so repos load once the store is available and refresh on workspace switch. - Replace raw `fetch('/api/.../native_triggers/github/repos')` with the generated `NativeTriggerService.listGithubRepos(...)` typed client. Adds `/repos` route + `GithubRepoEntry` schema to openapi.yaml. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com> |
||
|
|
c889a185d5 |
refactor: extract flow delete helpers (#8746)
* refactor: extract flow delete helpers Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * refactor: unify flow delete planning Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * refactor: stabilize flow delete execution Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * refactor: simplify flow delete plan execution Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com> |
||
|
|
6d36eca216 | fix: Flow status viewer layout nits (avoid excess y space and scroll) (#8780) | ||
|
|
abc6b12d68 |
feat: WAC workflow diagram visualization via WASM (#8604)
* feat: WAC workflow diagram visualization in script editor Add WASM-powered workflow diagram for WAC scripts in the script editor, inspired by Cloudflare's workflow diagrams approach. Parses WAC code client-side via WASM and renders an interactive DAG using @xyflow/svelte. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * feat: show WAC diagram on script detail page Show the workflow diagram below the run form on the script detail page for WAC scripts, matching how flows display their graph. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * feat: handle try/catch and while loops in WAC diagram Instead of rejecting these patterns with validation errors, render them as graph nodes: - try/catch → Branch node with "try"/"catch" edge labels - while loops → LoopStart/LoopEnd with condition as iter_source Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * chore: remove dead code from WAC parser and add pkg-wac to publish script Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * chore: use published windmill-parser-wasm-wac@1.668.5 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix: handle undefined language prop in WacDiagram usage Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix: resolve windmill-parser-wasm-wac from npm registry in lockfile Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix: create actual merge nodes for branch/try-catch convergence points Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com> |
||
|
|
0fb115304a |
fix: preserve notes on nodes inside collapsed groups (#8552)
* fix: preserve notes on nodes inside collapsed groups Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix: hide notes for nodes inside collapsed groups instead of repositioning Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com> |
||
|
|
c0aafee9a9 |
feat: improve-replay-ui (#8250)
* Improve UI of script record * Improve UI for scripts * Remove Result & Logs loading container while flow not finised * Improve Graph view * Add click on a step mention * Fix spacing when empty * Fix step duration disappearing in recorded flows * Modernize timeline tab * Improve Script recording result UI * feat: externalize recording player controls for fake-window embedding Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * refactor: reorder FlowViewer tab sync effects for clarity Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * refactor: eliminate tab sync effects in FlowViewer, use selectedTab directly Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * refactor: remove unnecessary untrack in FlowViewer tab init Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix: skip tab auto-selection when selectedTab is controlled externally Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * feat: export recording types from package Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix: non-null assertion for recording.flow in FlowGraphViewer Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix: replace banned $bindable(default_value) pattern and simplify tab sync Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix: use svelte 5 onclick syntax on replay page Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix: skip db clock endpoint during replay mode Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix: remove line numbers from script recording code display Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> --------- Co-authored-by: hugocasa <hugo@casademont.ch> Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com> |
||
|
|
81eb446eee |
feat: flow group nodes with collapsible groups (#8075)
* feat: add flow group nodes core infrastructure Add group data model (start_id/end_id boundary pairs), GroupEditor for CRUD operations, groupDetectionUtils for membership computation and validation, GroupedModulesProxy for reactive sync, and compound layout support. Update openflow.openapi.yaml with group schema. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * feat: add group UI components and rendering Add GroupOverlay with bounding box and z-ordering, GroupHeader with StepCountTab and ellipsis menu, GroupNodeCard, GroupNoteArea for inline markdown notes, CollapsedGroupNode/CollapsedSubflowNode for collapsed rendering, GroupEndNode/GroupHeadNode boundary markers, and group actions in NodeContextMenu and SelectionBoundingBox. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * feat: integrate groups into flow graph, builder, and existing components Wire group support into FlowGraphV2 (overlays, collapsed rendering, group-aware layout), graphBuilder (GroupedModule tree, container collapse/expand, group boundary nodes), BaseEdge (drop targets for group operations), ModuleNode (collapsed container rendering), and flow map components (schema item grouping). Remove SubflowBound in favor of CollapsedSubflowNode. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix: remove banned $bindable(default) pattern and dead ternary Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * refactor: decouple collapse state from grouped module tree Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * feat: pass groups prop to FlowGraphV2 and use GroupDisplayState via graphContext Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * refactor: remove group membership system, compute nesting depth from visual bounds Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * refactor: simplify GroupOverlay bounds, remove unused headerY and showNotes prop Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix: populate innerNodeIds for expanded subflow overlay Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * refactor: remove expanded subflow overlay feature for separate PR Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix: flatten groups in getContainerModules to prevent crash on collapsed containers Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * feat: add drag-to-move support for group nodes Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix: derive group boundaries from expanded membership to prevent splitting existing groups Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix: catch group validation errors and display as flow graph alert Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * test: add unit tests for group validation in buildGroupedModules Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix: reject virtual nodes (Input, Result, Trigger) from groups Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * test: add virtual node rejection tests for buildGroupedModules Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix: exclude preprocessor and failure module from groups Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix: disable Create group button when preprocessor is selected Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix: reject selection entirely when it contains excluded nodes Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * refactor: remove unnecessary excludeIds from buildGroupedModules Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix: remove debug console.log from FlowGraphV2 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix: use cross-browser CSS grid trick for group summary input auto-sizing Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix: hide group boundary edges and reformat GroupNoteArea Hide edges between group header and first node, and between last node and group-end, keeping them in the DOM but visually hidden. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * refactor: stop FlowGraphV2 from reading groups via groupEditorContext Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * feat: show module previews with status, selection, and suspend popover in collapsed groups Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * refactor: extract collapsible implicit containers to separate branch Remove collapse/expand functionality for implicit containers (forloops, while loops, branches) from this branch. Backed up as collapsible-implicit-containers-backup for later rebase. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * refactor: use original reactive modules for graph node data instead of proxy snapshots Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix: prevent node loss when moving into forloop inside a group Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * refactor: replace GroupedModule proxy with structure-only FlowStructureNode tree Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix: use "group-" prefix for group IDs instead of "note-" Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix: update group boundaries when renaming a module ID When a module at a group boundary (start_id or end_id) is renamed, the group definitions now get updated before the reactive rebuild, preventing stale references that would break the flow structure. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix: update graph layout when removing a group note Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix: add opaque background behind test run button to prevent see-through Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix: detect and reject duplicate group IDs Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix: simplify group creation validation with early marker normalization Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix: use $state.raw in MiniFlowGraph to avoid xyflow performance warning Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * refactor: address code review feedback - Revert backend traverse_modules change (not part of this feature) - Use Map for node lookup in GroupOverlay (O(1) vs O(n) per group) - Extract computeNodeExtraSpace to nodeExtraSpace.ts for testability Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * refactor: address PR review feedback - Compute group depths from structure tree O(n) instead of O(n²) bounds comparison - Remove unnecessary $derived(groups) in GroupOverlay - Remove unused collapsed field from container types in OpenAPI spec - Use NODE.width constant in GroupNodeCard instead of hardcoded 275px - Add comment explaining intentional stale preservation in rebuild() Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix: preserve flow groups during dependency job re-serialization Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix: resolve Svelte state_referenced_locally warnings in GroupHeader and FlowGraphV2 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * feat: show subflow groups when expanding a subflow in the graph - Store both modules and groups when expanding a subflow - Pass groups to buildStructureTree so group nodes render - Include subflow groups in overlay rendering and collapse tracking - Clone modules for prefix rewriting to avoid state_unsafe_mutation - Register expanded subflow modules in moduleMap before prefix rewriting - Disable group editing in expanded subflows and read-only views Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix: restore accidentally removed code from main - Restore subflowBound selection handling in selectionUtils - Restore comments in SelectionBoundingBox - Restore deletable={false} in FirstStepInputs Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * refactor: remove redundant adjacency check from MoveManager The disableMoveIds check already prevents all invalid drop targets, making the adjacencySourceId/adjacencyTargetId fields unnecessary. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * chore: regenerate auto-generated files after OpenAPI schema change Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * chore: regenerate cli skills after main merge Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix: include groups in view_graph localStorage state Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * refactor: centralize canCreateGroup and replace group note with group creation - Add canCreateGroup StateStore to GroupEditorContext, computed in FlowGraphV2 - Replace "Create group note" with "Create group" in FlowSelectionPanel - Remove "Add note" from selection bounding box dropdown - Remove unused NodeContextMenu component - Wire createGroup through FlowModuleSchemaMap → FlowGraphV2 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix: reject groups spanning parallel branches and surface ill-formed group errors Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * chore: regenerate auto-generated files after main merge Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix: ensure modules appears before groups in YAML export Svelte 5's $state proxy registers groups as a tracked property before it's explicitly set, causing it to appear before modules in Object.keys iteration. Reorder the value object at export time for readable YAML. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * refactor: address second round of PR review feedback - Add comment explaining duplicateMultiple bypasses structure tree - Add warning log for inverted ranges in computeGroupModuleIds - Use NODE.width constant in CollapsedGroupNode instead of hardcoded 275px - Simplify redundant condition in getGroupsEmptiedBy Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * refactor: remove stored group ID, derive ephemeral key from start_id:end_id Groups no longer store an `id` field. Instead, a `groupKey(g)` helper derives an ephemeral key from `${start_id}:${end_id}` at read time. This simplifies the schema while preserving all runtime functionality. When boundaries shift (module deletion), runtime state (collapse, note heights) is remapped to the new key via GroupDisplayState.remapGroupKey. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * feat: add note button, save/cancel hints, and rename collapsed_by_default to autocollapse Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix: propagate selection from collapsed group badges to external listeners Pass eventHandlers to GroupModuleIcons so clicking a module badge calls both selectionManager.selectId (visual highlight) and eventHandlers.select (side panel propagation via onSelect). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * chore: regenerate auto-generated files after main merge Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix: hide In/Out popovers and actions during click-to-move Replace isDragging with isMoving derived that covers both drag-move and click-move states, disabling popovers, delete button, and test run button during any move operation. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com> |
||
|
|
31d6660d56 |
feat: script module mode with CLI sync, preview, and WAC UI improvements (#8380)
* feat: add script module mode with folder model for Bun and Python Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: add missing modules field to RawCode in bun_executor Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * sqlx * feat: enrich WAC templates with checkpoint and replay semantics Add prominent comments explaining that all computation must happen inside task/step/taskScript or it will be replayed on resume/retry. Clarify that waitForApproval does not hold a worker and that approve/reject URLs are available in the timeline step details. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix(cli): script module sync idempotency, per-module hash tracking, and preview support - Fix pull→push idempotency: use `??` instead of `||` for module lock field so empty strings are preserved (matches API's `lock: ""`) - Add per-module hash tracking in wmill-lock.yaml following the flow inline script pattern (SCRIPT_TOP_HASH + per-module subpath hashes) - Selective module lock regeneration: only regenerate locks for modules whose content actually changed, not all modules - Use unfiltered rawWorkspaceDependencies for module hashes to match what updateModuleLocks passes to fetchScriptLock - Show changed module names in stale script output for clarity - Add module support to `script preview` command: read modules from __mod/ folder and pass them in the preview API request - Add preview tests for taskScript pattern (flat and folder layout) - Update test assertion for module stale detection output Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * feat(frontend): WAC UI improvements — reorder templates, module tab rename, import consolidation - Reorder WAC template buttons: TypeScript before Python in ScriptBuilder, CreateActionsScript, and CreateActionsFlow - Remove dropdown items from +Script button (simplify to direct link) - Move "Import Workflow-as-Code" to +Flow dropdown with dedicated drawer - Add module tab rename: pencil icon on hover opens popover with validation, fixed-width icon container prevents layout shift Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * feat: remaining module-mode changes from working branch - Backend parser updates for WAC detection - CLI sync/types updates for raw app path and module support - Frontend UI polish (Dev.svelte, ScriptRow, script hash page) - Test fixture updates Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * test(cli): add test for module modification detection in generate-metadata Verifies that modifying a single module file re-triggers stale detection and only the changed module is listed, not all modules. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix(backend): critical fixes from PR review - Fix hardcoded dev path in bun_executor.rs WAC v2 wrapper — use "windmill-client" import instead of absolute filesystem path - Fix missed no_main_func → auto_kind rename in parser TS test - Add modules column to clone_script SQL (windmill-common and windmill-api-workspaces) so cloned scripts retain their modules - Add modules: None to RawCode structs in worker tests - Restore complete sqlx cache (merge main's cache + our new queries) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix(backend): fix clone warning treated as error in CI Change `.clone()` on double reference to `*k` dereference in scripts.rs hash implementation. Update sqlx cache with new query hashes from modified clone_script SQL. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix(frontend): use published parser wasm versions for CI build The local file:// paths for windmill-parser-wasm-py and windmill-parser-wasm-ts don't exist in the Cloudflare Pages build environment. Revert to published npm versions (1.655.0). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix(frontend): update parser wasm packages to 1.657.2 Use newly published windmill-parser-wasm-ts and windmill-parser-wasm-py v1.657.2 which include auto_kind/WAC detection changes. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix(frontend): regenerate package-lock.json for npm ci compatibility Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix(frontend): use main's lockfile as base, update only parser wasm packages Regenerating package-lock.json from scratch pulled different dependency versions causing svelte-check type errors. Instead, start from main's lockfile and only update the two changed packages. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix(backend): add modules column to fetch_script_for_update query The Script<SR> struct has a modules field (FromRow), but fetch_script_for_update didn't SELECT modules, causing a runtime error "no column found for name: modules" when the worker processed dependency jobs. This was the root cause of the relock_skip test timeout. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix(backend): fix script module execution for Python and Bun - Fix modules not passed through job queue: inject _MODULES into PushArgs.extra when pushing Code jobs so worker can extract them - Fix Python module imports: use relative imports (from .helper) and add sys.path.insert for module directory in wrapper - Fix Python tests: use relative imports and empty lock to prevent pip from resolving module names as packages - Add local file check in Bun loader for module resolution - Ignore Bun module test (bundle mode loader integration tracked separately) - Add missing modules column to fetch_script_for_update query Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix(backend): remove unnecessary empty lock in Python module tests Relative imports (from .helper) are not parsed as pip packages, so the empty lock workaround is not needed. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix(backend): fix module execution for Python and Bun — all tests pass Python modules: - Use relative imports (from .helper import greet) since scripts run as packages - Add sys.path.insert for module directory in wrapper to ensure local modules take precedence over pip packages with same name Bun modules: - Use bundled output (./out/main.js) as wrapper import when modules are present — the bundled output has module content inlined by Bun.build, avoiding runtime loader resolution issues - Add local file check in loader.bun.js onResolve to short-circuit API URL resolution for module files on disk Job queue: - Inject _MODULES into PushArgs.extra when pushing Code jobs so the worker can extract them at execution time Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * refactor: address PR review — simplify, fix correctness, remove dead code Critical fixes: - Replace all CLI `no_main_func` references with `auto_kind` (string) to match the backend migration and API changes - Remove duplicated `compute_python_module_dir` in worker.rs, use the canonical version from python_executor.rs High priority: - Auto-create `__init__.py` in intermediate directories for nested Python modules so imports like `from .utils.math import add` work without users manually creating __init__.py files - Remove redundant `sys_path_insert` — relative imports use Python's package system, not sys.path Medium: - Fix lock file base name extraction: use regex to strip only the final extension (`.replace(/\.[^.]+$/, '')`) instead of `indexOf(".")` which breaks for files like `helper.test.ts` Simplification: - Remove dead `{#if false}` Popover block in ScriptEditor.svelte - Guard loader.bun.js local file check to only run for relative paths (matching the Windows loader pattern) - Add clarifying comment on Bun dual mechanism (build + run phases) - Add maintenance comment on manual Hash impl for NewScript Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix: final review fixes — stale cleanup, baseName, auto_kind export - Fix sync.ts baseName extraction using indexOf(".") → regex (same fix as script.ts/metadata.ts, missed this instance) - Add stale module file cleanup in writeModulesToDisk: removes files from __mod/ that are no longer in the modules map before writing, fixing the pull→push cycle that couldn't delete modules - Log warning when _MODULES serialization fails in job push instead of silently dropping modules - Use strict equality (===) for auto_kind comparison - Exclude auto_kind from workspace export — it is auto-detected by the parser at deploy time from script content Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix(cli): remove auto_kind from push, comparison, and metadata auto_kind is auto-detected by the parser at deploy time, so the CLI should not send it, compare it, or write it to script.yaml. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix: remove erroneously added backend/backend/.sqlx directory Duplicate .sqlx cache was committed at the wrong nested path. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix: address PR review feedback + fix CI dead_code warning Frontend (ScriptEditor.svelte): - Fix switchToMain() missing lastSyncedCode update — prevents stale code sync on external changes while editing a module tab - Fix formatAction saving module code to main script's localStorage draft — now saves main code when on a module tab - Fix non-null assertion on inferModuleLang in renameModule — fall back to original language instead of force unwrap - Remove redundant activeModuleTab truthy check in runTest CLI (script.ts): - Clean up empty directories after removing stale module files in writeModulesToDisk Backend: - Add path traversal guard in write_module_files — reject module paths containing ".." - Fix dead_code warning on auto_kind field in workspace export struct Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * feat(frontend): improve auto_kind UX + address review findings - Rename "Include without main function" toggle to "Include library scripts" in script list (ItemsList.svelte) - Update NoMainFuncBadge: "No main" → "Library" with clearer tooltip - Filter module file extensions by main script language — Python scripts only allow .py modules, TypeScript only .ts, etc. - Split flushModuleState into flushModuleContent (no UI side-effect) and flushModuleState (flush + reset tab), reducing duplication - Dynamic placeholder and hint text in add module popover based on main script language Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com> |
||
|
|
c431053a1e |
fix(frontend): prevent duplicate and reserved agent tool names (#8367)
* fix(frontend): prevent duplicate and reserved agent tool names Extend tool name validation to detect duplicates within an agent step and reserved names (like 'preprocessor', 'failure'). Show specific error messages in the editor panel and red styling in the graph view. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix(frontend): remove duplicate banner for agent tool name errors The inline per-tool error messages are sufficient — the panel-level banner was redundant and showed a double error. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com> |
||
|
|
cad44365ac |
feat(frontend): replace flat sugiyama with recursive compound layout for flow graph (#8204)
* feat(frontend): replace flat sugiyama with recursive compound layout for flow graph Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix(frontend): double forloop wrapper padding and include wrappers in bbox Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * fix(frontend): gate debug wrappers behind SHOW_DEBUG_WRAPPERS flag Remove all debug console.log calls from compoundLayout and gate WrapperInfo creation and wrapper node rendering behind an exported SHOW_DEBUG_WRAPPERS constant. Replace wrapper-based bbox computation with groupLayouts-based loop so no WrapperInfo is needed for correct layout. Add contentMinX to LayoutResult for the top-level minX shift. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix(frontend): remove debug wrapper nodes from flow graph Remove WrapperInfo type, SHOW_DEBUG_WRAPPERS flag, buildDebugWrapperNodes helper, DebugWrapperNode component, and all related plumbing in FlowGraphV2. The bbox computation now uses groupLayouts directly, keeping layout correctness without any debug wrapper overhead. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * perf(frontend): optimize compoundLayout recursive algorithm Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * refactor(frontend): remove dead offset plumbing from flow graph The old flat sugiyama layout used a CSS margin-left hack (offset) to indent loop bodies. The new recursive compound layout handles indentation natively via coordinates, making the entire offset pipeline dead code. Removes offset from 11 node type definitions, NodeLayout, addNode helper, processModules parameter, NodeWrapper prop, 9 node renderers, AssetNode x-position calculations, AIToolNode x-position calculations, DragGhost nodeOffset function, FlowGraphV2 layout pipeline, util.ts type signatures, noteUtils NodeDep type, and noteEditor function signature. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix(frontend): remove unused lastXCenter variable Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * perf(frontend): optimize compoundLayout hot paths Replace O(N²) queue.shift() with index pointer in BFS, eliminate redundant groupOwnedIds double-build, use Set for parent dedup, track minY in existing bbox loop, and cache maxBranchHeight. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * chore: remove debug artifacts from PR Remove elk_viewer test page, console log dumps, and layout screenshots that were used during development. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix(frontend): guard data.module.value access in ModuleNode When rapidly clicking expand/collapse on a subflow, the graph rebuilds and data.module can be transiently undefined. Add optional chaining to prevent "Cannot read properties of undefined (reading 'value')" errors. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * refactor(frontend): simplify CompoundGroup type to 'branch' | 'loop' The layout never distinguishes branchall/branchone or forloop/whileloop, so collapse to two variants that match the actual code paths. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix(frontend): address PR review feedback on flow layout - Add max recursion depth guard (50) to layoutLevel to prevent stack overflow with malformed flow data - Log swallowed decrossOpt error as console.debug for debuggability - Initialize maxY to -Infinity for correctness with negative positions - Fix indentation artifacts in graphBuilder data objects Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * formatting * fix: remove offset field from asset node data in FlowGraphV2 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com> |
||
|
|
a6d4390790 |
feat: workflow-as-code (WAC) v2 (#8172)
* feat: workflow-as-code v2 with @task decorator API
Replace ctx.step("name", "script") API with @task decorators where
functions are called directly. Users no longer need to pass WorkflowCtx
or use string-based step names/script paths.
Python: @task decorator with contextvars-based implicit context
TypeScript: task() wrapper with module-level context variable
Parsers: detect @task function calls instead of ctx.step() calls
Worker: updated wrappers to set implicit context
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* feat: WAC v2 checkpoint/replay with _executing_key child dispatch
- Rust-side orchestration: parent dispatches child jobs, suspends, resumes on completion
- _executing_key in checkpoint tells child which step to execute directly
- task() throws StepSuspend(mode="step_complete") after executing target step
- result_processor handles child completion and updates parent checkpoint
- WacGraph.svelte for runtime execution visualization
- Sequential and parallel workflows tested end-to-end
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: WAC v2 bundle cache, globalThis ctx sharing, description optional
- Disable bun bundle caching for WAC v2 scripts (wrapper needs
windmill-client from node_modules, not available in bundle mode)
- Use Reflect.set/get(globalThis, "__wmill_wf_ctx") to share workflow
context across dual module instances (wrapper vs user script)
- Never-resolving thenable for non-matching steps in child job mode
prevents Promise.all race conditions
- Make description field optional in NewScript API (defaults to "")
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* feat: add step() primitive for inline checkpointed steps
step() executes a function inline (no child job) and persists the result
to the checkpoint. On replay, the cached value is returned — ensuring
deterministic behavior for non-deterministic operations like Date.now()
or Math.random().
- TypeScript: step(name, fn) — executes inline, throws StepSuspend with
mode "inline_checkpoint" to persist before continuing
- Rust: InlineCheckpoint variant in WacOutput, saves to checkpoint and
resets running=false for immediate re-pickup (no zombie wait)
- Shared step counter between task() and step() via _allocKey()
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* feat: add Python WAC v2 support with task(), step(), workflow()
- Python SDK: WorkflowCtx with _executing_key child mode, _alloc_key
shared counter, _run_inline_step for step(), _execute_directly and
_never_resolve for child mode, step() async function
- Python executor: WAC v2 detection, checkpoint.json writing, WAC
wrapper.py generation calling _run_workflow(), post-execution hook
into shared handle_wac_v2_output()
- Make handle_wac_v2_output pub so both bun and python executors share
the same dispatch/suspend/inline-checkpoint logic
- 17 Python tests covering dispatch, replay, parallel, conditional,
inline checkpoint, and child mode
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* chore: update sqlx prepared queries
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: WacGraph Tooltip→Popover, simplify wacToFlow parsers
- Fix type error: Tooltip doesn't accept text snippet, use Popover
- Extract shared helpers for task matching and block collection
- Replace linear tasks.find() with Map lookups
- Remove mutable module-level counter
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: Box::pin WAC v2 output handler to prevent stack overflow
handle_python_job's async state machine was too large when combined
with handle_wac_v2_output. Box::pin heap-allocates the future.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: merge WAC v1 and v2 task decorators to preserve backward compat
The v2 @task decorator was shadowing the v1 one, breaking WAC v1
scripts that rely on HTTP-based dispatch via /workflow_as_code/ API.
The merged decorator handles three modes:
- v2: inside @workflow context → checkpoint/replay dispatch
- v1: WM_JOB_ID set, no @workflow → HTTP API dispatch + wait_job
- standalone: no Windmill env → execute function body directly
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: skip no_main_func detection for WAC v2 scripts in TS and Python parsers
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: prevent empty/noop dispatch causing infinite requeue loop
- Validate steps.len() > 0 in WAC dispatch handler (issue 3)
- Replace noop StepSuspend throw with never-resolving promise so it
can't reach the backend as an empty dispatch (issue 4)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: Python task wrapper now converts positional args to kwargs in v2 mode
Previously only **kwargs were passed to _next_step(), silently dropping
positional arguments. Extract shared _merge_args() helper used by both
v1 and v2 paths.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: replace unwrap() with proper error propagation in WAC arg serialization
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: add workspace_id filter to v2_job queries in WAC dispatch
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: prevent race condition in WAC child dispatch
Restructure dispatch to save checkpoint + suspend parent + seed child
checkpoints in a single transaction BEFORE pushing child jobs. This
ensures a fast child can't complete before the parent is suspended.
Also wrap InlineCheckpoint save + running reset in a transaction to
prevent corrupted state on crash.
Use ULID for pre-generated child job IDs (consistent with rest of API).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: include step key and child job ID in WAC error propagation
Move step_key lookup before the success check so failed child errors
include which task failed, the child job ID, and the original error.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* docs: document WAC determinism contract and step dispatch semantics
- Document that workflow functions must be deterministic across replays
- Document that WacStepDispatch.script/args are metadata, not dispatch targets
- Add comments on counter-based key allocation
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: tighten WAC v2 detection to reduce false positives
Replace naive substring matching with line-aware checks that skip
comments and look for specific patterns:
- TS: import from "windmill-client" containing workflow/task
- Python: @workflow and @task decorators with wmill import
Extracted shared helpers in wac_executor.rs used by both executors.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: show failed steps in WacGraph when workflow completes with errors
When flowDone is true and a pending step isn't in completedSteps,
mark it as 'failed' instead of 'running'. The failed state CSS and
XCircle icon were already defined but never triggered.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: unsuspend and fail parent when WAC child push fails
Previously if a child push failed mid-batch, the parent remained
suspended with suspend = num_steps but fewer children, hanging until
the 14-day timeout. Now the push loop catches errors and unsuspends
the parent before returning the error.
Also adds source hash validation: if the script content changes between
replays, the job fails with a clear error instead of silently feeding
stale checkpoint data into wrong steps.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: clear suspend_until when unsuspending WAC parent
Set suspend_until = NULL alongside suspend = 0 in both the child
failure and all-children-complete paths, so the parent doesn't rely
on subtle pull query invariants to be re-picked-up.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* test: add exhaustive edge case tests for WAC v2 SDK
fix: make TS task wrapper non-async to fix unawaited task flush
The async wrapper caused microtask-based thenable auto-resolution that
fired .then() and threw StepSuspend before _flushPending() could capture
unawaited steps — making the flush mechanism completely broken. Now the
thenable is returned directly without async wrapping. Backward compatible
with v1 (all code paths still return awaitables).
Tests added (59 TS + 66 Python) covering: full sequential lifecycle,
step after parallel, parallel after parallel, conditional on step result,
empty/single-task workflows, 10+ steps, falsy value preservation, inline
steps, mixed step/task, unawaited flush, child mode with parallel,
key determinism, large parallel groups, and complex mixed patterns.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: atomic checkpoint updates to prevent parallel child race condition
Replace read-modify-write pattern in handle_wac_child_completion with
atomic SQL operations:
- completed_steps merged via jsonb_set(... || jsonb_build_object(...))
so concurrent children on different workers don't overwrite each other
- suspend counter decremented atomically with RETURNING to determine
"all done" condition (instead of checking completed_steps in memory)
- suspend_until cleared in the same atomic decrement statement
Before this fix, two parallel children completing simultaneously could
both load the same checkpoint, each add their step, and save — the
second write would overwrite the first, silently losing a child result
and leaving the parent suspended forever.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: cancel already-pushed children on partial WAC dispatch failure
When pushing child jobs sequentially, if pushing child N fails, children
1..N-1 are already running. Previously the error handler only unsuspended
the parent, leaving orphaned children that would complete and corrupt the
checkpoint state (decrementing suspend on an already-unsuspended parent,
potentially causing duplicate step execution on re-run).
Now on partial failure:
1. Cancel all already-pushed children (prevents them from completing
and corrupting checkpoint state)
2. Clear pending_steps from checkpoint (so parent doesn't think
children are outstanding on re-run)
3. Then unsuspend parent (so the error propagates)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: skip WAC duration write and child check for non-WAC parents
The duration write to workflow_as_code_status was running for every
non-flow child with a parent (error handlers, success handlers,
run_script children), even though it was only intended for WAC jobs.
Add WHERE workflow_as_code_status IS NOT NULL to skip non-WAC parents
entirely. Piggyback RETURNING pending_steps.job_ids on the same query
so WAC v2 child completion needs zero extra DB round-trips on the
success path.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: seed child checkpoint in same transaction as push
The child checkpoint insert was happening before the child job was
pushed, violating the FK constraint on v2_job_status. Move it into
the push transaction so the job row exists and the child can't be
picked up before its checkpoint is ready.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: set running=false when WAC parent suspends for child dispatch
The parent job kept running=true after suspending, so workers wouldn't
pick it up when children completed and suspend reached 0. The parent
only advanced when the zombie job detector reset it (~90s). Now the
dispatch suspend sets running=false so the parent is immediately
eligible for pickup.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: WAC parent suspend/unsuspend lifecycle
Keep running=true when suspending the parent so the normal pull query
(WHERE running=false) never picks it up. Keep suspend_until non-null
when decrementing suspend to 0 so the suspended pull query
(WHERE suspend_until IS NOT NULL AND suspend<=0) picks it up.
Previously: setting running=false caused infinite restart loops because
the normal pull query has no suspend check and would immediately re-pick
the parent. Clearing suspend_until on the last child prevented the
suspended pull from ever seeing it, requiring the 90s zombie detector.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* feat: add approval primitive, flow child completion, timeline fixes for WAC v2
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* feat: add error propagation, task options, sleep, and parallel for WAC v2
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* test: fix python SDK tests to use name-based keys and add new test coverage
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: address WAC v2 review findings (sleep timing, error marker, atomicity)
- Fix sleep using suspend=1 instead of 0 to enforce actual delay
- Add approval/sleep resume injection to Python executor
- Fix TS SDK concurrency_limit mapping (was reading wrong property)
- Namespace error marker as __wmill_error to avoid user data collision
- Wrap child completion SQL in transaction for atomicity
- Decrement suspend even when step key is missing (prevents hang)
- Expand TASK_RE to handle export const, let, var, generics
- Validate step key uniqueness before dispatch
- Log warning on checkpoint deserialization failure
- Remove unimplemented delete_after_use from SDKs
- Add TaskError exception class to Python SDK with diagnostic context
- Fix extra positional args handling and add functools.wraps
- Improve getParamNames to handle typed/destructured params
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* sqlx
* sqlx
* test: add WAC v1 e2e integration tests for TS and Python
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: revert fake test versions in typescript-client
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* refactor: remove unused WacGraph component and strip wacToFlow to isWorkflowAsCode
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* refactor: extract shared approval/sleep resume logic into wac_executor
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
|
||
|
|
5d79f33590 |
Final Svelte 5 migration (#8211)
* Remove $$props.field usage * Rename slots to ensure no hyphen * _props * _trigger * OnSelectedIteration type correct capitalization * rename _content * Remove afterUpdate * Migrate everything to svelte 5 * array bind * Fix popover * type never * nit fixes * Fixed many trivial errors * onClick * Fix errors * use let: * nit typing * fix: wrap state_referenced_locally vars with untrack() Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * Add untrack import * Fix all syntax errors due to untrack migration * Fix undefined errors * Fix more undefined errors * untrack(() => initialOpen) * svelte-ignore * Fix state_descriptors_fixed error in Chart.svelte Use $state.snapshot() to pass plain copies of data/options to Chart.js instead of $state proxies. Chart.js's listenArrayEvents tries to define property descriptors on data arrays, which Svelte 5 proxies reject. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * nit typing * Merge issue * Fix "path is not set" error in resource picker / editor * Fix InputTransformForm error when rerunning some flows * fix npm run check --------- Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com> |
||
|
|
5f0ef936d1 | feat: add sandbox annotations, volume mounts, for AI sandbox starting with claude (#8058) | ||
|
|
c9c3baecb3 |
add context menu with delete option to preprocessor nodes (#8223)
* fix: add context menu with delete option to preprocessor nodes Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * feat: add delete styling and shortcuts to right-click context menu Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com> |
||
|
|
c0c9388415 |
feat: add move, delete, and duplicate to flow node context menu (#8050)
* feat: add context menu, multi-select actions, and keyboard shortcuts to flow editor Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: address review feedback on context menu PR - Revert accidental static import of @scalar/openapi-parser (keep lazy-loaded) - Restore [data-context-menu] in portalDivs for clickOutside compatibility - Make noteDisabled reactive ($derived) in ModuleNode - Use platform-aware shortcut hint (⌫ on Mac, Del on Windows/Linux) - Optimize resolveSelectedModuleIds with single-pass ancestor map Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: address additional review feedback on flow context menu PR - Use $derived.by instead of $derived for computed bounds in SelectionBoundingBox - Remove redundant structuredClone wrappers around $state.snapshot - Add null guard for originalModules/targetModules in move handler - Add upper-bound guard (n < 10000) to copyId loop - Fix fragile toggle comparison in moveManager with full array equality Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com> |