mirror of
https://github.com/windmill-labs/windmill.git
synced 2026-10-24 00:03:53 +00:00
338c4e921dc3185d886c8b040f253285adf20efb
1204
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
338c4e921d |
feat: operators get AI sessions (#11443)
* feat: operators get AI sessions `prefersSessionHandoff` stops taking the role, so every AI entry point an operator can reach — Ask AI, the home composer, Open in session, the flow editor's hand-off, the raw-app template picker — opens a session for them like anyone else. The sessions page drops its refusal, and the layout stops keeping them on the docked chat. In the sidebar they now get the Workspace/AI Sessions switch and session mode, and lose the Ask AI entry that stood in for them, since the pane behind it is no longer the one they are sent to. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * feat: operators get run-oriented examples in the home composer Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * docs: note builder_flows in the operator composer examples comment Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * feat: gate session tools and editors on operator rights Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * feat: keep operator AI sessions behind a browser opt-in Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * fix: keep flows refused in the prompt for operators without builder rights Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * refactor: decide every frontend edit check through one editRights module Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * fix: let admins who are also operators open session editors, as drafts.rs does Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * fix: mirror drafts.rs exactly in roleCanDraft and correct the edit-rights docs Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com> |
||
|
|
c52ba2fd30 |
feat: agent nits: multi-select, memory-off notice, agent step label (#11622)
* feat: agent nits: multi-select, memory-off notice, agent step label Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix: say saved, not renamed, on a new agent's first deploy Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix: run the agent page form on cmd+enter, select agents by keyboard Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * test: pin the agent step label Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
a85d0b76cc |
feat: add Pi template to the AI sandbox picker (#11619)
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
41162b270c |
feat: one page header across routes, and one sidebar for operators and developers (#11310)
* 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> * 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> * 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> * 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> * 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: 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 |
||
|
|
b2ef8478c6 |
vertically center flow step header actions (#11601)
Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com> |
||
|
|
046df9e44d |
feat: run AI decision steps on OpenAI's Decisions API (#11590)
* feat: run AI decision steps on OpenAI's Decisions API Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * fix: fail refused openai decisions and keep structured criteria Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * fix: send only user message lists as openai decision messages Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * fix: omit descriptions the openai decision step does not have Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * fix: pass only exact openai user messages through as decision input Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * fix: check the payload of openai decision message parts Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com> |
||
|
|
866179730a |
fix: keep run status buttons from selecting the flow input node (#11579)
Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com> |
||
|
|
c75113a235 |
capitalize AI Decision labels to match AI Agent (#11583)
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
9d55a9381d |
add customUi prop to hide save to workspace on flow steps (#11566)
Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com> |
||
|
|
8c74f75de3 |
fix: simplify the run page AI card to a prompt and a chat button (#11561)
* fix: drop the add a prompt for AI button from the run page * fix: open the run page in the session preview from a plain chat button * fix: rename additional prompt for AI to AI prompt * fix: put the run page chat button beside advanced when no AI prompt |
||
|
|
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> |
||
|
|
c962d3766b |
fix: evaluate field conditions and step test inputs in QuickJS (#11487)
* fix: evaluate field conditions and step test inputs in QuickJS Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix: answer single-quoted field conditions without loading the engine Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix: bound expression recursion and ignore leading blank space Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
e7fc1b2e2e |
feat: restricted job tokens per script and flow (#11484)
* feat: restricted job tokens (job_token_scopes on scripts and flows) Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * fix: admit flow-run reads, skip dedicated workers, gate on worker version Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * fix: keep restricted jobs off flow runners, preserve scopes on rename and promotion Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * fix: keep restricted jobs off every dedicated handoff, confine progress flow id Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * fix: exclude restricted runnables from dedicated worker startup Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * fix: gate restrictions on the release after 1.821.0 Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * fix: store per-job scopes on job_perms instead of v2_job, pin inline runs to the checked version Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * feat: step-level job_token_scopes for flow steps and agent tools Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014FHGE3ynoAu6yrgeg4kLwL * fix: fail closed on perms read errors, refuse restricted queue imports, gate step scopes in previews Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014FHGE3ynoAu6yrgeg4kLwL * fix: carry a job's scopes on its completion so a re-run keeps the caller's cap Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014FHGE3ynoAu6yrgeg4kLwL * fix: carry a zombie job's scopes into its completion Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014FHGE3ynoAu6yrgeg4kLwL * fix: leave a zombie for the next sweep when its scopes cannot be read Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014FHGE3ynoAu6yrgeg4kLwL * docs: correct the QueuedJobV2 completion comment Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014FHGE3ynoAu6yrgeg4kLwL * fix: validate step scopes in batch flows, fail closed on unvalidated step scopes Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014FHGE3ynoAu6yrgeg4kLwL * fix: refuse flows with step or tool restrictions at push while an older worker is live Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014FHGE3ynoAu6yrgeg4kLwL * fix: apply the step-scope worker gate to flow restarts Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014FHGE3ynoAu6yrgeg4kLwL * fix: list the job token toggle with the other step and flow settings Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014FHGE3ynoAu6yrgeg4kLwL * chore: pin the EE companion merged with EE main Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014FHGE3ynoAu6yrgeg4kLwL * perf: skip scope lookups for unrestricted jobs; list job token setting last Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014FHGE3ynoAu6yrgeg4kLwL * style: rustfmt scopes tests Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014FHGE3ynoAu6yrgeg4kLwL * fix: confine restricted job tokens to their own run lineage; drop remaining extra lookups Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014FHGE3ynoAu6yrgeg4kLwL * chore: update ee-repo-ref to 259ad3bfeef5285ba80eedc86309b11dca001220 This commit updates the EE repository reference after PR #843 was merged in windmill-ee-private. Previous ee-repo-ref: 2b77c0225dca441235daf7bf0a06ba968df0c927 New ee-repo-ref: 259ad3bfeef5285ba80eedc86309b11dca001220 Automated by sync-ee-ref workflow. --------- Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Co-authored-by: windmill-internal-app[bot] <windmill-internal-app[bot]@users.noreply.github.com> |
||
|
|
e952298f84 |
feat: replace the AI input filling toggle with an additional prompt (#11501)
* feat: replace the AI input filling toggle with an additional prompt for AI * feat: pass the additional prompt for AI to MCP clients and shared AI guidance * feat: shrink the run page AI card to a button and a collapsed prompt * fix: offer writers a way to add a prompt for AI from the run page |
||
|
|
f2393e5b24 |
keep flow priority input inline with its toggle on wide screens (#11500)
Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com> |
||
|
|
88d0cd00e5 |
fix: restore the save to workspace button on inline flow steps (#11469)
* fix: restore the save to workspace button on inline flow steps Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * fix: make the inline step save to workspace button icon only Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com> |
||
|
|
b10f83c763 |
feat(sessions): show an item's deployed page in the preview panel (#11458)
* feat(sessions): show an item's deployed page in the preview panel The preview panel showed an item's editor and nothing else. It now shows the deployed page too, as a tab of its own. **Two sides, two tabs.** The editor and the deployed page are different things to look at, so `isItemTabFor` keys on the side rather than the item: asking for a side already open focuses it, asking for the other opens it alongside. Two editors for one item still cannot coexist — they would race its single (kind, path) cell — but an editor beside a viewer is safe, since the viewer reads the deployed version over the API and holds no cell. The tab breadcrumb keeps re-pointing in place; `Exit & see details` and the detail page's `Edit` open the other side instead of consuming the one you are on. A tab's label carries `(edit)` when it is the editor side. **The detail pages moved out of their routes.** `/scripts/get` and `/flows/get` are now thin wrappers over `ScriptDetail` and `FlowDetail`, which the panel renders too. Everything they reach — drawers, triggers, saved inputs — is scoped to the viewer's workspace through `setOperatingWorkspace`, and every navigation they attempt is caught by `interceptNav` and turned into a move inside the panel, so nothing takes the browser out of the session. A plain click is intercepted; ⌘-click and middle-click still open a real tab, which is why the pages keep their `href`s. **The picker opens what exists.** A row opens the deployed page, or the editor when nothing is deployed there, and carries a Draft / Draft only badge in the review dock's words. `WorkspaceItem` gained `draftOnly` and `hasDraft` from the listers, which already returned both; deploys now invalidate the picker cache through `itemDeployed`, so a just-deployed item stops reading as a draft. Rows also carry a hover Edit action, reachable from the keyboard with the pick modifier. `open_preview` gained a `mode`, narrowed out of the advertised schema for a session that cannot write drafts and re-checked per path in the handler, where a refusal reports "couldn't check" apart from "denied". The mode is resolved before those checks, so a call that omits it is gated as the editor it will become. Alongside, the workspace a detail page acts on is now the one it is showing rather than the one the browser is navigated to: `MoveDrawer`, `toggleWorkspaceErrorHandler` and the pages' own permission gates read the operating workspace and its acting user, and `RunForm` mints a password argument's ephemeral variable there too — in a fork session all of these previously answered for the parent. `InWorkspaceAppViewer` hands the app's `ctx` user down as a prop instead of writing the global `userStore`, which from a session tab was re-pointing every permission check on the page. Fixes found on the way: `DetailPageLayout` claimed `h-screen` inside a panel that is not the viewport; Edit on a historical script version dropped the version from the intercepted click; the Run button stayed spinning after a run that left the page mounted; and the window-level run shortcut fired from a collapsed panel and from keys another handler had already claimed. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix(sessions): historical edits, stale not-found, shared edit rights, tab labels Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * fix(sessions): keep deployed-page links and workspace reads in the session Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * fix(sessions): scope detail hrefs to the session, re-point the viewer's own tab Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * fix(sessions): keep a previewed raw app's route out of the session URL Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * fix(sessions): resolve edit-in-fork against the session workspace Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * fix(sessions): read advanced run tags from the session workspace Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * fix(sessions): fork from the session workspace, star only navigation items Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * fix(sessions): mount only the side a preview tab shows Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * fix(sessions): address CI review round 1 findings Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * fix(sessions): route links in a deployed page's drawers through the panel Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * fix(sessions): tell the chat which deployed page the panel shows Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * fix(sessions): only a 404 reads as an undeployed raw app Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * fix(sessions): scope the unparseable-JSON run gate to the form Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * fix(sessions): a flow deleted from the panel stays in its tab Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * fix(sessions): the picker's edit shortcut works on the current row Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * fix(sessions): load-error toasts say what failed Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * fix(sessions): keep an oversized invalid JSON editor in its form's run gate Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * revert: keep main's draft_only description in openapi.yaml Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com> |
||
|
|
8c7dcbbda5 |
feat: agents as a standalone kind with home listing, detail and editor pages (#11332)
* feat: list agents on the home page and create them from the new menu Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * fix: keep runnables out of the agents view and anchor a new agent once saved Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * fix: autosave a new agent's first edit and list agents past one page Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * feat: add agent detail and editor pages Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * fix: explain when an agent cannot be run and drop the broken agent move Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * fix: keep query params and a unique path when creating an agent Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * fix: lead the home list with agents and keep rows while the agent view loads Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * fix: treat a loading agent as undeployed when leaving the editor page Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * feat: agent detail page config panel, run page on form runs, chat badge Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * feat: agent configuration modal and draft paths like other new items Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * fix: keep a new agent draft-free until the first input, land agents with runnables Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * feat: place AI agent after apps in the new menu and describe chat and flow use Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * feat: new agents start with managed memory, editor form says how to turn it off Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * fix: clearer managed memory hint in the agent editor form Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * refactor: share the agent editor's pane notice as a PaneNotice component Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * fix: name a new agent after a path no resource holds Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * fix: tell repeated tool names apart and hide permissions on draft-only agents Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * feat: agent configuration beside the model in the chat composer and above the form Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * feat: center the agent run form, configuration beside its Run button Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * fix: icon-only agent configuration button beside Run Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * feat: agents run on behalf of their deployer through a run-by-path endpoint Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * feat: agents keep their run-as identity in their value, preserved by the CLI The identity an agent runs as lives in `value.on_behalf_of` instead of a column. Every write of an agent resolves it server-side as a flow's is: the writer's own, unless an admin or wm_deployers member asks to keep it, and a folder default on create. Retyping a resource into an agent resolves its value the same way. Export leaves it out; the run endpoint reads it and drops it from the step's inputs. The CLI follows the app model: a pushed agent never takes its identity from the tracked file, an unchanged agent compares equal to the deployed one, and an admin or deployer push claims the deployed identity back. The owner-change pre-check lists agents. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * feat: deploying an agent draft from review keeps its deployed identity As for an app: an agent draft carries no identity, so the review page claims the deployed one back, which the backend honours for an admin or wm_deployers member. The draft diff leaves the deployed identity out, since a draft never holds one. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * feat: deploying an agent to another workspace offers the run-as choice An agent deployed to prod/staging, merged from a fork or promoted with `wmill workspace merge` gets the same identity choice as a flow or an app: the target's current one, the deployer, or a picked user, sent as a principal the way a trigger's is. The source workspace's principal is never copied, and a difference in identity alone is not a change in the workspace compare or its diff. The frontend consumes the published windmill-utils-internal, so its deploy provider carries the same rewrite until that version ships. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * fix: agent identity on fork, agent-scoped job reads, and the run license gate A fork re-points an agent's identity at its creator when they may not preserve someone else's, and at the creator when it names nobody in the fork, as it does an app's. A token scoped to `jobs:run:agents:<path>` reads back the runs it starts, chat turns included. The agent run endpoint checks the enterprise license like every other run entrypoint. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * fix: a CLI push decides agent identity handling by the tracked file's type An agent retyped into another resource by a push kept neither its value's `on_behalf_of` as the file stated it nor clear of the old agent's identity. The file's type now decides, and only a deployed agent's identity is claimed back. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * refactor: agents run as the caller, with a note on what a shared one needs Drops the agent run-as identity: its storage in the agent value, the backfill, the resolution on every write, and its handling in export, the CLI, draft and cross-workspace deploys, forks and the workspace compare. The run endpoint runs as the caller, so an operator or reader runs an agent with their own access. The editor tells the author of a folder agent that anyone running it needs access to its AI resource and to what its tools use. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * docs: agent editor comments describe runs as the caller Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * refactor: agent editor pane notes use Alert Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * refactor: agent editor pane notes render as Alert Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * fix: agent editor notes as regular Alerts, not banners Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * feat: agent path as its own editor level, and evals on the agent page The path leaves the agent form: the editor dialog opens it as a level, as it does evals, and the editor page in a drawer. The agent page gains Evals, in a dialog. The page supplies the run form, keeping it out of the editor the flow editor reaches. The draft edit gate no longer throws when a focused, changed field is removed: the `change` that removal fires lands mid-teardown, so the gate opens just after instead. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * feat: agent settings as the resource editor's header fields, behind a cog The agent's own settings (path, labels, workspace specific, description) open from a cog as the flow and script editors' do, laid out as the top of the resource editor. The folder note is gone. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * feat: agent settings fields and cog, completing the rename Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * feat: evals open as a dialog over the agent editor page The editor page opens an agent's evals over itself, as the agent page does, with the unsaved edits offered to a run; the editor dialog keeps evals as a level of its own. The two pages share the dialog. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * fix: the unreachable model provider note reads like the unreachable agent one Same warning level and wording as the note above it, with the path inline rather than in parentheses that lost their spaces. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * fix: the unreachable model provider note offers editing the agent too Editing the agent to use a provider the reader can access is often the simpler way out; offered when the reader can write the agent, with Unlink and asking for access. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * fix: provider note lists asking for access as its own option Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * fix: shorter provider note, without the header's buttons repeated Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * fix: evals only for those who can edit the agent Evaluating builds datasets and runs against the agent, which is authoring: the agent page and the editor offer it only with write access to the agent. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * fix: agent page actions ordered as the script and flow pages The menu leads and Edit comes last, as DetailPageHeader lays them out. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * fix: the agent editor dialog's levels slide in built on the first visit Warmed, as the evals pane's levels are, so settings and evals are mounted before the first navigation rather than inside its transition. Evals are only in the strip where they can be opened. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * fix: the agent's settings report path errors, and hold nothing a reader can edit The path field reads its error back, so it shows it and keeps deploy blocked on it. Labels are shown rather than editable without write access. Evals wait for the load to know they can be opened, and the page layout builds no levels it never shows. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * refactor: one builder for an agent's run flow, and the agent page on the shared header The run endpoint and evals build the agent's one-step flow through the same function. The agent page uses DetailPageHeader, whose error handler, tag and trigger context are now optional, and whose menu items keep their disabled state. The home row and the page share the agent's menu and delete. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * fix: the agent page's menu is built from its current path Deploy settings are the workspace's, so they load once and the menu is derived from them rather than fetched per path, where a superseded fetch could land after a navigation. The shared run-flow builder lives with agent runs rather than evals. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * fix: the scoped-read comment names the run-flow builder as it is Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com> |
||
|
|
ca44043e12 |
feat: let operators compose flows when the workspace grants the right (#11228)
* feat: let a workspace withdraw operator schedule and trigger writes Operators can create, edit and delete schedules and triggers today through the API, CLI and MCP, while the operator_settings flags beside them only hide those pages. An admin who wants operators to see what is scheduled without letting them change it cannot express that. Add manage_schedules and manage_triggers as enforced settings, gated at the schedule handlers and at the generic TriggerCrud routes so every trigger kind is covered by one check. They name capabilities operators already hold, so they are granted unless withdrawn, and absence has to mean "never configured" rather than a value. The read coalesces to true; the update endpoint merges into the stored jsonb with the two fields as Option<bool>, so an omitted key keeps what is stored. operator_settings is git-synced as a whole object, so a settings file written before these keys existed reaches the endpoint on every pull, and a serde or SQL default of either polarity would turn that pull into a silent withdrawal or restoration. The rights are read through a per-process cache, so withdrawing one publishes a notify_event that drops the entry on every replica. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Dsf6VC4MVLisiEoeQkgbr4 * feat: let operators compose flows when the workspace grants the right Adds operator_settings.builder_flows: a workspace setting that lets every operator compose flows out of runnables that already exist. It does not make them authors. The boundary the operator role draws is authoring code and running arbitrary code, and this does not move it: check_flow_is_composition_only walks the value and refuses anything carrying code, including the shapes an obvious walk misses (code hoisted into a flow_node, an AI agent step's tools, and a linked ai_agent resource whose tool list is resolved at run time). What the walk cannot settle it returns for the caller to authorize under RLS: the worker tags the steps pin, every runnable they reference, and the (path, hash) of every version-pinned step. Composing a path is enough to run it and to run it as whoever it runs as, since the worker resolves a step's path with the root DB handle and adopts that runnable's on_behalf_of. A pinned hash needs its own check because dispatch ignores the path beside it. The gate runs on every write and on both request-supplied-value paths, flow preview and flow dependencies, or either becomes the way to run what the write path refuses. Operators of a builder workspace consume a full author seat; the EE companion carries the counting. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Dsf6VC4MVLisiEoeQkgbr4 * feat: enforce operator write rights on the router and in the UI Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: close the capture gap and gate the trigger editors' write actions Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: gate acl writes and the native trigger drawer behind manage rights Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: refuse operator writes with 403 and gate sharing at the drawer Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * perf: resolve identity in the operator write gate only for writes Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: gate the suspended-jobs actions and stop the route check refusing reads Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: explain the empty-state create button when operator writes are withdrawn Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: audit operator settings changes and fold path writes into native rows Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * fix: open locked editors read-only and group the operator settings Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * fix: skip email and azure lookups on editor open while triggers are locked Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * docs: state each operator-rights rationale once in comments Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * fix: address CI review findings on operator write rights Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * fix: keep capture move gated and skip it in the builders while locked Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * fix: refuse builder-rights violations with 403 so operators stay logged in Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * refactor: trim duplication in the operator builder gates Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * fix: hide build app from builder operators on the flow page Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * chore: point at the companion EE PR merged with EE main Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * fix: keep a builder's drafts list loading past drafts they cannot write Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * fix: hide saved agents from builder operators in the step picker Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * chore: note the inlined seat rule and drop orphaned sqlx entries Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * fix: stop a builder's step test from logging them out Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * fix: refuse a builder's dependency job on a path it cannot write Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * fix: keep builders from adding dynamic dropdown code to a flow A flow's dropdown code runs as whoever loads its form, so a builder may keep or drop the code stored on the flow it updates, never add or change it. The builder's editor hides the dropdown types and code, and previews options through the deployed flow; the inline dropdown refusal is a 403 so it no longer logs operators out. Also trims rationale comments repeated across sites. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * fix: show why saving operator settings failed The seat-cap refusal on granting builder rights explains what to do; the toast now carries the server's message instead of a generic failure. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * fix: check builder flow drafts like deploys and treat dropdown code as code A developer who loads a builder's flow draft in the editor runs its dynamic dropdown code as themselves, so a builder's draft now passes the same checks as a deploy. Dropdown code is refused like step code rather than kept or dropped, which also removes the exact-match comparison that refused builders over whitespace. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * fix: bill a builder workspace's operators as developers on cloud The cloud seat count behind the Premium page, the sidebar usage and the fork cap still weighed every operator at half a seat, while the builder right makes them authors. The out-of-repo invoicing job must follow the same rule. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * fix: check a builder's flow draft as it will be stored Draft storage strips NUL escapes after the builder check, so a key ending in one (value\u0000, x-windmill-dyn-select-code\u0000) passed the check as an unknown field and was stored under its plain name. The check now reads the sanitized text. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * fix: list a builder's flow drafts and hide hub imports from builders A builder's undeployed flows now appear in the home list, the flow list and the folder counts. Hub project imports and templates bring scripts and apps along, so builders are no longer offered them. The docs record builders' JavaScript expressions as an accepted risk. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * fix: keep the stored builder right when a settings payload omits it A git-synced settings file written before the key existed withdrew the right on every push. builder_flows now follows the manage_* rights: an omitted key leaves the stored value, and the CLI does not count it as a difference. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * fix: word builder refusals by what the flow contains, test the tag refusal A builder refused on a developer's flow never changed its code, so the refusals now describe the flow ("has inline code, so only a developer can edit this flow") rather than an authoring attempt. The grant confirmation uses the neutral dialog: granting changes billing but destroys nothing. The integration test pins the refusal of a worker tag the workspace cannot use. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * fix: read builder rights from the operating workspace, gate the flow page's audit logs entry Builder rights now come from useOperatorBuilderFlows(), next to the schedule and trigger locks, so an editor embedded for another workspace answers about that workspace; the legacy AI chat, one instance for the whole app, reads the navigation workspace. The flow page's Audit logs entry follows the operator audit_logs setting now that builders open that menu. Operator settings reset every value on load, null settings included, so nothing carries over from the previous workspace. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * fix: pick a dynamic dropdown's code source by the operating user's role The flow input editor, the flow test panel and the flow chat send the dropdown request to the operating workspace, so they now also choose inline versus deployed code by the role held there, through useOperatingUser(), instead of the navigation workspace's. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * chore: update ee-repo-ref to 40ac1c5f8cbce3843b582d9b392d3f3cc7eca3e6 This commit updates the EE repository reference after PR #815 was merged in windmill-ee-private. Previous ee-repo-ref: 31c9e66884b8ca805b20bbfad41fc428fbedbc0e New ee-repo-ref: 40ac1c5f8cbce3843b582d9b392d3f3cc7eca3e6 Automated by sync-ee-ref workflow. --------- Co-authored-by: Claude Opus 5 <noreply@anthropic.com> Co-authored-by: windmill-internal-app[bot] <windmill-internal-app[bot]@users.noreply.github.com> |
||
|
|
077709b914 |
feat: rename agent memory options to On and Legacy, explain each (#11442)
* feat: rename agent memory options to On and Legacy, explain each Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix: default the chat agent example to On memory and align the schema copy Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * feat: offer Legacy memory only to steps that hold it, explain under the toggle Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix: keep the off memory hint true on the saved-agent editor Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * feat: state the 128k fallback in the context window description Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
c1b59f70dd |
feat(ai-agent): add compaction memory that summarizes older context (#10928)
* feat(ai-agent): add autocompacted memory that summarizes older context Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01ViJyjUmidDYV2m6ifQdLeH * fix(ai-agent): compact on final-answer turns and count what a turn appended Address the pre-push review findings on the compaction path: - A turn the model answers without a tool call left the agent loop on its first iteration, so a chat-shaped step never compacted and reloaded the whole conversation on every later turn. Compaction now also runs after the loop. - The trigger measured only the last request, so a single large tool result could carry the next one past the window without ever crossing 80%. - The summarization call re-sent the usage-tracking request shape on endpoints the loop had already learned to drop it for. - The flat 8000-token summary reserve swallowed the whole target on a small context window, leaving one message in the tail and summarizing the rest. - A response cut off inside the <analysis> scratchpad was accepted as a summary. - The chat-mode memory default was a shared object the step form edited in place. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01ViJyjUmidDYV2m6ifQdLeH * fix(ai-agent): keep Anthropic prompt counts and compact once per response Address the first CI review round on the compaction path: - Anthropic's streaming parser dropped `message_start`, the only event carrying the prompt-side counts, so a native Anthropic run reported no input tokens at all and compaction fell back to a character estimate. - A loop that exits without issuing another request — a structured-output turn does — reached the post-loop pass still holding the previous measurement and compacted a second time, or retried a failure with nothing changed. - The summarization call inherited the step's `max_completion_tokens`; a low one truncates the summary inside its scratchpad, which counts as a failure and disables compaction after three of them. - A fired trigger that found nothing to summarize said nothing. - Memory already over the window — a lowered `context_window`, or a step moved over from `auto` — had no way back, since compaction only ran after an accepted request. It now also runs once before the first one. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01ViJyjUmidDYV2m6ifQdLeH * fix(ai-agent): state the summary's own completion cap and drop the pre-flight pass - The summarization call asked for no completion cap at all, which is "uncapped" only on the OpenAI-shaped providers: Anthropic substitutes 64000, over several Claude models' output ceiling, and Bedrock leaves the model's own small default, short enough to cut the response off inside its scratchpad. It now asks for the reserve the split already set aside, raised to the step's cap when that is larger. - Compaction no longer runs before the first request. The fallbacks the loop learns from a rejection are not known that early, so on exactly the endpoints that need them the summarization was malformed by construction: it failed, spent a strike, and the first agent request still carried the oversized conversation. A memory already past the window is repaired on the turn after a request the endpoint accepts, rather than by a pass that cannot succeed there. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01ViJyjUmidDYV2m6ifQdLeH * fix(ai-agent): ask the summary for exactly the room the split reserved The split scales its reserve down on a small window while the request asked for a flat 8000, so the two diverged below an 80k window: on a 4k/8k model the cap alone exceeded the window and every summarization was refused, and on a 20k one a full-length summary could land the conversation back over the trigger and compact its own previous summary on the next response. Both now read one `summary_reserve_tokens`. The call also no longer inherits the step's reasoning effort. Every provider counts thinking against that same budget, so a high-effort model could spend the whole reserve before writing anything and return a summary cut off inside its scratchpad; the compaction prompt asks for an `<analysis>` block, which is the reasoning this call needs. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01ViJyjUmidDYV2m6ifQdLeH * fix(ai-agent): charge the compaction budget for tools and the system prompt The tail budget was the whole target, but a request also carries the system prompt compaction keeps and the tool definitions, which are not in the message list at all. On a small window those are most of it: a tail sized to the full target left the next request back over the trigger, compacting again every response, and the no-usage estimate missed the tool schemas entirely so it could fail to trigger at all. Both now account for them. The reserve also gains a floor. It is the summary's output cap as well as the room the split leaves, and scaled down without one a small window gave a structured nine-section summary a few hundred tokens — truncated inside its scratchpad every time, which is discarded, which switches the mode off after three. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01ViJyjUmidDYV2m6ifQdLeH * fix(ai-agent): count Gemini's tool-use prompt tokens in an agent step's usage Gemini splits a tool-using turn's input across `promptTokenCount` and a disjoint `toolUsePromptTokenCount`, and its thinking apart from `candidatesTokenCount`. The agent step's parser read only the headline fields, so every tool-using turn under-reported both — and the compaction trigger, which runs off the reported prompt, could not see the tool results that grew it. It now goes through the same helpers the proxy path already used. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01ViJyjUmidDYV2m6ifQdLeH * fix(ai-agent): calibrate the compaction estimate against the measured prompt Two rounds running, the finding was "the character estimate cannot see input X" — tool schemas, then S3 attachments, which are short paths in the message list and whole images by the time a provider counts them. Enumerating those is a list that only grows, so the estimate is now scaled to the one number that is ground truth: what the provider charged for the last request. Attachments, tokenizer drift and whatever comes next fall out of that, because the estimate is only ever used relative to itself. Also stop the Gemini helpers turning an absent count into `Some(0)`. Downstream, absent means "fall back to estimating the conversation" while zero reads as an empty prompt and would hold the trigger below its threshold for the whole run. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01ViJyjUmidDYV2m6ifQdLeH * fix(ai-agent): charge attachments what they cost and let a heavy short prefix compact The calibration conserved the conversation's total cost but spread it by character count, so an attachment — a short S3 path in the message list, a whole image or PDF once a provider expands it — was charged to the text messages around it and stayed nearly free in the split. It now carries a nominal cost of its own, which the calibration corrects a residual on rather than the whole gap. The four-message minimum also refused exactly the case that fix is for: an attachment arriving on the first or second turn can pass the trigger before four removable messages exist, and summarizing even one of them saves most of the prompt. A prefix worth a quarter of the window is now enough on its own. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01ViJyjUmidDYV2m6ifQdLeH * fix(ai-agent): never summarize a prefix holding only a previous summary The message-count floor was carrying a second job: a fresh summary sits in a one or two message prefix, so requiring four declined it. The share threshold added last commit admits it, and a summary is reserve-sized by construction — so the post-compaction shape could spend one summarization per response swapping a summary for another the same size, shrinking nothing and losing fidelity each time. A previous summary no longer counts towards that threshold. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01ViJyjUmidDYV2m6ifQdLeH * fix(ai-agent): take the context window from the model and drop the estimate calibration Brings compaction in line with how the AI session does the same job, which had already answered these three questions. - The window is looked up from the model. `MODEL_CONTEXT_WINDOWS` in `windmill-ai/src/model_context.rs` mirrors the session's table in `copilot/modelConfig.ts`, entry for entry and with the same matching rules; each side points at the other, since a model added to one and not the other compacts at two different sizes. A step's `context_window` becomes the override for what the lookup cannot serve, and chat mode writes none. - Provider usage is normalized where the provider's quirk is, not at the consumer. `TokenUsage::with_cache_beside_input` raises `input_tokens` to the whole prompt for Anthropic and Bedrock, which report their cached prefix beside it; the OpenAI shape already counts it inside. `prompt_tokens()` is then just `input_tokens`, rather than inferring the shape from whether a write count is present. - The estimator is no longer calibrated against the measured prompt. The session uses the provider's count when it has one and a chars/4 estimate otherwise, with nothing in between, and a tail sized a little wrong only compacts again a turn later. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01ViJyjUmidDYV2m6ifQdLeH * feat(ai-agent): summarize memory down to what the database can store Without an instance object store, memory is a 100KB database row cut from its oldest message, the summary included, so compaction on a mainstream model never got to keep anything across runs. A step that persists there now runs its post-loop compaction pass against the smaller of the model's window and the cap at chars/4, about 25k tokens: the loop keeps the whole window, and what is written is a summary plus a tail that fits. The run logs when that pass summarizes, and how many messages the write dropped when one still overshoots. The editor's storage warning on the option is removed: nothing exposes the instance storage to it, so it keyed on the workspace S3 setting, which is unrelated to where memory goes. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01ViJyjUmidDYV2m6ifQdLeH * fix(ai-agent): get a complete, billed summary out of every provider Compaction against the real providers turned up four things the stub could not: Gemini and OpenAI's reasoning models think by default and bill it against the same cap the summary must fit in, so the summarization request now asks them for their least (none, low); an OpenAI Responses call that hits max_output_tokens ends in response.incomplete, whose usage the parser dropped, so that summarization went unbilled; a summary that quotes </summary> when it describes its own instruction was cut off at the quote, on the agent step and the AI session alike; and the prefix could end on an unanswered user message, after which the instruction reads as part of that turn (Anthropic merges the two outright). The tail now starts on a user message, and both prompts tell the model the instruction is not part of the conversation. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01ViJyjUmidDYV2m6ifQdLeH * fix(ai-agent): compact down to half the window, on the agent step and the AI session The gap between the 80% trigger and the target is what one compaction buys, and every summarization request carries most of the window. At a 70% target a 128k model summarized about 13k tokens of prefix for a summary of up to 8k, so each ~100k-token request bought a few turns of room before the next one re-summarized the previous summary. At 50% the same request frees about 30k. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01ViJyjUmidDYV2m6ifQdLeH * fix(ai-agent): drop the workspace-S3 memory hint and state the database bound in the tooltip The memory field warned that memory is kept in the database whenever the workspace had no S3 storage. That setting has no bearing on where memory goes: the instance object store decides, and nothing exposes it to the editor. The field's tooltip now describes both memory kinds and states the database bound unconditionally; the run log says what happened. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01ViJyjUmidDYV2m6ifQdLeH * fix(ai-agent): send the summarizer its tool history as text The summarization request carries no tool definitions, and Bedrock's Converse API rejects toolUse/toolResult blocks that arrive without them, so on Bedrock every summarization of a prefix holding a tool call failed silently until the breaker tripped. The prefix's tool calls and results now reach the summarizer rendered as text, on the agent step and in the AI session's compaction, which goes through the same proxy. Also drops the TokenUsage::prompt_tokens accessor, which had become a plain read of the normalized input_tokens, and shortens the context window field's description. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01ViJyjUmidDYV2m6ifQdLeH * fix(ai-agent): price attachments from the provider count, bound storage in bytes, effort per pro model Addresses two Codex rounds and a leftovers audit. - Attachments were priced at a flat 1500 tokens in the split, so a multi-page PDF (tens of thousands of tokens to the provider, a short S3 path in the message list) could be kept in the tail or leave no prefix worth summarizing. They are now priced from the provider's count for the request that carried them, less that request's text, with the 1500 floor where nothing was counted. - The database storage bound measured the provider's token count, but the 100KB cap is bytes and repetitive text packs several characters per token. The persist pass now measures the serialized conversation. - The summarizer forced `low` on every reasoning model, which the pro variants reject (gpt-5-pro takes only high, gpt-5.2-pro starts at medium); they now get no effort. - Dropped the unused prompt_tokens accessor and its orphaned assert, an unused PartialEq, a needlessly public lookup, and fully-qualified Gemini calls; refreshed stale comments and the memory_id schema doc; regenerated the flow schema artifacts. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01ViJyjUmidDYV2m6ifQdLeH * fix(ai-agent): evict a heavy attachment into the summarized prefix, not the tail Pricing attachments from the provider count was not enough on its own: a leading attachment is a user message, and the boundary rule pulled the last unanswered user turn back into the kept tail to keep it with its answer. For a heavy attachment that dragged it into the tail — or, at the front, emptied the prefix — so it was never summarized and rode every request. The boundary now moves forward instead, keeping that user turn and its answer in the summarized prefix. Verified on the running instance: a 25k-token PDF on a 30k window is summarized out on the turn it overflows, and later turns drop from 26k to ~1.5k tokens. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01ViJyjUmidDYV2m6ifQdLeH * fix(ai-agent): keep the forward boundary move off tool results and the prefix start The forward move that keeps an unanswered user turn out of the tail had two edges the third Codex round found: advancing past the user could land the boundary on a tool result (its tool_calls then summarized away, orphaning it), and with no system prompt the summarizable prefix starts at 0, so a trigger firing while the tail estimate fit everything indexed below the start and panicked the task. The forward scan now skips tool-opening boundaries, and the move is guarded above the prefix start. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01ViJyjUmidDYV2m6ifQdLeH * fix(ai-agent): drop the step temperature from the summary request OpenAI's reasoning models (gpt-5-mini, gpt-5.1, gpt-5.2) reject `temperature` alongside any reasoning effort but their own default, so a step configured with a temperature made every summarization fail once the summarizer forced a low effort — history then grew unchecked. The internal summary call now omits the step's temperature: a structured extraction does not need a set one, and omitting it sidesteps each provider's temperature-versus-reasoning rules. Confirmed against the API that low + temperature is refused on those models. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01ViJyjUmidDYV2m6ifQdLeH * fix(ai-agent): compact an oversized loaded memory before the first request Compaction was reactive, taken only after a request the endpoint accepted, so the fallbacks the loop learns from a rejection are known first. But a memory loaded from an earlier run can already exceed this run's window — the step was switched to a smaller model, or a run under a wider one persisted more than fits — and that first request then overflows and fails the run, with every retry reloading the same history and failing again. A pass is now taken up front, off the character estimate, before the first request. It uses the default request shape; an endpoint needing a fallback may reject this one summary, which is non-fatal, and mainstream providers need none. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01ViJyjUmidDYV2m6ifQdLeH * fix(ai-agent): under the storage bound, trigger on the max of bytes and model tokens The storage-bound pass measured only the serialized row size, so an attachment — a few bytes as an S3 path but nearly the whole model context — read as tiny and the pass skipped a compaction the model needed. It now takes the larger of the byte measure and the model's token count, since repetitive text is few tokens but many bytes and an attachment is the reverse; either being over must fire a pass. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01ViJyjUmidDYV2m6ifQdLeH * fix(ai-agent): drop oldest turns when a summary cannot fit the window, as the AI session does An oversized loaded memory (a step switched to a smaller model, or an object-store run that persisted more than a later model's window holds) left a prefix larger than the summarizer's own window, so the summary request overflowed and failed, the memory was untouched, and every retry failed the same way. The AI session handles this by falling back from summarization to dropping the oldest turns down to the target; compaction here now does the same. When a summary cannot run — it failed, the breaker is tripped, or nothing is worth folding — the oldest turns are dropped until the conversation fits and opens on a user message, keeping the newest turn. The next request then always fits. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01ViJyjUmidDYV2m6ifQdLeH * fix(ai-agent): drop whole turns only, keep the storage pass to bytes, refresh the count after a rewrite Three edges the seventh Codex round found, all in the drop-oldest fallback and the storage-bound measure: - drop_oldest_to_fit dropped to any point that freed enough, which could strand a tool result whose tool_calls went with the messages before it. It now drops whole turns only, always landing the boundary on a user message and never splitting the newest turn; a lone turn too big for the window is left whole rather than broken. - The storage-bound pass measured the whole model prompt against the shrunk 25k window, so a large tool roster and the system prompt — neither written to the row — tripped it on a conversation the row easily held. It measures the serialized bytes alone now; the model's own window is enforced by the in-loop passes and the pre-first-request pass, so the persisted size is all this pass is for. - A compaction rewrites the message list, so the provider's count for the request that produced it no longer lines up. The count is now cleared after any pass that rewrites the conversation, so a later pass measures the estimate over the actual messages instead of a stale, larger prompt (which could decline a summary that already fit and then drop it). The step temperature, no longer sent to the summarizer on any path, is dropped from the request struct. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01ViJyjUmidDYV2m6ifQdLeH * fix(ai-agent): measure only the persisted messages against the storage cap Persistence strips the system prompt before writing the memory row, but the storage pass was serializing every message including it, so a large system prompt with a tiny conversation reported far over the storage trigger, and the fallback dropped the one real turn, run after run. The storage measure now serializes only the non-system messages, matching what the row actually holds. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01ViJyjUmidDYV2m6ifQdLeH * fix(ai-agent): run the model-window pass before the storage-bytes pass post-loop A turn the model answered without a tool call broke before the in-loop compaction check, so on database-backed memory its only pass was the storage one, which measures bytes. An attachment fills the model context but is a few bytes in the row, so that turn never compacted and a follow-up could overflow the model. The post-loop now runs a model-window pass first, off the provider's count, then the storage-bytes pass when the row is smaller than the model — both limits enforced for a chat-shaped step, not just the one that happens to bind. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01ViJyjUmidDYV2m6ifQdLeH * fix: simplify agent compaction and preserve execution history * fix: remove unused compaction history setting * fix: preserve answers and recover rejected agent context * refactor: make agent compaction transactional * fix: skip agent summaries that cannot fit retained context * fix: explain skipped agent context compaction * fix: retain recent agent memory when storage compaction cannot fit * fix: start retained agent memory at a user turn * fix: reject unsafe agent memory truncation on storage fallback * docs: clarify agent context window override scope * fix: keep recent turns verbatim when compaction memory outgrows storage Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01ViJyjUmidDYV2m6ifQdLeH * fix: keep the compaction summary out of the agent's answers Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01ViJyjUmidDYV2m6ifQdLeH * fix: shorten the agent context window help text Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01ViJyjUmidDYV2m6ifQdLeH * chore: update ee-repo-ref to 942d4013f36edac1fc9a9addbdb02198db1c7a05 This commit updates the EE repository reference after PR #812 was merged in windmill-ee-private. Previous ee-repo-ref: 8ca1682ce6106ba6ea96894fbe606dac64102eb6 New ee-repo-ref: 942d4013f36edac1fc9a9addbdb02198db1c7a05 Automated by sync-ee-ref workflow. --------- Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com> Co-authored-by: windmill-internal-app[bot] <windmill-internal-app[bot]@users.noreply.github.com> Co-authored-by: Ruben Fiszel <ruben@windmill.dev> |
||
|
|
6064aecdec |
feat: stop cross-origin isolating the raw app editor (#11411)
* feat: stop cross-origin isolating the raw app editor Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0166irwM15U8vZjc58MsU54U * docs: drop stale raw app editor reload comments Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0166irwM15U8vZjc58MsU54U * feat: drop wm_coep from the default raw app embed snippet Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0166irwM15U8vZjc58MsU54U * chore: pin the UI builder that type-checks without cross-origin isolation Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0166irwM15U8vZjc58MsU54U * docs: name the proxy-isolated case behind the remaining isolation checks Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0166irwM15U8vZjc58MsU54U --------- Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com> |
||
|
|
f367eaf6d0 |
feat: run turns in several flow chat conversations at once (#11202)
* feat: run turns in several flow chat conversations at once Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: keep finished turns finished and cached chats current in the flow chat pool Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: attribute a turn's rows by job id as well as sequence Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: count only real stream updates and retry the job-id read Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: keep a chat that holds an unsent draft, and take one back when its first turn is withdrawn Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: ignore a stale running-turn snapshot, keep a withdrawn chat's draft, poll after clean stream ends Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: follow the turn running now when the listing named one already over Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: keep replacement turns and SSE fallback moving * fix: keep replacement turn handoffs active * fix: preserve unread badge line height * fix: settle local fallback handoffs * fix: settle refused turn handoffs * fix: scope turn handoffs to conversation * fix: drop stale turn handoffs * refactor: move the queued message and 409 handling into per-conversation turns Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: address cubic's review of the parallel flow chat turns Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: clear a stale failure on refresh, and tighten the docs and test waits Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: recover running rows past the first page, and drop the failure a re-read disproves Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * refactor: check the running-turn query at compile time, and narrow what a refresh clears Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: settle a failed turn only from an answer that turn wrote Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: settle a failed turn from its own answer, and only while it is still the failure shown Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: drop a failure whose answer arrived even when a newer turn owns the error Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: free an answered failure whatever the turn that started meanwhile is doing Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: drop a rows read that a turn outran, rather than merging it under newer messages Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: drop a rows read whose conversation was left and opened again Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: hand over a file still being read when its composer goes Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: count a drop's routing as work in flight, so its file is handed over too Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: hold the send until every file a conversation is owed has landed Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * refactor: keep a panel mounted per conversation instead of handing its draft over Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: keep the withdrawn chat whose composer was written in, not the empty one Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: keep the chat in front of the reader when both withdrawn composers were written in Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: keep a retry's own run arguments when a turn elsewhere refuses it Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: name panels apart across pools, and read a flow's inputs when its chat is built Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.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 |
||
|
|
1d119e6b25 |
fix: correct the tool controls and name field of a nested AI agent (#11221)
* fix: hide tool controls a nested AI agent cannot use Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * refactor: drop the tool navigation prop an agent tool now implies Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * fix: ask for a tool name on every kind of agent tool Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * fix: keep enabled_tools reachable on a linked nested agent tool Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * docs: name the tool kinds the header's name field actually renders Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * docs: state the tool-name rule without listing the kinds it covers Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5 <noreply@anthropic.com> |
||
|
|
1b74939952 |
feat: support aiagent steps in test_run_step (#11321)
* fix: support aiagent steps in test_run_step Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * fix: offer the agent's tools as a picker in the step run form Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * fix: run a blank tool list as no tools when the step form is bypassed Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com> |
||
|
|
62d0088de5 |
feat: show restart from failed step in run page top bar (#11317)
* feat: show restart from failed step in run page top bar Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * fix: keep failed-step restart button when selection is not restartable Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * feat: add restart link to the failed run status line Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * fix: use the input error color for the progress bar error state Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * feat: mention restarting on a fixed flow version in the error line Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * feat: show a chevron on the restart button when it opens a picker Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * fix: shrink run page top bar buttons so the bar fits on one line Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * fix: target the step that failed the run, not a tolerated failure Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * fix: address review nits on the restart link Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * fix: skip canceled runs and match the restart link label to its text Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com> |
||
|
|
fa0fc24269 |
feat: render a tool's web search result as the session web search card (#11313)
* feat: render a tool's web search result as the session web search card
Any tool whose result is exactly `{ sources: [{ url, title? }], query? }`
now renders as the card the AI session shows for a provider-side web
search, in the agent step trace and in the flow chat. The provider-side
search itself gets the same card on both surfaces: its citations, which
the worker records on the assistant turn that follows, move onto the
search row.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix: keep the trace tool label off the lazily fetched job
The web search card's label read the tool's job, which is only fetched
once the row is expanded, so the query suffix appeared only after the
row had been opened. The shape of the result decides the label; the
job's failure still decides whether the sources or the error show.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix: keep unrenderable sources and tool hostnames out of the search card
A result whose urls the card cannot render — relative, or javascript: —
matched the shape and replaced the tool's own output with an empty list,
so the predicate now requires what the renderer accepts. A tool's sources
can name internal services, so they no longer resolve a favicon through
Google's service; provider-side search results still do. An absent
optional reaches JSON as null from a Python tool, which now reads as
absent rather than rejecting the whole result.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix: name the host when a source carries a blank title
A source whose title is an empty string rendered as a link with no text
at all, the empty title also suppressing the hostname beside it.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
||
|
|
d8aaa73573 |
feat: chat with a saved agent from the agent editor (#11292)
* feat: chat with a saved agent from the agent editor * fix: keep agent chats apart from a same-path flow's conversations * fix: point an agent editor chat's model gap at the agent, not a step * fix: match the memory gate's icon to the chat's empty state |
||
|
|
4cbc944c0b |
perf: keep the sessions page fast with many ai sessions (#11224)
* perf: skip whole-document menu lookup on pointerdown when closed Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * perf: load only a session's own chats in its chat history Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * perf: stop mounting a chat per listed session on the sessions page Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: keep unsent input, init and chat rotation safe from runtime eviction Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * refactor: cap mounted chat panes instead of evicting session runtimes Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * refactor: read only message count and error for sessions without a runtime Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: keep a chat pane mounted while its composer reads attachments Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: hold a session's first send until its chat has been restored Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: queue a second send behind one waiting on the chat restore Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: queue raw-app inline prompts behind a send waiting on the restore Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: keep a chat pane mounted while its send waits on the restore Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: preserve session chat drafts across async updates --------- Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com> |
||
|
|
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> |
||
|
|
3b4e13d1c5 |
fix: key the large root font size on screen width, not window width (#11216)
* fix: key the large root font size on screen width, not window width Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: move the flow preview button offset to the screen-width query Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com> |
||
|
|
a08992834d |
feat: render an AI agent result as its answer, not as raw JSON (#11051)
* feat: render an AI agent result as its answer, not as raw JSON Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: sanitize agent markdown through the shared plugin chain Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * refactor: fold agent stream events incrementally per poll Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: separate the agent meta line from the result toggle group Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * feat: add a transcript view of an agent run's conversation Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * refactor: retire AIAgentLogViewer in favour of the transcript Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * feat: show the partial transcript a max-iterations failure carries Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: move the agent meta line and system prompt below the conversation Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * refactor: show an agent run as what it did, not as a conversation Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * refactor: name the agent run breakdown a trace Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix(ai-agent): label the save-as-agent form fields per the guidelines Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix(ai-agent): reuse the resource form's path and description fields Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix(ai-agent): keep the action tags on a max-iterations failure Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix(ai-agent): keep offline replay inert and the streamed answer to one turn Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix(ai-agent): reset the streamed answer on providers that skip tool_call Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: carry the event type narrowing through the stream parser Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: survive a malformed message rather than take the viewer down Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * refactor: coerce agent messages once at the parse boundary Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * feat: show an agent run as one scroll ending in its output Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: keep every streamed turn instead of dropping the narration Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: share the chat divider and drop the unsafe run auto-scroll Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: give the labelled divider a border colour and the standard pretty icon Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: pad the agent run below its badges as well as above Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * feat: follow a streaming run's pane without moving the page Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * refactor: share the chat's stick-to-bottom mechanics with the agent run Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: keep the answer's citations and end a turn's reasoning with the turn Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * refactor: read the agent stream through the windmill-chat sdk parser Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: show an agent run's thinking instead of falling back to raw json Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: stop a stream the fold cannot use from claiming the run pane Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: identify an agent run by more than the job id the replay withholds Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * refactor: drop the tests and comment lines that were not earning their place Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: stop a streamed turn's text shifting when a tool call closes it Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com> |
||
|
|
e2a91ca2b1 |
feat: flow chat job-backed detail, smooth streaming and answer chrome (#11186)
* feat: flow chat job-backed detail, smooth streaming and answer chrome * chore: document setFlowPath, drop unused chatIdentity, tighten comments * fix: read a nested agent tool's call from its own job * fix: show only the model's arguments on a tool card read from its job * feat: add attachments to the chat sdk message type * refactor: read a flow chat message's files from the message, not its run * fix: keep every job-backed answer when reads finish out of order * refactor: build flow chat tool cards from the conversation row alone * feat: keep the model picker's current choice when a flow chat retry replays its run * fix: export ChatAttachment from the chat sdk entry point * fix: drop a conversation list for the flow path before setFlowPath * fix: return the current listing, not old-path rows, after setFlowPath * fix: treat a listing stale on kind or path as one stale listing * revert: drop setFlowPath and rebuild the chat when the flow path changes * fix: refuse a flow chat retry once any turn ran while it read the run * docs: say where a display message's createdAt comes from * style: drop the rule between New chat and the conversation list |
||
|
|
c4c9677982 |
feat: attach files to a flow chat message (#11185)
* feat: attach files to a flow chat message Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: store chat uploads under windmill_uploads and withdraw refused sends cleanly Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: refuse extra files for a single-file input and keep attachments on retry Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: clean up partial upload batches, withdraw a stopped send once, free retry payloads Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: list a chat conversation only once its run starts and require files where the flow does Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * feat: carry uploaded attachments on the pending chat user message Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: route rich-composer file paste through the attachment lanes and tighten comments Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: keep a stopped turn's files for retry and let an explicit media type win Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: refuse chat attachments sent without text and shorten comments Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: resolve the attachments input from real flow input reads, ignoring loop iteration Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * refactor: read flow input references through one parser for the model and attachments controls Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: withdraw an attachment send stopped after its uploads answered Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: discard uploads when a send is stopped as its attachments are announced Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * docs: keep uploadAttachments' doc comment on uploadAttachments Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * refactor: never delete chat uploads from workspace storage Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * test: pin that a failed upload aborts the rest of its batch Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com> |
||
|
|
a571117f3f |
feat: store mcp tool call, result and reasoning on flow conversation rows (#11176)
* feat: store mcp tool call, result and reasoning on flow conversation rows Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * fix: keep the failure reason and web search citations on tool rows Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * fix: persist a structured answer as its own row and keep reasoning-only rows from closing a turn Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * fix: keep a failed Windmill tool's error on its conversation row Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * fix: let a structured answer row claim its streamed thinking Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * fix: scope a structured answer's claim to its own turn and document the row fields as stored Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * fix: claim a textless assistant row only within the newest turn Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * refactor: store the thinking that led to a tool call on the tool row Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: keep tool calls in stream order and scope a structured answer to its turn Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * feat: store the files a user message carried as object-storage references on its row Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * feat(chat-sdk): read a message's attachments and build their download URL Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * feat(chat-sdk): carry a loaded user message's attachments in AI SDK metadata Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * feat: store the model's call and what it got back on every tool row Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: pass no extras in the orphaned-conversation test's message insert Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix(chat-sdk): keep a stored JSON null tool result instead of the row text Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: label a tool call the turn finished without as not finished Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: keep a structured answer's streamed call out of the did-not-finish label Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: write a turn's conversation rows in order and describe stored tool calls Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: await the image answer row like the agent loop's other rows Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix(chat-sdk): place a row nothing streamed by its sequence, not at the end Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix(chat-sdk): place only tool rows by sequence, keep a closing row last Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix(flow chat): show a failed tool's error, and no Retry on a running or stopped turn A failed tool card showed the row label in place of the error the row now stores. The live tool result now reports failures, so a failed call briefly flagged a running turn as failed; a stopped turn, whose last row is the failed tool or the cancelled flow's failure, offered Retry too. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com> |
||
|
|
c297ed0052 |
feat: managed memory with an inherited or custom memory id per step (#11118)
* feat: split ai agent memory into agent policy, run memory id and step history * fix: scope string memory ids to workspace and flow, keep nested tool history inputs * chore: update sqlx cache for the flow context query * docs: describe memory id scoping as collision-free rather than isolated * chore: regenerate openflow json after merging main * fix: offer no memory id for legacy manual memory, document linked history inputs * fix: seed provided messages from legacy manual memory and hide its note once set * fix: bypass memory when a provided messages expression evaluates to null * fix: require a user message when provided messages are empty * chore: keep the empty messages comment within the line width * docs: name the history inputs wherever linked steps list their flow-local inputs * docs: keep the memory storage path on one line * feat: managed memory with an inherited or custom memory id per step Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * fix: list a custom memory id in the test run form and name where an inherited one comes from Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * fix: keep memory id out of the add-field menu and drop the memory id telemetry Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * fix: keep legacy auto memory without an id working after an untouched redeploy Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * fix: rename step messages to previous_messages and address review Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * style: rewrap comments and docs lines lengthened by the previous_messages rename Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * refactor: read agent memory as either a legacy shape or the current one Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * fix: name the memory setting in ignored-input notes and keep conversions honest Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * fix: keep a legacy memory count unset on open and read a cleared count as off Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * fix: address review on cleared test history and zero-count memory Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * fix: drop flow-local keys from a linked agent resource before interpolating it Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * fix: keep a linked resource's own inputs as fallbacks and note ignored history on image runs Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * fix: restore the linked agent draft tests and log ignored history on every image run Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * fix: resolve the one-of variant from the value when the selected one leaves the list Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * fix: treat zero-count managed memory as off when enabling chat mode and shorten comments Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * fix: stop requiring user_message in the openflow agent contract when previous messages are the prompt Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5 <noreply@anthropic.com> |
||
|
|
4eab995cf7 |
feat: tell test flow conversations from deployed ones and rename a chat (#11179)
* feat: mark test flow conversations apart from deployed ones and allow renaming a chat Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * fix: keep the conversation kind across refreshes and reject NUL titles Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * fix: ignore conversation lists for a kind no longer selected Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: start a fresh conversation listing when the kind changes on a later page Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: refuse sending into a conversation of the other kind Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: refuse cross-kind conversation continuations on the server Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: keep the conversation filter unavailable while an answer runs Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com> |
||
|
|
189793c2e4 |
feat: flow chat model picker on a shared model-settings component (#11187)
* refactor: render the session chat model menu from a shared ChatModelSettings config Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * feat: pick the flow chat's model and thinking from the provider fields the flow exposes Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * fix: name only the thinking level the flow run will send on the model button Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: let the flow chat take a typed model id and keep a shared thinking input editable Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: promote a flow input to the model button only where its control can edit it Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: drop any reasoning token the chosen model rejects before a flow chat run Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com> |
||
|
|
68f2248018 |
feat: keep flow inputs and seed the agent when chat mode is enabled (#11177)
* feat: keep flow inputs and seed the agent when chat mode is enabled Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * fix: leave a linked agent's memory and streaming to the agent when enabling chat mode Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> --------- Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com> |
||
|
|
a9ec0aec3a |
feat: render the flow chat through the shared session chat components (#11175)
* feat: render the flow chat through the shared session chat components Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * fix: settle the flow chat queue on the turn's outcome and guard IME enter Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * fix: keep copilot free-tier banners and deploy-locked sends out of the flow chat Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> --------- Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com> |
||
|
|
3d08197182 |
feat: badge chat-input flows on the home list (#11164)
* feat: badge chat-input flows on the home list Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * fix: keep a malformed draft value from aborting the runnables list Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * fix: only a JSON boolean marks a draft flow as chat-enabled Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> --------- Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com> |
||
|
|
57a99f66a8 |
feat: rename saved agents from the agent editor and flag broken links (#11147)
* feat: list flows that link a saved agent and flag broken agent links * feat: rename saved agents from the agent editor and repoint the flow * fix: show an unreadable linked agent as not accessible, not missing * fix: address review nits on agent rename and missing-agent state * fix: open content search above modals and keep Escape for it * fix: register content search on the opener's overlay stack * docs: scope the global search z-index comment to the bases it clears * refactor: show linked agents' rename warning as for scripts and flows * fix: keep the failed-lookup rename warning to resources |
||
|
|
8b4f6220dc |
refactor: run the flow chat UI on the windmill-chat sdk (#11134)
* refactor: run the flow chat UI on the windmill-chat sdk Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * fix: structural answer check, poll option and latest run in the chat sdk Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * fix: count jobless tool rows and the loaded license in the flow chat Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> --------- Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com> |
||
|
|
a78beff743 |
feat: dynamic AI agent toolsets (#11050)
* feat: dynamic ai agent toolsets, and memory as a step input Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: address review round 1 on dynamic ai agent toolsets Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * refactor: tag enabled_tools and drop the memory step input Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: let an mcp server entry be named by the path the roster shows Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: keep $res: out of the tool names the enabled tools picker offers Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: name an mcp server by its bare path on the one side that can hold it Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: count the enabled tool names that matched nothing instead of logging them Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * refactor: narrow an agent's roster in one pass, by whole entries Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * test: pin that an mcp summary is rejected against a name that is not Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * chore: regenerate the copilot flow schema after the merge Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * docs: shorten the enabled tools list hint Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * refactor: take enabled_tools back to a plain list of tool names Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * docs: keep the enabled tools add-menu hint describing the unset field Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: name a websearch tool that carries no summary of its own Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: reserve the name web search is enabled by so no tool can share it Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * refactor: spell the reserved web search name with a hyphen Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * refactor: reserve __wm_web_search as the name web search is enabled by Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * chore: advance ee-repo-ref past the git sync ci check work Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * docs: shorten the enabled tools description the run form shows Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * chore: update ee-repo-ref to e4c1b794d6c5e6e390987341b2840587bbb40348 This commit updates the EE repository reference after PR #785 was merged in windmill-ee-private. Previous ee-repo-ref: af668462f0f06b02a5f4e0c22e6156858487a518 New ee-repo-ref: e4c1b794d6c5e6e390987341b2840587bbb40348 Automated by sync-ee-ref workflow. --------- Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com> Co-authored-by: Ruben Fiszel <ruben@windmill.dev> Co-authored-by: windmill-internal-app[bot] <windmill-internal-app[bot]@users.noreply.github.com> |
||
|
|
42f489685b |
feat: store resource type display names and label hub integrations (#11113)
* feat: label resource types and integrations with hub display names Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: load hub integration names in the app and flow pickers Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: load hub resource type names where drawers title a type Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * feat: store resource type display names and drop the hardcoded list Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: leave display_name out of the fork comparison Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: ignore over-long synced display names, move name loaders Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: share the hub integration list cache, backfill admins only Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: keep a name over a nameless duplicate, retry failed hub reads Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com> |
||
|
|
94c548cd5d |
fix: re-attach flow chat to the same job on SSE timeout instead of re-running it (#11122)
* fix: re-attach flow chat to the same job on SSE timeout instead of re-running it Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01S4xKKyrBTs35MEScYucgZW * fix: restart the flow chat stream when the streaming sub-job changes across a reconnect Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01S4xKKyrBTs35MEScYucgZW --------- Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com> |
||
|
|
63cb46d7bb |
feat: add a minimal skin for the approval page and slack/teams (#11061)
* feat: add an approval skin to the approval page and slack/teams messages Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01KK2Ye4PizykReZVuMEm3m9 * chore: point ee-repo-ref at the teams approval skin commit Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01KK2Ye4PizykReZVuMEm3m9 * fix: resolve the approval skin from the step awaiting approval Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01KK2Ye4PizykReZVuMEm3m9 * fix: shorten the slack approval message to fit the button value limit Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01KK2Ye4PizykReZVuMEm3m9 * fix: rename skins to detailed/minimal and keep long slack messages Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01KK2Ye4PizykReZVuMEm3m9 * feat: title the minimal approval page from the step and flow summaries Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01KK2Ye4PizykReZVuMEm3m9 * feat: let wait_for_approval set the description approvers see Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01KK2Ye4PizykReZVuMEm3m9 * fix: keep a finished workflow's approval description, still gated Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01KK2Ye4PizykReZVuMEm3m9 * fix: keep a login-required approval locked after the run moves on Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01KK2Ye4PizykReZVuMEm3m9 * feat: hide the windmill version on the approval page Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01KK2Ye4PizykReZVuMEm3m9 * chore: update ee-repo-ref to e92abc9d1fba3ba898640df0cfeb0af8a50849b4 This commit updates the EE repository reference after PR #786 was merged in windmill-ee-private. Previous ee-repo-ref: bf1766ff49458f62d3f11746f1a06893ae3c2325 New ee-repo-ref: e92abc9d1fba3ba898640df0cfeb0af8a50849b4 Automated by sync-ee-ref workflow. --------- Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com> Co-authored-by: windmill-internal-app[bot] <windmill-internal-app[bot]@users.noreply.github.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> |
||
|
|
fd35b47658 |
feat: create the cloud workspace in onboarding, and teach the empty home (#10959)
* [ee] feat: create a personal workspace on cloud signup instead of the demo invite Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012fRjnaHLwjpHN84gNNxah9 * feat(frontend): land cloud users in their workspace after onboarding Cloud signup creates exactly one workspace for the new user, so the picker that followed onboarding was a page with a single choice on it. Switch to that workspace and go to the home page instead, falling back to the picker whenever there is a real choice: an invite to accept, several workspaces, or none. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012fRjnaHLwjpHN84gNNxah9 * chore(frontend): remove the tutorial system Deletes the guided-tour feature: the tutorials directory, the per-editor wrappers, the home banner and button, the /tutorials route, and the driver.js dependency they were built on. Also removes what only existed to serve them — the `tutorialsToDo` / `skippedAll` / `isCurrentlyInTutorial` stores, the `disableTutorials` prop chain through the flow editor, the `?tutorial=` deep links, PopupV2's clickOutside exemption for the driver popover, and the selector-anchor class on the flow editor tabs. The backend `tutorial_progress` endpoints and table stay: nothing calls them now, and removing them is a public-API break plus a migration that would drop existing progress. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012fRjnaHLwjpHN84gNNxah9 * feat(frontend): suggest Hub projects on an empty workspace home A workspace with nothing in it showed only "Welcome to Windmill". Replace that with a grid of ready-made Hub projects to import, and hide the search box, kind toggles and the sort/filter row while the workspace is empty — they would act on an empty list. A search that matches nothing still keeps its controls and shows the no-match message. The project list is seeded locally for now; the Hub endpoint that ranks them is not there yet, and Import is still a placeholder. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012fRjnaHLwjpHN84gNNxah9 * feat(frontend): make a new cloud workspace the thing onboarding produces Signup already makes a personal workspace; nothing let its owner name it, and a user who ended up without one landed on a workspace picker whose only action was a button. Onboarding now ends on the workspace itself, and the empty home that follows says what a workspace is for rather than "Welcome to Windmill". Onboarding gains a third step that names the workspace signup created, prefilled from the login provider's name or the email local part — `ruben@…` gives "Ruben's workspace". Skipping the survey reaches it too: the questions are ours, the workspace is theirs. Advanced settings swaps in the real creation form for someone setting up for a team. The workspace picker stands down when it has nothing to offer: no workspace to enter and no invite to accept leaves one action on the page, so the page is that action — one field, prefilled, "Create workspace". Both hand-overs hold a loading state for 900ms and the app fades in behind them, so creating a workspace reads as something that happened. The empty home draws three static placeholder rows in the shape of real ones, under a caption offering a template or the New menu. "Start from a template" opens a popover listing the hub's projects, most-starred first, preloaded when the empty state renders and paged as you scroll. Picking one opens the import wizard in a dialog: its two destination steps are already answered by being in a workspace, so it starts at the import itself and pages to the credentials step with the animation the paged-modal pattern provides. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012fRjnaHLwjpHN84gNNxah9 * fix(frontend): gate the empty state and repair the derived workspace id Review findings from the first round. The empty state offers a template import and the New menu, and neither checks a permission — so an operator, or a workspace whose direct-deploy protection cleared `showEditButtons`, was offered both. It now sits behind the same gate as the create menu thirty lines above it. `validateWorkspaceId` answers with the *reason* an id is unusable, so `if (validateWorkspaceId(next)) break` stopped on the first invalid candidate and returned it: someone named Global got the reserved `global`, and a 50-char seed got a taken one. Invalid candidates are skipped instead, and when none works the caller opens advanced settings rather than posting a name the server refuses. Also: `rd` may be absolute (the CLI login sends one) and `goto` refuses those, which would strand the caller on the "Creating …" screen with the workspace already made; the hub host is parsed defensively, since the instance setting is whatever an admin typed and `new URL` was throwing in render; `insert_workspace` says which authorization its callers still own; and the two arrival animations' comments now describe when they actually play. Tests for the two pure helpers the review named: `defaultWorkspaceName` and `hubProjectDescription`. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012fRjnaHLwjpHN84gNNxah9 * fix(frontend): use unifiedSize on the new onboarding step's buttons `size` and `color` are deprecated on Button; the new step copied them from the survey steps above it. AGENTS.md: deprecated props survive at old call sites, copying one forward is still a bug. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012fRjnaHLwjpHN84gNNxah9 * fix(frontend): let Skip wait for the workspace onboarding names `loadWorkspaceStep()` was fired and dropped, while Skip and the use-case Continue branch on `ownWorkspace` in their `finally`. Skip awaits one POST that starts after those two GETs and can finish before them, so a first-frame Skip fell through to `leaveOnboarding()` and landed in the workspace with the backend's name — the step this flow exists for, silently gone. Both exits await the load; `isSubmitting` already covers the wait. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012fRjnaHLwjpHN84gNNxah9 * refactor: create the workspace in onboarding rather than at signup Signup no longer makes a personal workspace, so the last onboarding step creates one instead of renaming it — the same one-field `SimpleCreateWorkspace` the workspace picker falls back to, so a user who leaves onboarding early meets the form again rather than something new. The id now comes from the name they type rather than from their email, and there is one creation path instead of two. `insert_workspace` goes back to being private: the extraction existed only so the EE signup path could call it, and nothing outside `create_workspace` does now. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012fRjnaHLwjpHN84gNNxah9 * fix(frontend): count a pending invite as somewhere to go Onboarding read `listUserWorkspaces`, which returns membership. An invite is a `workspace_invite` row until `accept_invite` runs, so an invited teammate reached the last step owning nothing and was walked into creating a personal workspace, with the invite nowhere on the page. Invites are fetched alongside the workspaces, the way the picker already gates the same decision. A failed load now reads as placed rather than not: the picker can work the decision out, while the create step's only way forward is creating. The create form reports when it is handing over, so the Previous button beside it stands down for the ~900ms rather than offering a way back out of a workspace that now exists. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012fRjnaHLwjpHN84gNNxah9 * fix(frontend): open the template picker downward and size it from the popover The popover's default positioning caps its height to the viewport, and the list inside it carried a fixed one, so a capped box overflowed its own frame — visible with the AI composer hidden, where the caption sits high and `placement: top` left almost no room above it. It opens downward now, with flip fallbacks, at a definite `min(72vh, 520px)`; the list fills what the header leaves, which is still the definite height it needs to page. `creating` on the create form becomes `onCreatingChange`: `$bindable(default)` on an optional prop is banned, and this is something the form reports rather than state it shares. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012fRjnaHLwjpHN84gNNxah9 * refactor(frontend): drop the InfiniteList containerClass prop Added for the template picker, which turns out not to need it: DataTable's own container is already `h-full`, so `containerClass="h-full"` merged to nothing and the height the list pages against comes from the flex chain above it. A prop with no effect at its only call site is public surface for free. InfiniteList is back to what it was. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012fRjnaHLwjpHN84gNNxah9 * fix(frontend): stop a dismissed project import from running on Modal reports dismissal only through its bindable `open` — the X, Escape and the backdrop dispatch neither `confirmed` nor `canceled`. Bind it, so clearing `pick` follows the dialog closing: re-picking the same project opens it again, and a run still in flight is abandoned with a toast instead of writing to the workspace with no UI in front of it. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012fRjnaHLwjpHN84gNNxah9 * fix(frontend): stop a dismissed project import from running on Modal reports dismissal only through its bindable `open` — the X, Escape and the backdrop dispatch neither `confirmed` nor `canceled`. Bind it, so clearing `pick` follows the dialog closing: re-picking the same project opens it again, and a run still in flight is abandoned with a toast instead of writing to the workspace with no UI in front of it. Also mark the inline-link buttons as sanctioned rather than oversights, and give Log out `text-accent` instead of `text-blue-500`. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012fRjnaHLwjpHN84gNNxah9 * fix(frontend): keep the stopped-import toast off the Finish path `done` survives a retry, so Finish is clickable while the run is going again, and its own closing reaches the same falling edge the X does. Abandon the run either way; say it was stopped only when that is what the click asked for. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012fRjnaHLwjpHN84gNNxah9 * feat(frontend): reach the hub importer from the create menu, and count the funnel The picker only existed inside the empty state, which disappears as soon as a workspace holds one item — nothing else in the product linked to `/projects/import`. New → Import now offers a hub project, opening the catalogue in a dialog: a popover anchored to an item inside an open dropdown leaves two melt layers arguing over focus. The list and the import dialog move up to ItemsList, so one dialog serves both doors. `template_setup` records how the credentials step ended — `filled` only when nothing was outstanding, `skipped` carrying how many rows were left — and `template_abandon` records where a dismissed import was given up. `template_picker_open` gains a key naming the entry point. Also on the workspace picker: logging out is a text link on the line that says who you are and an item in the settings menu, rather than the page's accent action, and onboarding's Previous joins the row it belongs to instead of hanging under the button that finishes the form. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012fRjnaHLwjpHN84gNNxah9 * fix(frontend): make the import counters answer what they claim to `template_abandon` folded a landed import closed with the X into `idle`, the bucket read as "opened this and bounced" — three outcomes in one number. It gets its own `done` stage. `template_setup` counted skipped rows through `value`, which is an increment: `skipped` accumulated rows while `filled` and `none` counted imports, two units in one counter with no way to recover one from the other. The row count becomes a bucket in the key, so every event is one import and the buckets compare. The import dialog also asked for the hub URL settings at init, and the home list now mounts it for everyone on every arrival — two GETs for a string only the project card renders. Deferred to the first pick. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012fRjnaHLwjpHN84gNNxah9 * fix: sanitize the inferred username, and stop counting an unread setup step as clean `loadUsernamePolicy` derived a username by stripping dots, so `O'Connor` and `alice+demo` both produced values the `proper_username` constraint refuses — posted invisibly by the simple form, which then failed with nothing on screen explaining why. `usernameFromName` keeps only `[\w-]` and answers undefined when nothing usable is left, which is already the form's cue to open the full one. The credentials step offers Finish when the export could not be read, since it cannot tell what is outstanding — and that landed in `template_setup` as `filled`, the bucket meaning the step came out clean. It reports whether it checked anything, and an unread step counts as `unchecked`. Also drops an orphaned `.sqlx` entry left by the create-at-signup query this branch abandoned, and rewrites the stepper's first-frame comment, which argued from a meaning of `resourceCount` that main has narrowed. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012fRjnaHLwjpHN84gNNxah9 * fix(frontend): cap the inferred username at what the column holds `usr.username` is VARCHAR(50) while the provider name and email it is derived from run to 255, and `create_workspace` inserts the value untruncated — so a long first name failed the same way the invalid characters did: posted invisibly, refused on insert, with nothing on screen naming the field. Undefined instead, which the form already routes to the full one. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012fRjnaHLwjpHN84gNNxah9 * fix(frontend): show the import note where it applies, and drop onCreated's unused id The note is about landing on top of what a workspace already holds, so it belongs wherever the destination is an existing workspace. The route already read it that way; the dialog, which always imports into the current workspace, was hiding it. It costs one collapsed row. `onCreated` was typed as taking the new workspace id, and the advanced branch passed `''` because `CreateWorkspaceInner` does not report one. No caller reads it — the form has already switched to the workspace by then — so the argument goes rather than the lie staying. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012fRjnaHLwjpHN84gNNxah9 * fix(frontend): keep the empty-state toolbar reachable, and name the view counters "Empty" here means the default listing found nothing, and a workspace whose items are all archived looks exactly the same. The searchbar carries "Only archived", so taking it off the pointer left those items unreachable without hand-writing a query URL. Dimmed still, never `inert`. The disclosure named the counters that fire on a creation or an import and not the three that fire on merely seeing the empty home or opening either picker. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012fRjnaHLwjpHN84gNNxah9 * fix(frontend): respect disable_hub in both hub-project entry points An instance with the hub turned off still got the catalogue preloaded on every empty home and an "Import a hub project" entry in the create menu — an outbound request the operator has said not to make, and a door to somewhere unreachable. Both now observe `disableHubStore`, the store the script and flow hub pickers already read. With the hub off the caption reads "Create a new one." rather than continuing a sentence whose first half is gone. The telemetry disclosure also scoped the create menu and picker counters to the empty home, when both fire from the toolbar in a populated one, and said a creation was recorded when what is recorded is the menu opening. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012fRjnaHLwjpHN84gNNxah9 * refactor(frontend): drop the catalogue preload rather than gate it twice Warming the hub catalogue when the empty state rendered bought the time between the caption appearing and someone clicking it, and cost two defects: the request fired on instances with the hub turned off, and the gate added for that raced `disable_hub`'s own load, which starts false and stays false if the settings request fails. The picker fetches on open instead. Measured: nothing before the click, one request after it, 411ms to a filled list. `disableHubStore` still hides the link and the menu entry, which cost no request and correct themselves if the setting lands late. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012fRjnaHLwjpHN84gNNxah9 * docs: count the home actions, and state the lazy-fetch constraint without its history The telemetry doc's tally is maintained by hand and main had just moved it; this PR adds a feature, so it reads 48 across eighteen with `home` in the list — verified against the pinned EE ref rather than counted by eye. The empty state's comment narrated a preload that no longer exists and the defects it caused. What a future reader needs is the constraint: `disable_hub` loads asynchronously, so a fetch from here goes out before the setting forbidding it is known. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012fRjnaHLwjpHN84gNNxah9 * fix(frontend): stop the prefill overwriting a typed name, and gate submit on the policy `load()` assigned the suggested name unconditionally, so a name typed while its two requests were in flight was replaced a moment later. It now yields to anything already typed. Nothing may be submitted before the username policy lands either: `automateUsername` starts at the common case, and posting that guess to an instance that derives no usernames sends none where one is required. `policyLoaded` gates both the button and `create()`, and is set in a `finally` so a failed load leaves the form usable rather than wedged. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012fRjnaHLwjpHN84gNNxah9 * fix(frontend): settle the username policy on failure instead of guessing it `policyLoaded` was set in a `finally`, so a failed policy load unblocked the form with `automateUsername` still at its default — the exact submit the flag exists to prevent. The failure now hands over to the full form, which asks for a username outright rather than inferring one, so the flag is never true while the answer is still a guess. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012fRjnaHLwjpHN84gNNxah9 * fix(frontend): answer the username policy instead of rejecting it Three rounds of this bug moved between call sites because the shared loader rejects when it cannot read `automate_username_creation`, leaving each caller to guess — and both guessed "automated", which hides the username field and posts none to an instance that derives none. `loadUsernamePolicy` now answers "ask for one" in that case, so `SimpleCreateWorkspace` and `CreateWorkspaceInner` both render a field someone can type into rather than submitting a guess. An instance that does automate ignores a username it was sent, so asking is safe either way. The prefill and the policy are settled apart now too: a failed `globalWhoami` costs the suggested name and nothing else. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012fRjnaHLwjpHN84gNNxah9 * fix(frontend): block creation when the username policy is unknown There is no safe default. `create_workspace` refuses a username on an instance that automates them and requires one on an instance that does not (`workspaces.rs:5820`), so a client that cannot read the setting has two request shapes available and the server rejects both. Last round's "ask for one" was as wrong as the "automated" guess it replaced. So the loader reports the failure instead of inventing an answer, and the form says so: Create stays disabled, with a line explaining why and a link to try again. Verified in the browser both ways — unreadable policy disables Create and shows the message, a healthy load prefills the name and enables it. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012fRjnaHLwjpHN84gNNxah9 * fix(frontend): close the advanced-settings bypass while the policy is unknown Create was gated on knowing whether the instance derives usernames, and the link beside it went to a form with no such gate — so the way around the block sat next to it. It is disabled until the policy is known, with a title saying why. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012fRjnaHLwjpHN84gNNxah9 * fix(frontend): reload the list on dismissal, and never re-offer a workspace that exists Closing a landed import with the X left the home list stale: only `finish()` reloaded it, so a workspace that now holds a project kept showing its placeholder rows. A run that started wrote items whether it finished, was abandoned or failed partway, so any dismissal after one reloads. Creation reported failure for a failed *list refresh* too, and handed the form back — where a retry picks the next free id and creates a second workspace. Once `createWorkspace` returns, nothing may report failure: the refresh is logged if it fails, and the hand-over proceeds, since the workspace is real either way. The disabled-link tooltip also claimed the settings could not be read during the ordinary load, before anything had failed. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012fRjnaHLwjpHN84gNNxah9 * fix(frontend): reload after the abandoned run stops, not when it is asked to `abandon()` stops the run at the next phase boundary; the request already sent still lands. Reloading the list at that moment could read it before that write committed, leaving the caller stale again — the thing the reload was added to fix. It now waits for `running` to clear, which is immediate for the common case of dismissing a finished import, with a cap so a run that never settles still ends in a reload. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012fRjnaHLwjpHN84gNNxah9 * fix(frontend): give the list reload one owner, taken by both exits Finish reloaded immediately while dismissal waited for the run to stop, so Finish pressed during a retry — `done` survives one, which is what makes the button clickable then — read the list mid-write, and its `finishing` flag stopped the deferred reload from correcting it. Both exits now go through the same wait. One reload per closing, always after the writing stops, whichever way the dialog was left. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012fRjnaHLwjpHN84gNNxah9 * feat(frontend): give ImportExecution a whenIdle(), and await it instead of polling The reload waited on a 250ms poll of `running` with a 15s cap, because the modal receives the execution after `run()` was already called and so holds no promise to await. The cap was its own hole: a write slower than 15s reloaded early, and nothing followed. `run()` now keeps the in-flight promise and `whenIdle()` hands it out — resolved when nothing is being written, immediate when no run is in flight. The modal awaits that: no poll, no cap, no window. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012fRjnaHLwjpHN84gNNxah9 * fix(frontend): back the settlement reload with a bound, and keep reporting run failures `installProject` writes serially and takes no signal, so a request left pending after earlier items committed leaves those invisible until the next page load — `whenIdle()` alone never resolves for it. A bound now reloads once in that case, *without* replacing the settlement reload: replacing it was the flaw in the timeout this grew out of, so a hung run reloads on the bound and again if it ever finishes. `whenIdle()`'s rejection handler also swallowed the only report an unexpected throw had — `#runInternal` has no catch of its own, and a throw outside its inner ones leaves a stalled run with nothing on screen. It logs now instead of discarding. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012fRjnaHLwjpHN84gNNxah9 * feat(frontend): say when a workspace holds only archived items A workspace whose items are all archived read as empty, because the placeholder is decided by the default listing. Reaching those items then depended on the toolbar, which is why it had been left interactive while dimmed — and that let a kind toggle replace the invitation with "no items found" on a workspace that really was empty. The state is named instead. When the default listing comes back empty, one request asks whether anything archived exists, and the placeholder says which of the two it is: "Everything in this workspace is archived" with a link to show them, or the ordinary invitation. Held until that answer lands rather than drawn and swapped, since the wrong one claims the workspace is empty when it is not. The toolbar is dimmed and `inert` again, its original design: the archived case now carries its own way in. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012fRjnaHLwjpHN84gNNxah9 * fix(frontend): make the archived route independent of write permissions Three ways the archived-only placeholder failed to deliver what it promised: Reading archived items is not a write, but the notice offering them sat behind the create-permission gate — so an operator, or a workspace whose direct-deploy protection cleared `showEditButtons`, got "no items found" over items it could see and a toolbar now inert. The gate governs the create actions alone; the notice is shown to whoever the probe found something for. The probe answered once per workspace and was never invalidated, so archiving the last item left a cached "nothing archived" claiming the workspace was empty until a page load. `reloadItemsAndCounts` clears it. And it omitted `includeWithoutMain`, which the backend reads as excluding library scripts — a workspace holding only archived ones answered "empty". Always true here: hiding library scripts puts a filter in `activeFilters`, which `workspaceEmpty` requires to be empty. `whenIdle()` gains the two tests its contract deserves, since the reload correctness three rounds argued over rests on it. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012fRjnaHLwjpHN84gNNxah9 * fix: harden the hub proxy, the workspace picker's gating and the rd hand-off Findings from four local review passes over the branch: - `list_projects` refuses when `disable_hub` is set, and `is_public_hub` now compares the parsed host, so no spelling of the public hub (mixed-case scheme or host, port, trailing dot, userinfo) forwards a member's bearer token there. Covered by a unit test table. - The workspace picker waits on `usersWorkspaceStore` as well as `workspaces`, which derives to `[]` while the store is unloaded; with the create-form latch, one such frame swapped a member's picker for the create form until reload. - `refreshSuperadmin` takes `force`, and the picker uses it: a `false` left over from a logged-out load decides whether the page is a picker or a create form. A cancelled call no longer publishes `false` over the live request's answer, and only its own request's handle is cleared. - `rd` is sanitized once where it is derived rather than at each of the four hand-offs, so an absolute target keeps the OAuth callback's allowance and `https://evil.example/` is dropped. - The archived-items probe answers "unknown" on failure, which keeps the ordinary caption and leaves the toolbar reachable. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012fRjnaHLwjpHN84gNNxah9 * fix: answer the round-33 nits on the hub route and the empty state - `empty_state_view` is no longer logged for an archived-only workspace, which is not the state the counter measures. - `detail`'s fetcher keeps its last answer in a local instead of reading `detail.current`, a self-reference that typed the resource `any`. - `list_projects`' comment, including its authorization contract, is back on the handler rather than on the predicate inserted above it. - `listHubProjects` documents the 400 an instance with the hub disabled returns. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012fRjnaHLwjpHN84gNNxah9 * feat(frontend): keep the operator onboarding tour Operators cannot create anything, so the home page is the whole product to them and its three tabs are worth naming. The tour that did that is the one piece of the removed tutorial system that still has an audience. Restored trimmed: driver.js, the driver wrapper and its controls, the `.driver-popover` styling, and a module for the progress bit. The catalogue machinery it used to sit in — the config, the role gating, the router, the banner and the tutorials page — stays deleted, so the five steps are reached directly instead of through a registry of one. It runs on an operator's first home page visit and is recorded as seen however it ends, including navigating away; afterwards it is in the sidebar menu under Take the tour, which is where the last step points. Progress uses the surviving `tutorial_progress` route, slot 6, read-modify-written so the slots of the removed tutorials keep their state. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01JirHCYVR6qg7Xqe4PcZ1KG * fix(frontend): dim the home toolbar only where the placeholder replaces it Standing the toolbar down depends on something else offering a way onwards. An operator in a workspace that is simply empty gets no placeholder — they cannot create, and there is nothing archived to reach — so the search and the kind toggles were the only controls on the page, dimmed to 40% and `inert`. They now follow the placeholder rather than emptiness, which also stops the operator tour spending three of its five steps highlighting controls this page had greyed out. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01JirHCYVR6qg7Xqe4PcZ1KG * docs(frontend): put the inline-link rationale on the first link, not the third The caption's three links share one reason for being bare `<button>`s, and it was written on the last of them. A reader — or a reviewer — meets the archived one first. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01JirHCYVR6qg7Xqe4PcZ1KG * fix(frontend): keep private hub project names out of telemetry An instance pointed at its own hub imports its own projects, and the slug naming one is the customer's content — `template_import` was recording it verbatim, which the disclosure ("the name of any public hub project") does not cover and `hub_script` already avoids by collapsing a private script to `private`. `hubProjectUsageKey` gives projects the same treatment, deciding by the configured hub's host so a port, a scheme's case or a trailing slash cannot turn a private hub into a public one. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01JirHCYVR6qg7Xqe4PcZ1KG * fix(frontend): treat an unread hub setting as private, not as the public hub `hubBaseUrlStore` is seeded with the public hub and written in one place, by a loader with no catch and no retry. A settings read that threw therefore left the store naming hub.windmill.dev for the rest of the session, and the import counter read that as permission to report a private instance's project slug — the leak the previous commit closed, narrowed to "after one failed read". The fact has three states and the store held two, so `hubBaseUrlKnown` carries the third: the loader sets it only once the value is the instance's own, and the telemetry key requires it. Links keep rendering the default meanwhile, which is what they always did. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01JirHCYVR6qg7Xqe4PcZ1KG * fix(frontend): tag each hub detail with the slug that asked for it `resource()` assigns whatever its fetcher returns, with no guard for a run that has been superseded, so handing back the previously fetched project on a stale response published that project. With two slow requests in flight — pick A, leave B loading, pick C — B's answer put A's name, author and counts on the card while the plan underneath still said C, and Import wrote C. Each answer now carries its own slug and is read only while that slug is the chosen one, which also drops the local the previous shape needed to keep the resource's type from going circular. The hub-telemetry tests reset their shared fixture per case; the private-hub one had been passing on what the case above it left behind. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01JirHCYVR6qg7Xqe4PcZ1KG * fix(frontend): stop the template picker spinning on a hub with no projects Opening the picker against a reachable hub that has published nothing pinned the renderer at full CPU and froze the tab. The effect arming the list called `setLoader` and `loadData`, which read `InfiniteList`'s reactive state as well as writing it, so the effect depended on what its own load changed and re-ran itself; a list that stays empty never settles that cycle. It now arms the loader once per workspace, untracked, and leaves the load to `setLoader`. The same empty list also claimed the hub was unreachable, since one `empty` snippet serves both. The loader records which happened, so a hub with nothing on it says so. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01JirHCYVR6qg7Xqe4PcZ1KG * fix(frontend): keep a superseded hub answer from erasing the chosen project `resource()` publishes whatever its fetcher returns, superseded or not, and `fetchHubProject` takes no abort signal — so an answer for a project the user had moved on from replaced the published value, the slug guard rejected it, and the chosen project's item counts went off the card for good with nothing left to ask for them again. The fetch now records its own answer, tagged with its slug and only while that slug is still the chosen one, and the card reads that. Nothing reads the resource, so it is a `watch` — the same machinery without the value that was the problem. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01JirHCYVR6qg7Xqe4PcZ1KG * chore: update ee-repo-ref to 81edd1382d951265ab3e9b67fc7ca7967676fd56 This commit updates the EE repository reference after PR #775 was merged in windmill-ee-private. Previous ee-repo-ref: 21ace847ec1c1406bafc50153004e1874642bf6c New ee-repo-ref: 81edd1382d951265ab3e9b67fc7ca7967676fd56 Automated by sync-ee-ref workflow. --------- Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com> Co-authored-by: windmill-internal-app[bot] <windmill-internal-app[bot]@users.noreply.github.com> |