Commit Graph

14148 Commits

Author SHA1 Message Date
Diego Imbert f4dfaff9c6 refactor(datatables): drop best-effort fork schema diff for migrations
Fixes GIT-890

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0168uEtDtsvdbk89S1LqtcLW
2026-07-29 00:33:29 +02:00
Ruben Fiszel 33d28456cc fix: surface the real reason git sync settings saves are rejected (#10398)
* fix: surface the real reason git sync settings saves are rejected

* fix: redact credentials and cover the remaining api error sites

* chore: update ee-repo-ref to 85209cfccb07538ae4748d85b56e61c0bef4f606

This commit updates the EE repository reference after PR #691 was merged in windmill-ee-private.

Previous ee-repo-ref: 01ca990c6a02a745e16f13da972497add0ad7a6c

New ee-repo-ref: 85209cfccb07538ae4748d85b56e61c0bef4f606

Automated by sync-ee-ref workflow.

* fix: drop the unactionable branch advice and the last inline error copy

---------

Co-authored-by: windmill-internal-app[bot] <windmill-internal-app[bot]@users.noreply.github.com>
2026-07-28 23:12:28 +02:00
Ruben Fiszel a17ccbdd0d fix: distinguish waiting-on-user from streaming in ai sessions (#10396)
* feat: expand the active fork's family in the workspace menu

* fix: distinguish waiting-on-user from streaming in ai sessions

* fix: honor compact sizing in the waiting-for-input pill

* docs: condense waiting-state comments to the 4-line limit

* fix: detect a blocked tool card sitting behind queued ones

* fix: scan to the turn boundary for a blocked tool card
2026-07-28 22:30:13 +02:00
Ruben Fiszel cfb8ca4391 chore(main): release 1.775.1 (#10394)
* chore(main): release 1.775.1

* Apply automatic changes

---------

Co-authored-by: rubenfiszel <275584+rubenfiszel@users.noreply.github.com>
v1.775.1
2026-07-28 20:43:07 +02:00
Ruben Fiszel 39dd411481 fix(frontend): add the preprocessor node before the error handler markers (#10395) 2026-07-28 20:37:22 +02:00
Guilhem d842f765a4 fix(ai): render pending parallel tool calls as faded queued cards (#10208)
* fix(ai): show queued state instead of spinner for pending parallel tool calls

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* fix(ai): clear queued tool cards on chat cancel or stream error

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* fix(ai): render queued tool calls faded with imperative labels

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* fix(ai): keep queued labels past preAction, humanize camelCase names

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* style: drop narrating comment in queuedToolStatus

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* fix(ai): run preAction at tool promotion, dedupe queued-state comments

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-07-28 19:34:17 +02:00
Ruben Fiszel 0de18dc017 chore(main): release 1.775.0 (#10392)
* chore(main): release 1.775.0

* Apply automatic changes

---------

Co-authored-by: rubenfiszel <275584+rubenfiszel@users.noreply.github.com>
v1.775.0
2026-07-28 18:59:14 +02:00
Ruben Fiszel 7ac2909b30 fix: don't crash the flow editor when a step with an error handler marker is deleted (#10393)
* fix(frontend): don't anchor an error handler marker to a deleted step

* test(frontend): pin that topologicalSort tolerates a missing parent node
2026-07-28 18:59:01 +02:00
Ruben Fiszel bff654596f fix: render the flow editor's error handler node as an inert run marker (#10391)
* fix(frontend): render the error handler as an inert run marker in the flow editor graph

* fix(frontend): dismiss nested error handler markers via a dedicated handler

* docs(frontend): note that error handler markers are keyed by failing step
2026-07-28 18:41:52 +02:00
Guilhem bd246644c9 feat: add github dark mode variant switchable in user settings (#10002)
* feat: add github dark mode variant switchable in user settings

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* feat: boot the UI Builder iframe into the current theme

Seed the UI Builder iframe URL with the live dark/variant state
(`?dark=&variant=`) so the VS Code workbench boots straight into GitHub
Dark / Nord / Light instead of flashing the dark default until the host's
`setDarkMode` message lands. Read from the <html> classes rather than the
reactive state so the src is computed once at mount — a later theme toggle
still updates the workbench via postMessage and does not reload the iframe.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* feat: align github-dark surfaces to GitHub Primer's elevation scale

Snap the invented mid-greys to Primer's real dark canvas scale
(inset=neutral.0, default=neutral.1, muted=neutral.2). Recessed surfaces
now use true inset (#010409) instead of washed-out half-steps that sat in
no-man's-land between inset and the page; raised surfaces align to muted.

- surface-secondary  #0b0e13 → #010409  (true inset)
- surface-input      #0c0f14 → #010409  (true inset)
- surface-disabled   #0b0e13 → #151b23  (muted)
- surface-tertiary   #161b22 → #151b23  (Primer neutral.2)
- component-virtual-node #161b22 → #151b23
- surface-selected   #21262d → #212830  (Primer neutral.3)

surface-sunken (#010409) and surface-primary (#0d1117) already matched
Primer inset/default exactly.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* fix: keep github-dark inputs subtle instead of full inset

surface-input at true inset (#010409) made form fields read as recessed as
the sidebar rail — too much contrast against the canvas. Inputs aren't
sunken, so keep the subtle #0c0f14 (a hair below the page) while the
recessed panel surfaces stay at inset.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* chore: bump UI Builder pin to the github-dark build (76ee616)

windmill-code-ui-builder PR #16 is merged and published to R2, so pin the
artifact to that build. The embedded raw-app editor now renders GitHub Dark
(and honors the `variant` message) natively from the pinned build — no local
swap needed. Reword the variant comment now that the dependency is resolved.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* fix: address codex review nits on the github-dark theme

- UserSettings: re-read the dark variant when the settings drawer opens, so a
  change made through one mounted instance (page-local drawer) isn't shown
  stale by another (the always-mounted layout instance).
- PublicApp / OAuth login callback: restore the `github-dark` variant class,
  not just the base `dark` class. These routes bypass the (root) layout, so
  they previously fell back to the default dark palette despite the saved
  preference.
- RawAppEditor: condense the two new theme comments to the durable constraints
  per AGENTS.md (drop narration and the ephemeral artifact-pin history).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* fix: address CI review findings on the github-dark theme

- Move the hand-authored `github-dark` token set out of the Figma-generated
  tokens.json into githubDark.json, merged back in at the two consumers
  (tailwind.config.cjs before the rgb pass, utils.ts) so a Figma re-export of
  tokens.json can no longer drop the set and crash the build.
- Restore the default-dark sidebar divider to #374151 — the PR must leave the
  Default variant unchanged; only the github variant adapts it to border-light.
- Extract the `github-dark` DOM-class read into getAppliedDarkModeVariant() and
  reuse it across RawAppEditor and vscode.ts; drop the redundant `void darkVariant`.
- Override the Monaco popup vars (suggest/hover widgets) in the github variant so
  they match the GitHub palette instead of VS Code's greys.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-authored-by: Ruben Fiszel <ruben@windmill.dev>
2026-07-28 18:34:41 +02:00
Ruben Fiszel 91b8ce581a feat: validate and make explicit the hub project's resource type export (#10388)
* feat: make hub resource type export explicit and validated

* fix: skip resource type validation when the workspace has no type catalog

* fix: snapshot the export opt-in and exclude s3_object unconditionally

* fix: capture the export opt-in at publish click, not after the draft request

* docs: correct the publish-snapshot rationale
2026-07-28 18:30:55 +02:00
Ruben Fiszel faa2aaf214 fix: truncate strings on char boundaries to avoid panics on multibyte input (#10390)
* fix: truncate strings on char boundaries to avoid panics on multibyte input

* fix: add borrowed truncate_chars helper and pin ee ref for audit fix

* docs: clarify truncate_with_ellipsis length contract

* chore: update ee-repo-ref to bbfb0de0dc9fa06130a231eb10c64f60238d1bbd

This commit updates the EE repository reference after PR #690 was merged in windmill-ee-private.

Previous ee-repo-ref: de15aeff12daf457711f5b981de691418484535c

New ee-repo-ref: bbfb0de0dc9fa06130a231eb10c64f60238d1bbd

Automated by sync-ee-ref workflow.

---------

Co-authored-by: windmill-internal-app[bot] <windmill-internal-app[bot]@users.noreply.github.com>
2026-07-28 18:29:45 +02:00
Ruben Fiszel 773a428ad0 chore(main): release 1.774.0 (#10365)
* chore(main): release 1.774.0

* Apply automatic changes

---------

Co-authored-by: rubenfiszel <275584+rubenfiszel@users.noreply.github.com>
v1.774.0
2026-07-28 17:43:36 +02:00
Ruben Fiszel 3b95c947d4 test(wac): pin the failure record with one corpus both SDKs read (#10385)
* test(wac): pin the failure record with one corpus both SDKs read

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* test(wac): add the behaviour matrix that verified the failure record

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* docs(wac): record how to exercise an unreleased SDK change

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* fix(wac): guard the whole extra pair, not just its value

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* fix(wac): never rehash an untrusted extra key

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* fix(wac): walk only a real __dict__ when collecting extra

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* docs(wac): name the divergence the corpus cannot pin

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* chore(wac): state the extra-encoding constraints in four lines

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-28 16:54:40 +02:00
Ruben Fiszel faf5aead6f ci: run the SDK suites on release (#10386)
* ci: run the python and typescript SDK suites

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* ci: run the SDK suites on release tags only

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* chore(ci): state the constraint without the incident

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* docs(sdk): claim only what functools.wraps actually restores

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* docs(ci): note the interpreter the suite runs on is not the worker's

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-28 16:51:47 +02:00
Guilhem ac970efa16 feat: bulk discard selected drafts on the compare & deploy page (#10372)
* feat(frontend): bulk discard selected drafts on the Compare & Deploy page

Add a destructive "Discard N drafts" button next to "Deploy N drafts" in
draft mode. A single confirmation modal lists draft-only items (permanent
deletions) by path before discarding sequentially with per-row status.

Split the selection gate into isDiscardable (own draft, not deployed this
session, not a data-pipeline bundle) and isDeployable (+ can_write): the
server lets you discard your own draft on a path you can no longer write
to, so each footer button counts its own eligible selection.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* fix(frontend): address review findings on bulk draft discard

- invalidate the workspace-drafts resource once per batch instead of once
  per discarded row (discardDraft gains an invalidate opt-out)
- write-gate legacy (ownerless) drafts in isDiscardable + tooltips,
  mirroring the server's discard check
- explain diverging footer counts with a hint when selected drafts are
  discardable but not deployable
- update selection-contract comments left over from the deploy-only gate

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* fix(frontend): cover shared-draft outcome in bulk discard modal + comment reflow

A draft-only item someone else also drafted is neither reverted nor
deleted — only the current user's draft is removed. Say so in the modal.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-07-28 14:35:44 +02:00
Guilhem c12e7c3431 feat(ai-chat): add get_flow_run_details tool for per-step flow run results (#10374)
* feat(ai-chat): add get_flow_run_details tool for per-step flow run results

* fix(ai-chat): report flow step retries as attempts, not loop iterations

* fix(ai-chat): scope-tag flow tree descendants, cap entries, fix labels

* fix(ai-chat): cap rows pre-join, signal tag scoping, code-point slicing

* fix(ai-chat): authoritative sibling order + pinned flow_version lookup

* fix(ai-chat): decorrelate drill ordinal join, cap step diagnostics
2026-07-28 14:35:24 +02:00
Guilhem 5feec9b4cd fix(ai-chat): make hub script paths readable from the global chat (#10381)
* fix(ai-chat): make hub script paths readable from the global chat

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* fix(ai-evals): match hub fixtures on whole words, not substrings

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-28 14:35:01 +02:00
Alexander Petric c4e75683a8 fix: mark Setup URL as required in self-managed GitHub App instructions (#10380)
* fix: mark Setup URL as required in self-managed GitHub App instructions

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WTZ5UBBLNh2rkgfNzUmCWs

* fix: clarify workspace assignments table only renders once app is configured

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WTZ5UBBLNh2rkgfNzUmCWs

---------

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-07-28 14:34:29 +02:00
Ruben Fiszel 2a2ef41152 fix: home kind filter no longer resets a fork or reloads the page (#10384)
* fix: source setQuery's query string from the address bar, not page.url

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* fix: stop treating site-wide cross-origin isolation as leaving the editor

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-28 14:32:44 +02:00
Ruben Fiszel fbf9f04e10 fix: surface the real postgres error when data table migrations fail (#10371)
* fix: surface the real postgres error when data table migrations fail

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* fix: address review nits on the data table migration error fix

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* fix: name the exact grant a data table migration needs

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* fix: quote both identifiers in the data table grant hint

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* feat: add a data table connection and privilege check to workspace settings

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* fix: report data table privileges from the capability fields, not the grant list

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* fix: read grant targets from the server and drop the public schema guess

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* fix: render the search_path suggestion server-side and pin the granted database

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* fix: key the connection check on request identity, not the data table name

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* fix: declare the data table check schema field nullable and required

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-28 14:29:06 +02:00
Ruben Fiszel aeaea57ca1 fix(wac): one failure record for tasks and steps, in every round (#10368)
* fix(wac): hand a caught task and step failure the same shape in every round

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* refactor(wac): decide the failure record once, server-side

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* fix(wac): leave a legacy SDK's failure marker untouched, and ship wacError to jsr

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* fix(wac): carry a step's custom error fields, and bound the stack in bytes

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* fix(wac): keep a step's extra fields serializable and bounded

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* fix(wac): record a non-Error throw the way a task records it

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* fix(wac): guard the last unguarded throw site in the step marker

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* fix(wac): make failure reporting non-throwing on both clients

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* fix(wac): take the step traceback the way the executor takes it

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* fix(wac): contain the reads that happen before a failure is checkpointed

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* fix(wac): fall back to the checkpointed marker, not the live one

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* fix(wac): keep non-finite fields and hostile proxies out of the checkpoint path

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* fix(wac): keep the snapshot that passed the serialization probe

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* chore(wac): keep the failure-record module's surface to what is used

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-28 13:15:24 +02:00
Ruben Fiszel 8d684c0b23 fix(ai-agent): keep tool description through flow deployment (#10373)
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-28 13:09:30 +02:00
Ruben Fiszel a0798a3d82 refactor(flows): make the flow-value round-trip preserve display-only fields in one place (#10382)
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-28 13:09:08 +02:00
Ruben Fiszel ecde94567c fix: make same worker mutually exclusive with retries and sleeps in the flow editor (#10379)
* fix(frontend): make same worker mutually exclusive with retries and sleeps

* fix(frontend): cover failure/preprocessor modules and skip agent tools
2026-07-28 12:34:36 +02:00
Ruben Fiszel 5e52346242 fix: surface postgres publication errors as 400 instead of 500 (#10376) 2026-07-28 12:25:08 +02:00
Ruben Fiszel 1b6b2aa859 fix(datatable): provision the replication user on managed postgres (#10375)
* fix(datatable): provision the replication user on managed postgres

* fix(datatable): serialize replication user provisioning and sync config schema

* fix(datatable): keep replication cleanup best-effort and self-heal a null password
2026-07-28 12:17:09 +02:00
Diego Imbert a544dfde9a fix(frontend): preserve top-level flow settings in AI flow tools (#10369)
* fix(frontend): preserve top-level flow settings in AI flow tools

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DaNkfh3YH8VoTNebkRuunB

* fix(frontend): treat degenerate agent transforms as unconfigured in chat mode toggle

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DaNkfh3YH8VoTNebkRuunB

* fix(frontend): treat persisted static-null agent transforms as unconfigured

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DaNkfh3YH8VoTNebkRuunB

---------

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-07-28 10:48:18 +02:00
Diego Imbert 3c2dab9f8f fix(apps): stop cross-origin isolating the raw app viewer (#10370)
* fix(apps): stop cross-origin isolating the raw app viewer on page reload

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WAprL4Yp4T8GxYgSuuJJyT

* fix(apps): shed cross-origin isolation when leaving the raw app editor

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WAprL4Yp4T8GxYgSuuJJyT

* chore(apps): address review nits on COEP scoping

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WAprL4Yp4T8GxYgSuuJJyT

---------

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-07-28 10:41:08 +02:00
Ruben Fiszel 044ce39e5f fix(wac): return the checkpointed value from step(), not the live object (#10367)
* fix(wac): return the checkpointed value from step(), not the live object

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* docs(wac): regenerate system prompts and narrow the round-trip claim

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* style(wac): condense the round-trip comments and fix the fallback note

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* feat(sdk): type step() as the JSON round trip of its body's result

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* feat(sdk): apply the JSON round trip to task() and the standalone paths

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* fix(sdk): encode bigint, keep unknown as unknown, align dropped-key results

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* fix(wac): null out results whose key JSON.stringify would drop

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* fix(wac): normalize only the top-level result, keeping nested keys as they were

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* fix(wac): normalize a child task's result so a deployed job cannot fail to parse

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* docs(sdk): pin non-finite number behavior in Jsonified and its tests

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* fix(sdk): admit undefined for keys whose value JSON.stringify may omit

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* fix(sdk): make a key JSON.stringify may omit optional, not just nullable

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* fix(sdk): treat a class-valued property as dropped, like any other function

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-28 09:46:23 +02:00
Guilhem b0c7e09173 fix: show draft badge and disable the toggle for draft-only triggers (#10155)
* fix: show draft badge and disable toggle for draft-only triggers

* fix: align draft badge visibility with local draft hint

* fix: refine draft trigger rows (badge by label, off toggle, hover hints)

* fix: match draft pill size to standard badge size

* fix: show not-allowed cursor on disabled toggles

* fix: show the draft-only badge in place of the trigger toggle

Draft-only triggers have nothing deployed to enable, so the row renders
the "Draft only" badge in the toggle's slot instead of a disabled toggle.
Deployed triggers that also have a draft keep their toggle and show the
"Draft" badge next to the label.

Applies to schedules and every trigger list page, including amqp.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* fix: place the draft badge left of the trigger toggle

Both badges now sit in the toggle's row: "Draft only" next to a disabled,
off toggle, and "Draft" next to the live toggle of a deployed trigger that
also has a draft. The label keeps only its `*` marker.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* fix: show the draft badge hint as a tooltip when it has no actions

Without owner rows the popover renders a focus-ringed 256px card for a
single sentence. Route that case through Tooltip and keep the popover for
the owner list, whose View Diff / Load / Migrate buttons need click targets.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* fix: drop the "edited by" label when there is no author

Draft-only rows are synthesized from the draft table and carry no author,
so the label rendered with nothing after it. Show it only when a name exists.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* fix: render the draft badge on push-mode GCP and Azure triggers

Those rows have no mode toggle, and the badge slot was nested inside the
toggle's conditional, so they showed no badge at all.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* fix: let the trigger control slot grow, and hint the suspended group too

The suspended three-state control is ~246px and overflowed the fixed 8rem
slot into the row's status and badges; the slot now treats 8rem as a
minimum so unsuspended rows still line up. Moving `title` onto the wrapper
also gives the suspended group the draft explanation the toggle already had.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* fix: drop the date's "the"/"at" prefix on authorless rows

Without an author the prefix dangled ("the 7/15, 03:42 PM"); those rows now
show a bare timestamp.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* fix: address PR review — draft-only row state, and DraftBadge visibility

- Derive each trigger row's status indicator from one effective mode, so a
  synthesized draft-only row (mode 'enabled', no server_id) no longer claims
  the trigger is starting up next to an off, disabled toggle.
- Fold draft_only into DraftBadge's own visibility rule so call sites pass
  their state as-is instead of hard-coding is_draft={true} behind a guard
  that duplicated the rule.
- Apply the same call to variables and resources, which still carried the
  original is_draft={false} form and so rendered no badge at all.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* fix: keep every mode control off draft-only rows

The row's overflow menu still offered "Suspend job execution" for draft-only
triggers, calling the mode API for a trigger with no deployment, and the
schedules enabled/disabled filter still read the raw `enabled` flag, so
draft-only schedules listed under Enabled while rendering an off toggle.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* perf: mount the draft diff drawer only where it can be opened

DraftBadge mounted a DiffDrawer on every instance, so unpaginated lists like
resources and variables carried a hidden drawer per row (measured: 4334 vs
3854 DOM nodes over 120 draft-less rows). The drawer is only reachable from
the popover's View Diff, which already requires `actionsEnabled`.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-07-28 09:03:11 +02:00
Guilhem ad0fef4a2e feat(ai-chat): recall queued/last message into the composer (#10191)
* feat(ai-chat): recall queued/last message into input via ArrowUp or chip click

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* feat(ai-chat): cycle chat mode with Shift+Tab, keep full message in chip tooltip

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* fix(ai-chat): only cycle mode on Shift+Tab when the textarea is focused

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* revert(ai-chat): drop Shift+Tab mode cycling, it conflicts with browser shortcuts

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* fix(ai-chat): only recall on ArrowUp when the textarea is focused

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* fix(ai-chat): make ArrowUp recall image-aware, unnest the queued-chip controls

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* fix: align workspace banners with page content padding and round corners

* fix(ai): recall attachments and context chips on ArrowUp, unnest chip buttons

* fix(ai): skip synthetic auto-resume turns in ArrowUp recall boundary

* fix(ai): defer recall during in-flight sends, make synthetic flag per-send

* fix(ai): gate recall on send-in-flight, not loading

---------

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-07-28 08:57:15 +02:00
Ruben Fiszel 3b95a2d096 feat: reusable AI agent steps with rigid linking and edit/fork (#9825)
* feat: reusable AI agent steps with hybrid linking and evals

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* feat: make linked AI agents rigid (read-only) with unlink-to-fork

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* feat: show inherited agent config read-only on linked step

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* feat: edit/update a saved agent in place via upsert

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* feat: bind linked AI agent tool inputs to host flow context

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* feat: rebind linked AI agent tool inputs via graph tool nodes

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* fix: linked AI agent tool nodes, step test, and read-only card

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* chore: remove ai_agent resource type migration, sync from hub instead

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* chore: remove AI agent eval suite and run endpoint, defer to later

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* chore: unwire eval routes, types and UI (completes eval removal)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* docs: update reusable AI agents guide for eval removal and tool rebinding

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* chore: regenerate system prompts for AIAgent agent/tool_inputs schema

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* fix: strip brain transforms on link, avoid dirtying flow on tool open

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* fix: flow-local test form and linked-agent marker in read-only graph

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* fix: store linked tool overrides as diff from resource base

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* feat: resolve linked agent tools in read-only viewer with fallback

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* fix: use operating workspace, block non-static provider, warn on unbound tool inputs

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* fix: resolve linked parent's tools from resource for nested agent tool lookup

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* fix: scope linked-agent tools by flow path, thread workspace to path check and embedded viewer

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* fix: strip flow-context tool inputs on agent save, drop unbound-inputs warning

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* fix: persist agent edit mode across tool selection, show linked tool code read-only

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* feat: show linked agent resource path in node definition panel

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* refactor: edit linked tool inputs in step panel, make tool nodes display-only

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* refactor: wire step-panel tool bindings (completes display-only pivot)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* fix: single scroll for linked card, agent path as node label, drop fill-inputs in tool cards

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* style: align linked-agent UI with design tokens and components

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* fix: separate linked tool select target from module id to unbreak agent clicks

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@aanthropic.com>

* fix: save agent tool inputs verbatim, host flows override via tool_inputs

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* fix: scope agent edit state by flow path, require linked-tools scope at init

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* fix: block saving an agent whose static provider is incomplete

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* fix: type errors in agent tool bindings and save drawer input

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* fix: key agent edit state by workspace, resync tool bindings on external changes

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* fix: include workspace in linked-tools scope and tool schema fingerprint

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* fix: remove unused workspace prop from FlowModuleSchemaMap

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* refactor: drop linked-agent placeholder tool node, path label suffices

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* fix: workspace-qualified resource links, guard stale tool schema loads

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* fix: keep flow tool overrides out of the agent on edit, fold only on unlink

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* fix: fold preserved tool overrides into the step on edit cancel

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* fix: refuse overwriting non-agent resources on save, show memory kind on linked card

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* fix: consume picker value, invalidate edit state on undo/reinit, cap nested agent tools

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* fix: guard in-flight edit fork against restores, migrate edit state on rename

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* refactor: validate agent edit state by fork identity instead of path keys

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* fix: key agent edit entries by fork marker alone, immune to editor nesting

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* fix: keep agent edit state across structural graph edits and flow renames

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01B6kq9PYqNdc5q7ubidBYAs

* fix: centralize agent edit reanchor, guard in-flight saves, seed rename scope from flow path

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01B6kq9PYqNdc5q7ubidBYAs

* fix: ancestry-keyed edit reanchor and doc-scope sweep for republished linked tools

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01B6kq9PYqNdc5q7ubidBYAs

* fix: guard stale linked-tool fetches and resolve while-loop nested linked agents

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01B6kq9PYqNdc5q7ubidBYAs

* fix: drop empty tool override entries on revert and correct stale viewer comment

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01B6kq9PYqNdc5q7ubidBYAs

* docs: drop stale eval mention from the linked-agent comment

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* fix: deploy linked agent resource, guard viewer fetches, align tools schema

Address review findings on the reusable-agent branch:

- Cross-workspace deploy never collected a linked step's `agent` resource, so
  the deployed flow failed at runtime unless the agent already existed there.
- The read-only viewer published resolved tools without the generation guard
  flowState uses, letting a superseded link's tools win a race. Share one
  guarded publisher (`publishLinkedAgentTools`) between both call sites.
- `tools` was still required in the OpenFlow AiAgent schema while the
  deserializer defaults it, rejecting hand-authored linked steps; make it
  optional and narrow the call sites.
- Overlay `tool_inputs` in the non-linked branch too, so a flow persisted
  while a step sits in "Editing" mode still binds tools to this flow.
- Cap the linked-tools store's scope map; nothing evicted it before.
- Drop the orphaned `.sqlx` entry left by the eval removal, regenerate the
  copilot OpenFlow schema, and fix the generator's nested-`z.record` arity.
- Move `refreshFlowStateStore` out of `agentEditStore` into its own module.
- Document that linked agents' tool scripts are outside the lock pipeline.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* chore: regenerate system prompts for optional AIAgent tools

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* fix: follow saved-agent deps on deploy, accept the linked shape in the schema

Round-18 review findings:

- Deploying a linked flow queued only the outer ai_agent resource. Follow
  `$res:` refs inside a resource value (every UI-saved agent has a provider
  resource) and the agent's own tools, which reference scripts, flows, MCP
  resources and nested linked agents by bare path.
- The AiAgent input_transforms schema still required provider/output_type,
  so it rejected the very shape linking persists (brain transforms stripped,
  flow-local inputs kept). Only user_message is always present.
- dfs traversed `value.tools` unconditionally through a cast, which throws on
  a linked module that omits it now that the field is optional.
- Trim the flow-refresh invariant comment to the 4-line limit.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* fix: recurse into inline nested agent tools on deploy, require provider when unlinked

Round-19 review findings:

- The deploy walk only inspected a saved agent's top-level tools, so an inline
  nested agent tool's own scripts, flows and MCP resources were skipped.
  Recurse into it; a linked one is still queued as a resource instead.
- Normalize a `$res:`-prefixed MCP tool resource_path like other refs.
- Dropping provider/output_type from the schema's required list also let a
  standalone providerless agent validate, which deploys clean and then fails
  on every run. The constraint can't go in the schema: an `anyOf` makes
  AiAgent a union, which breaks the FlowModuleValue discriminated union it
  belongs to (verified: zod throws "Invalid discriminated union option").
  Enforce it in validateFlowModules instead, next to the other cross-module
  checks, via a shared collectProviderlessAgentIds.
- Correct the deploy paragraph in the docs: provider resources are traversed
  now.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* fix: follow linked tool_inputs overrides on deploy, untrack vitest artifact

Round-20 review findings:

- A linked step's `tool_inputs` override replaces the resource tool's default
  at runtime, so a static `$res:`/`$var:` override is the dependency the flow
  actually uses. The deploy walk queued only the saved agent, leaving runs in
  an empty target workspace to fail on the missing override target. It also
  never scanned an aiagent module's own input_transforms, since the scan was
  gated to script/rawscript/flow.
- Extract the pure walkers to deployDependencies.ts and cover them: three
  rounds have each found a further gap in this one function.
- Untrack a vitest cache artifact committed by accident, and ignore a
  repo-root node_modules/ (only per-package paths were listed).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* fix: collect inline agent provider and tool deps, correct tool_inputs docs

Round-21 review findings:

- An inline agent's provider credential sits inside an object-valued static
  transform, so the top-level string check missed it and such a flow deployed
  without its provider. Walk transform values instead of string-matching them.
- An inline agent's own tools were only partly reachable: getAllModules drops
  MCP and websearch tools, so their resources were never queued. A standalone
  agent module now recurses through agentResourceDependencies, and the module's
  own input_transforms are scanned inside aiAgentModuleDependencies so one
  function owns the whole step rather than splitting it with the caller.
- `tool_inputs` was documented as empty/absent for non-linked steps, which
  contradicts the runtime applying it when `agent` is unset so a flow persisted
  mid-Edit keeps its bindings. Describe that case in both the Rust doc and the
  OpenFlow description.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* fix: keep linked steps brain-free on load, gate stale agent fetches, log linked tools

Round-22 review findings:

- loadSchemaFromModule filled every AI agent schema key with a placeholder
  transform, re-adding provider/memory to a linked step that deliberately
  carries none — persisted on the next save and rejected by the generated
  Copilot schema. Fill only the flow-local keys when the step is linked.
- The linked-resource fetch was neither aborted nor tagged, so switching a
  step from agent A to B could publish A's tools under B and show A's brain
  next to B's link. Tag each result with the (workspace, path) it was fetched
  for and drop the ones that no longer match.
- "Test this step" passed no tools for a linked agent, and the log viewer
  drops tool_call entries it cannot resolve to a definition, so the agent's
  invocations vanished from the log. Pass the resolved resource tools.
- Correct the cancel-edit comment: the runtime does apply tool_inputs on an
  unlinked step, and folding is what leaves nothing for it to overlay.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* fix: pin the edit session across saves, resolve linked tools in the run viewer

Round-23 review findings:

- Cancel stays enabled while a save awaits its requests, and it keeps the
  `tools` array identity, so the old guard passed and the completing save
  relinked the step and cleared the edits Cancel had just kept. It also
  accepted any replacement edit marker. Pin the path being saved and require
  the marker to still hold it, which still tolerates a content-preserving
  refresh re-anchoring the marker onto a clone.
- Resolve linked agents' tools in the run/status viewer too: it reads
  module.value.tools straight from raw_flow, which is empty for a linked step,
  so AIAgentLogViewer dropped every tool_call it could not match and the graph
  drew the agent with no tool nodes. Same gap the previous commit closed for
  "Test this step" only.
- Drop the overlay call-site comment: it claimed resource defaults are
  discarded and unmatched keys ignored, while overlay_tool_inputs preserves
  defaults and inserts new keys, as its own test asserts.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* fix: scope linked tools without the trigger-node path, keep the standalone save guard

Round-24 review findings, both regressions from the previous commit:

- Passing `path` to the run viewer's graph also switched on its Trigger node
  (`triggerNode ? path : undefined`), which reads a TriggerContext that
  /run/[...run] does not provide — the page threw "Cannot read properties of
  undefined (reading 'triggersCount')". Give the graph a separate
  `linkedToolsPath` for the tools bucket so the two stay independent.
- The rewritten save guard tracked only the edit path, so a plain "Save as
  agent" no longer noticed the step being replaced mid-request (undo, session
  sync): the replacement has no edit path either, so the stale completion
  relinked it and stripped its brain. Keep the array-identity check when there
  is no edit session, and use path re-anchoring only when there is one.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* fix: keep recorded tool calls in run history, send tool_inputs from step previews

Round-25 review findings:

- The agent log viewer dropped any recorded tool_call whose definition it
  could not find among the supplied tools, so renaming or removing a tool —
  or losing read access to a linked agent's resource — erased calls that had
  actually run. Render the recorded call labelled by its function name; its
  args, logs and result come from the child job, not the definition.
- "Test this step" sent tool_inputs only for a linked step, but a step forked
  for editing has no `agent` while still carrying the flow's bindings, which
  the runtime overlays. The preview ran resource-authored defaults instead of
  the bindings under test. Send them from both branches.
- Polling a running flow replaces `job` every tick, so the run viewer re-read
  every linked agent's resource each time. Key the fetch on the set of linked
  steps instead.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* fix: never discard edits made during a save, isolate the run viewer tools bucket

Round-26 review findings:

- The agent editor stays live while a save is in flight, so edits made after
  the snapshot were not in the resource yet linking stripped them from the
  step too, losing them outright. Compare the config against the snapshot on
  completion and, if it moved, leave the step alone and tell the user to save
  again.
- The run viewer published into the editor's `${ws}:${flow path}` bucket, so
  opening an older run in the preview pane could flip the edited flow's tool
  nodes to that run's agent. Key it by job instead.
- Drop the now-unreachable undefined filter in the agent log viewer.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* fix: claim the linked-tools generation on direct publishes and clears

Round-27 review findings:

- The step editor wrote resolved tools (and cleared them on unlink) straight
  into the store, leaving the fetch generation untouched. An older in-flight
  load for the previous agent then still passed its own check and overwrote
  them, so the graph and binding editor could show agent A while the step
  links to B. Claim the generation before those writes.
- Correct two comments that still described unmatched tool calls as dropped;
  they are kept and labelled by their recorded name.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* fix: retain the loaded linked agent, rebuild run logs when tools resolve

Round-28 review findings:

- Rejecting a superseded resource response left the card with nothing: a late
  reply for a previous agent replaces `linkedResource.current` and no refetch
  follows, so the linked step lost its brain, tools and provider warning until
  remount. Retain the last response that matched the current link instead.
- The agent log viewer built its module list on mount only, so a linked
  agent's asynchronously resolved tools never replaced the placeholders, and
  switching between completed runs reused the first snapshot. Rebuild on a
  value key — callers rebuild the agentJob object each render, so tracking its
  identity would reload in a loop.
- Refresh a linked-tools scope's recency when it is read, not only when it is
  published: a run viewer opens one bucket per nested job, which could
  otherwise evict the bucket a still-displayed run is using.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* fix: supersede stale log reloads and stale tools on a link change

Round-29 review findings, both on the reloads added last round:

- Every prop change starts another loadToolCalls, and it awaits child-job
  requests before writing the shared view, so a slower reload for a previous
  run could restore its logs and tool states over the run now selected — or
  replace newly resolved definitions with an earlier empty-tools snapshot.
  Build the states locally and let only the newest load publish, including the
  parent's index-keyed job cache.
- While a newly linked agent resolves, the previous agent's tools stayed in
  the store, so its bindings were editable against a step already linked
  elsewhere, and a failed load left them indefinitely. Clear them once the
  link moves away from what this component published; tools resolved at flow
  load are untouched, so selecting a step still doesn't flicker.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* fix: resolve a run's linked agents in the run's own workspace

Round-30 review finding: the run viewer fetched linked agent resources with
the navigation workspace, but session and fork previews render it with
`workspaceId` pointing elsewhere. Those runs resolved nothing — or an
unrelated resource sharing the path — losing tool nodes and log definitions.
Prefer the explicit override, then the job's own workspace. The store scope
stays keyed on `workspace` so it still matches what FlowGraphV2 reads; the
job id in the key already makes the bucket unique.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* fix: refetch a run viewer's linked tools if its scope is evicted

Round-31 review nit: the viewer publishes one scope per mounted nested job,
hidden ones included, so a loop with many loaded iterations can push a
displayed scope past the store's cap. Nothing refetched it afterwards — the
set of linked steps had not changed — leaving the run without tool nodes or
log definitions. Track the store and republish when the bucket is gone;
publishing always writes a key, so this settles instead of looping.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* fix: retain in-use linked-tool scopes instead of refetching evicted ones

Round-32 review findings. Republishing an evicted scope settles for one
scope but not against the cap: with more than 32 mounted nested jobs holding
linked agents, restoring one necessarily evicts another, and that mutation
reran every viewer's effect — an endless round of resource requests.

Hold a scope for as long as a viewer is mounted and skip retained scopes when
evicting, so buckets in use are never dropped and nothing has to refetch. The
cap yields to correctness when everything mounted is in use.

Dropping the publish key also restores refetching when the fetch workspace
changes for an otherwise unchanged job and link.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* fix: guard non-static brain edits during save, retain every displayed scope

Round-33 review findings:

- The in-flight edit guard compared the saved config, which holds only static
  brain values. A computed system prompt, memory or temperature changed while
  the save was awaiting the API therefore compared equal, and linking stripped
  it with no warning. Compare what linking actually discards — every brain
  transform and the tools — leaving the flow-local inputs free to change.
- Retaining run-viewer scopes made them fill the cap, and eviction then picked
  any unretained scope, including the editor bucket a user is looking at, with
  nothing to refetch it. Retain the scope each graph draws from for as long as
  it is mounted, so every displayed bucket is protected.
- A failed agent job has no parseable action list; the loader returned early
  and left the previously selected step's tool tree under the new header.
  Clear the view instead.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* fix: resolve only flow modules in viewer scans, prune scopes on release

Round-34 review findings:

- Both viewer scans used the default dfs, which descends into agent tools, and
  published each linked agent under its bare id. Tool ids imported from a
  resource are not flow-global, so a nested linked agent sharing an id with a
  top-level step superseded that step's fetch and showed its tools instead.
  Scan flow modules only — the graph resolves the store per module node.
- Scopes skipped while retained were never reconsidered, so closing views left
  the store over its cap for the tab's life. Prune on release too.
- Correct two comments that still argued the premises the retain mechanism and
  the read-recency policy replaced.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* fix: don't report success when a save left the step unlinked

Round-35 review nits:

- persist warns that changes made during the save are not in the resource and
  leaves the step alone, but both callers then toasted success unconditionally,
  burying the only actionable message. Report whether the step was linked.
- Condense the tool_inputs invariant to the four-line limit.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* fix: seed the published link at mount, keep run history for toolless agents

Round-36 review findings:

- `publishedFor` started unset, but initFlowState has already published for the
  step's link by then. A link change landing before this component's own
  request therefore skipped the clear, leaving the previous agent's tools under
  the new link — indefinitely if the new one fails. Seed it from the link at
  mount.
- A standalone agent that omits `tools` kept `undefined` here, and the gate
  downstream then hid the AI message and tool-call history behind the generic
  result view. Default to an empty list like the other consumers.
- A save that lands after the step was replaced writes the resource but leaves
  the step alone; say so instead of closing the drawer with no outcome.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* fix: qualify nested agent tool store keys, keep an empty tools identity stable

Round-37 review findings:

- The step editor keyed the linked-tools store by the bare module id for
  nested agent tools too. Those ids come from a resource and are not
  flow-global, so a nested linked agent sharing an id with a top-level step
  read that step's tools — then overwrote them once its own fetch landed.
  Qualify the key by the parent agent, as the edit store already does; flow
  modules keep the bare id the graph looks up.
- The `tools` binding handed the editor a fresh [] on every read when the
  module omits the field — a shape this PR made valid — so the save guard's
  identity check never matched and such a step could never link. Read through
  one shared empty array instead.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* fix: accept the first tool on an agent module that omits tools

Round-38 review nit: the graph's tool insert required an existing `tools`
array, so a module authored without the field — valid since `tools` became
optional — swallowed the insert while still pushing history and dispatching a
change. Create the array on first use.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* fix: don't evict a scope on the write that created it, and cover the store

Round-39 review findings:

- A rename removed the retained old key from the order but the new one is not
  retained until readers re-run, so eviction deleted the fresh bucket
  immediately. Reorder without evicting; the next publish or release enforces
  the cap, by which point the new key is held.
- Writing the test for that surfaced the same shape in touchScope: it evicts
  right after appending, so once every older scope is retained the scope just
  published was the only eligible victim and was dropped at once. Exclude the
  scope being written.

Add the store's first test: retention, eviction past the cap, pruning on
release, and the rename handoff — four rounds landed fixes here with nothing
pinning the behaviour.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* fix: re-resolve linked agents when a wholesale edit changes the links

Round-40 review findings:

- Undo/redo, YAML apply, AI apply and session restore swap a step's `agent`
  without re-running initFlowState, and the step editor only watches the step
  it is mounted on — so an unselected step kept showing, and binding against,
  the previous agent's tools. Re-resolve from the editor whenever the set of
  links changes.
- Document that linked resolution is live rather than pinned: an edit landing
  mid-run affects steps that have not started, and a nested agent tool looks
  its definition up by id when its own job starts, so it can run a changed
  definition. Pinning would mean carrying the resolved definition into the
  child job instead of its id; inline agents are unaffected because their
  tools are snapshotted with the flow value.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* fix: per-module empty tools identity, invalidate tools when a link is replaced

Both findings are over-corrections in the two preceding commits:

- The shared empty-tools array made identity stable, but stable everywhere: a
  wholesale edit that keeps the module id reuses the component, so when both
  the old and the replacement module omit tools the save guard saw no change
  and could link and clear the replacement. Hand out one empty array per
  module value, which a replacement always renews.
- The editor's link watcher resolved the replacement agent without dropping
  the previous one's tools first, so a step selected before the fetch landed
  still showed agent A under link B — and the freshly mounted editor seeds
  itself from B, so it could not tell. Clear the entry when the link for a
  module changes, seeding the map from the graph so the first run doesn't
  refetch what initFlowState just resolved.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* fix: reserve graph space for linked tools, re-resolve only changed links

Round-41 review nits:

- The layout reservation read the module's own `tools`, which is empty for a
  linked agent, so its display-only tool nodes were drawn over the node above
  in read-only viewers. Count the resolved tools for a linked step.
- The editor's link watcher refetched every linked agent on each run. Resolve
  only modules whose link actually changed, and skip the pass entirely on a
  rename, where the scope sweep has already carried the buckets over.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* fix: protect a renamed scope until it is retained, drop the phantom tool row

Round-42 review nits:

- Readers release the old scope before retaining the new one, so a migrated
  bucket is unretained in between and, over the cap with everything else held,
  was the only thing eviction could take. Protect a just-migrated scope until a
  reader retains it, and cover that release/retain order in the store test.
- The layout reserved an add-tool row for linked agents, which have no add-tool
  node, leaving dead vertical space. Match computeAIToolNodes.
- Re-resolving links no longer short-circuits on a rename: comparing each
  module still costs nothing when only the path changed, and a restore that
  renames and relinks in one tick now gets both.
- Hoist the duplicated linked-tools lookup in the graph's store update.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* fix: kill a scope's in-flight fetches before migrating it

Round-43 review finding: fetch generations are keyed by (scope, module), so a
resolution still running against the pre-rename scope keeps a valid generation
there. It publishes into the old bucket after the rename, and the doc-scope
sweep — which gives the source precedence — carries it forward over a link
resolved since under the new scope, leaving the graph and binding editor on the
previous agent's tool ids with nothing to refetch them.

Invalidate the source scope's fetches before each migration, and pin the
behaviour: the new test fails without the invalidation.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* fix: re-resolve links a scope sweep cancelled, and only sweep a real bucket

Round-44 review findings, both on the previous commit:

- Invalidating the source scope killed fetches that were perfectly current —
  a link still loading when the rename landed — and nothing restarted them,
  because the watcher already records that link. Resolve again, in the
  destination, every link the migration left without tools.
- The doc-scope sweep ran on every store version bump, so during a draft
  refresh the first completed fetch cancelled the others mid-flight. Skip the
  sweep entirely when the source scope holds nothing.
- Condense a six-line invariant to the four-line limit.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* fix: split rename from doc sweep, hide brain fields of nested linked agents

Round-45 review findings:

- Two reviewers disagreed about invalidating a scope whose bucket is empty,
  because the two callers differ. A rename is a cut-off: every fetch still
  running against the old scope is stale whether or not anything resolved
  there, so it always invalidates. The doc-scope sweep has no cut-off — those
  fetches belong to the refresh in progress — so it still waits until that
  scope holds something.
- Recording the swept links as published undid the rename+relink fix: a
  restore that renames and swaps a link in one tick would keep the previous
  agent's tools with nothing to refetch them. Leave that comparison to the
  watcher, which compares links rather than presence.
- A nested agent that is itself linked was offered the whole agent schema in
  the tool bindings, but the runtime overlays only its flow-local inputs, so
  the rest were collected and dropped. Show what actually applies.
- Condense the hybrid-linking comment to the constraint.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* fix: don't resolve a shared agent's tool defaults when loading it

Round-46 review finding: the whole agent resource was interpolated before
tool_inputs was overlaid, so each tool's default `$res:`/`$var:` resolved
first. A host flow overriding a default that points at the author's resource
still had to resolve that resource, and an unused tool whose default is
unreadable in the consumer's permission context failed the agent outright —
defeating the point of sharing an agent across contexts.

Read the resource raw, overlay the host's overrides, and interpolate only the
brain; each tool resolves its effective inputs when it executes. The nested
tool lookup reads raw too, since it only needs definitions.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* fix: interpolate the brain before overlaying caller inputs

Round-47 review findings, all on the previous commit:

- user_message and user_attachments were inserted before interpolation, so
  they went through it a second time: a user message of `$WM_TOKEN` expanded
  to the job token and was sent to the model provider. Interpolate the
  resource first, then overlay the already-resolved flow-local inputs.
- The relink watcher skips tool nodes, so a linked agent nested as a tool kept
  the previous agent's entry through undo, YAML/AI apply or a session restore,
  and the step editor seeds itself from the new link and cannot tell. Emit the
  ancestry-qualified key for those too.
- Correct the guide, which still named the interpolation path this branch
  replaced, and condense two invariants to the four-line limit.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* fix: deploy $jsonvar deps, key run logs by tool identity, seed only top links

Round-48 review findings:

- The deploy walkers recognised `$res:` and `$var:` but not `$jsonvar:`, which
  the worker resolves too, so a secret referenced that way by an agent brain,
  a saved tool default or a host override never reached the target workspace.
- The run log rebuilt only when a tool's name or the tool count changed, so a
  refreshed resource that altered a tool's path, code or id behind the same
  name kept showing the old definition. Key on the array identity instead: the
  store swaps it exactly when the contents differ.
- Nested linked agents were seeded as already published, but initFlowState
  resolves only top-level links, so their tools never loaded until their
  editor was opened. Seed what initFlowState actually publishes.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* fix: let the watcher's fetch survive the step editor's stale-clear

Round-49 review nits:

- On a relink the step editor claimed the fetch generation before clearing the
  previous agent's tools, which discarded the watcher's already-running fetch
  for the new link. The tool nodes then only appeared if the step stayed
  selected until the editor's own refetch landed. Clear without claiming: the
  watcher superseded the old fetch when the link changed, so nothing stale can
  return. Unlink still claims, since no watcher fetch covers it.
- Condense the store's opening invariant to the four-line limit.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* docs: condense the stale-clear invariant

Round-50 review nit. Also records why the branch deliberately doesn't claim a
fetch generation: a reviewer asked for the opposite this round, but writing
`agent` re-runs the editor's watcher, which supersedes the old fetch and
starts one for the new link — claiming here would discard it.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* fix: guard Edit/Unlink by step identity, not just the link path

Round-51 review finding: forkFromResource compared only the agent path after
its fetch, so a module replaced mid-request while keeping the same link passed
the check — the stale continuation then wrote the fetched brain and tools into
the replacement and unlinked it. Compare the step's own `tools` array too,
which is one instance per module value and so identifies the step.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* fix: report an Edit or Unlink abandoned because the step changed

Round-52 non-blocking note: forkFromResource returns undefined when the step
was replaced mid-request, and both callers treated that as do-nothing, so the
click looked ignored. Say what happened, as the save path already does.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-authored-by: hugocasa <hugo@casademont.ch>
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@aanthropic.com>
2026-07-28 01:38:16 +02:00
Ruben Fiszel 727d22b9a1 fix(wac): report a task failure the child round's body catches (#10366)
* fix(wac): report a task failure the child round's body catches

* chore(wac): state the child-round failure invariant once

* test(wac): pin the catch-then-continue re-raise in the child round
2026-07-28 00:23:04 +02:00
Guilhem 350eb66560 fix: loop "Test an iteration" progress bar, while-loop modules and schema (#10357)
* fix: hide loop iteration progress bar until a test job runs

* fix: test an iteration on while loops ran no steps and showed the for-loop schema

* fix: mirror iter.value from iter.index in while loop iteration previews

* fix: default while loop preview iteration to index 0 like a real first iteration

* feat: describe and constrain the iter fields in the loop iteration drawer

* docs: describe iter as the loop iterator in the iteration drawer

* fix: clamp while loop preview index to a whole non-negative iteration
2026-07-27 22:33:36 +02:00
Guilhem 8a96e3a4ec fix: raw apps with no stylesheet were permanently un-deployable (#10364)
* fix: raw apps with no stylesheet were permanently un-deployable

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* fix: keep js strict when defaulting the raw app bundle css

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* test: drop ephemeral narration from raw app bundle regression test

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* test: pin the extension each raw app bundle half is fetched under

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-27 22:32:57 +02:00
Ruben Fiszel 621718b32f fix(ai): resolve deployment-pinned Azure base URLs to the v1 surface (#10362)
An Azure OpenAI base URL naming a deployment, such as the
`https://<res>.openai.azure.com/openai/deployments/<id>` format that
`openai_azure_base_path` documents, was appended to as-is. That names the legacy
surface, which serves only with an `api-version` query and answers 404 without
one, so both the proxy and the AI agent step reached a route that does not exist.

Such a base now resolves to the resource root and the v1 surface, like every
other Azure shape. The deployment in the URL is redundant there: the v1 surface
takes it from the request body. `azure_foundry_root` recovers the root the same
way, so a Foundry resource on such a base builds its Claude URL from the root too.

The instance-settings help text promised the URL pins the model for every
workspace, which that surface never delivered; it now says where the model comes
from.

Verified against a live Azure OpenAI resource: the previous URLs 404 and the ones
built now return 200.

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-27 22:31:36 +02:00
Ruben Fiszel 3b4c648e4a chore(main): release 1.773.0 (#10363)
* chore(main): release 1.773.0

* Apply automatic changes

---------

Co-authored-by: rubenfiszel <275584+rubenfiszel@users.noreply.github.com>
v1.773.0
2026-07-27 19:04:24 +02:00
Ruben Fiszel 7973549e7f feat: list draft-only runnables on the homepage again (#10361)
* feat: list draft-only runnables on the homepage again

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* perf: trim the draft listing index to the columns that measure

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* fix: address review findings on draft-only runnables

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-27 18:17:32 +02:00
Ruben Fiszel 86e7f18f09 chore(main): release 1.772.0 (#10346)
* chore(main): release 1.772.0

* Apply automatic changes

---------

Co-authored-by: rubenfiszel <275584+rubenfiszel@users.noreply.github.com>
v1.772.0
2026-07-27 16:57:27 +02:00
Ruben Fiszel 4145e6f162 feat: hide empty owners from the homepage chips and cap them at 20 (#10360)
* feat: hide empty owners from the homepage chips and cap them at 20

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* fix: address review nits on the homepage owner chips

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-27 16:56:00 +02:00
Ruben Fiszel 6e56ce11db fix(ai): make the proxy and the AI agent step read a resource the same way (#10359)
The two paths derive the endpoint and the credential header independently, so a
resource could authenticate in one and 401 in the other. A parity test pins them
together across the provider/platform matrix and fails on each divergence below.

- Anthropic base URLs were read differently: the proxy trimmed and re-appended
  `/v1` while the agent step appended `/messages` to the stored value, so a
  `.../anthropic` base worked in workspace settings and 404'd in an agent step.
  `build_anthropic_api_url` accepts both forms for both paths, and the URL no
  longer depends on the client-supplied `X-Anthropic-SDK` header, which is gone.
- A base URL stored with a trailing slash doubled it in an agent step.
- An OpenAI resource pointed at Azure got Azure's URL layout and `api-key`
  header from the proxy but bearer auth and the plain path from the agent step,
  where `OpenAIQueryBuilder` ignored `is_azure`.
- The agent step sent an empty credential when the resource had no api key,
  where the proxy sends none at all. `retain_effective_credentials` gives both
  the same rule, so an endpoint that authenticates another way still works.
- An OAuth resource cannot resolve to a token in a worker: there is no client
  credentials exchange there, so it now fails with that reason unless it carries
  the credential header its provider reads.

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-27 16:38:13 +02:00
Ruben Fiszel b9960267bb fix(cli): resolve module script metadata on windows path separators (#10358)
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-27 16:00:08 +02:00
Ruben Fiszel ebf68d7970 fix(ai): support OpenAI/Anthropic-compatible gateways in workspace AI settings (#10356)
* fix(ai): stop breaking OpenAI-compatible gateways in workspace AI settings

The workspace/instance AI proxy sent credentials in a shape that
OpenAI-compatible and Anthropic-compatible gateways reject, while the same
resource worked in an AI agent step:

- `is_azure` treated *any* OpenAI base URL other than api.openai.com as Azure,
  so a gateway got the Azure `api-key` header instead of `Authorization: Bearer`
  and an `/openai/v1/`-rewritten path. Match on the host instead.
- The Anthropic proxy sent both `authorization: Bearer` and `X-API-Key`.
  Gateways reject ambiguous credentials; send only the header the endpoint
  expects, matching `get_auth_headers` and the agent-step path.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* fix(ai): match Azure on the endpoint and let resource headers own auth

Review follow-ups:
- Azure OpenAI reached through a custom domain keeps its `/openai/deployments`
  path, which `openai_azure_base_path` documents; match on it so those
  instance-wide settings are not reclassified as plain OpenAI-compatible.
- Cover the sovereign-cloud API Management suffixes and FQDNs with a trailing
  dot.
- A resource that supplies its own `authorization`/`x-api-key` header now
  suppresses the built-in one. Outgoing headers are appended rather than
  replaced, so both credentials used to travel, which is exactly what gateways
  reject; this is the escape hatch for endpoints wanting bearer auth.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* fix(ai): give the agent step the same resource-header credential rule

Review round follow-ups:
- `ai_executor` appended the query builder's credential header alongside the
  resource's, so an AI agent step still sent two credentials where the proxy now
  sends one. Both paths share `resource_owns_credentials`/`CREDENTIAL_HEADERS`;
  non-credential headers such as `anthropic-version` are kept.
- Cover the OpenAI-compatible proxy's suppression branch with a test.
- Match the Azure deployments path case-insensitively, like the host.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* fix(ai): scope the credential override to the header the provider uses

A resource header now replaces the built-in credential only when it is the same
header the provider authenticates with, or an `authorization` one (which every
endpoint reads as the credential). Matching any credential-shaped header let an
OpenAI-compatible resource's `x-api-key` routing header suppress the bearer
token. Google AI's `x-goog-api-key` joins the list so the override reaches that
provider too.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* refactor(ai): share credential and trailing header assembly across AI paths

The proxy and the AI agent step each assembled outbound headers themselves, so
this fix had to be applied at three sites and the rules could drift apart
silently. Two pieces move into `proxy`:

- `credential_header` picks the credential to send, applying the resource
  override. `authorization` carries a bearer token and every other credential
  header carries the raw key, which holds for every provider.
- `common_outbound_headers` yields Windmill's own headers then the resource's,
  the tail every outbound request shares.

A resource resolves to an api key or an OAuth token, never both, so selecting
one drops the branch that could emit two `authorization` headers.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* fix(ai): keep OAuth tokens on the bearer header

An OAuth resource resolves to an access token, which every provider reads from
`authorization` — Azure OpenAI accepts api keys in `api-key` but Entra ID tokens
only as a bearer. Sending it in the provider's key header left Azure OpenAI and
Foundry Claude OAuth resources unauthenticated.

Also covers the credential-override narrowing: a credential-shaped header the
provider does not authenticate with is an ordinary header and must not suppress
the built-in credential.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-27 15:23:49 +02:00
Ruben Fiszel 50da65c886 feat: show per-owner runnable counts in the homepage tree (WIN-2253) (#10351)
* feat: show per-owner runnable counts in the homepage tree

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* fix: exclude pipeline members from runnable owner counts

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* fix: address review findings on runnable owner counts

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* fix: avoid tree reflow while counts load and label pipeline rows

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* fix: drop collapsed owners' cached rows when the tree scope changes

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* fix: untrack tree owners whose node is removed

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-27 14:57:54 +02:00
Ruben Fiszel f9d5da11b7 feat: allow changing an account email in the superadmin settings (#10355)
* feat: allow changing an account email in the superadmin settings

* fix: cover slack_email and usage rows, and scope job rewrites to the queue

* fix: compare the destination email case-insensitively

* fix: only warn about the consequences once the email is edited

* docs: warn that changing an account email is a last resort

* fix: repoint app policies and raw-email permissioned_as, reject self-change

* fix: repoint folder default rules and guard the varchar(55) job column
2026-07-27 14:54:23 +02:00
Ruben Fiszel cdd8718a93 fix(cli): sync push no longer reports success on a script it never deployed (#10353)
* fix(cli): do not report success when sync push drops a script metadata change

`sync push` skipped every added `.script.yaml` / `.script.json` / `.script.lock`
on the assumption that the sibling content file in the same group carried the
deploy. When the content file was not in the changeset — e.g. filtered out by
`excludes` — nothing was sent to the remote, yet the push still printed
"Done! All N changes pushed" and exited 0, so CI gating on the exit code went
green on a deploy that never happened.

Route those changes through `handleScriptMetadata` (as the "edited" branch
already does), which resolves the content file from disk and deploys it. The
deploy stays idempotent via `alreadySynced`, and a metadata file with no content
file now fails the push instead of being counted as pushed.

Fixes WIN-2254

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* fix(cli): treat only the module entry point as script metadata

`handleScriptMetadata` / `findContentFile` matched any `script.yaml`,
`script.json` or `script.lock` anywhere under a `__mod/` tree, so a module file
nested deeper (e.g. `f/foo__mod/config/script.yaml`) was mistaken for the
script's own metadata. Gate on `isModuleEntryPoint`, which requires the file to
sit directly under `__mod/`.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* fix(cli): reject non-metadata paths in findContentFile

Every candidate-path replacement in findContentFile is a no-op on a path that
is neither flat `*.script.{yaml,json,lock}` nor a module entry point, so the
input resolved to itself and the caller got a "more than one candidate found"
list of 25 copies of the same path. Reject those inputs up front.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* fix(cli): report an unpushable script as a failure instead of aborting the push

Throwing out of the apply loop for a metadata file with no script file left the
push partially applied: every change queued behind it was dropped, including
ones with nothing wrong. Collect these into a failed list, log each one, keep
applying the rest, and report `N of M changes pushed; K failed` with a non-zero
exit (`success: false` plus a `failed` array under --json-output).

Only the content-resolution failure is soft, via MissingScriptContentFileError.
A deploy the remote rejected still aborts, since it says nothing about whether
the remaining changes are safe to apply.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* fix(cli): let stdout drain before sync push returns a failure exit code

process.exit does not wait for a pending piped stdout write, so a --json-output
push with enough changes was cut off at the 64KiB pipe buffer, handing CI
consumers unparseable JSON. Set process.exitCode instead and return normally,
matching how main.ts already reports failures.

Reproduced with a 1904-change push: process.exit truncated the result at exactly
65536 bytes; process.exitCode emits all 432KiB and still exits 1.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* fix(cli): treat an ambiguous script file as a recoverable push failure

findContentFile has two ways to fail to pair a metadata file with a script
file, and only the "none found" one threw the class sync push catches. Two
script files for the same name (a .ts and a .py both being in exts) therefore
still aborted the whole push, dropping every change queued behind it — the
failure mode failedChanges exists to prevent, newly reachable now that an added
.script.yaml reaches findContentFile at all.

Both branches now throw the same class, renamed to
UnresolvableScriptContentFileError since it no longer only covers a missing
file, and the ambiguous case gets a message that names the clashing files.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-27 13:21:50 +02:00
Ruben Fiszel a8ef98edff feat: build a React raw app from the script and flow detail pages (#10337)
* feat: build a React raw app from the script and flow detail pages

* fix: keep generated raw-app state and setter names unique

* fix: make the generated app readable on dark and handle labeled enums

* fix: reserve the undefined binding in generated raw apps

* fix: mask password args, keep __proto__ args, and enforce required inputs

* fix: quote non-identifier arg names, preserve JSX entities, support resource args

* fix: JSON-quote generated arg keys and start resource fields empty

* fix: render array enums as multi-selects and let optional enums be omitted

* fix: stop the generated template naming Math/Array and omit untouched optional json

* fix: enforce required on array-enum multiselects
2026-07-27 12:53:43 +02:00
Ruben Fiszel be5e3bbfc4 fix(wac): checkpoint step errors so a caught exception does not hang replay (#10348)
* fix(wac): checkpoint step errors so a caught exception does not hang replay

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* fix(wac): honour a step suspend the workflow body caught and swallowed

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* fix(wac): park every suspend, not only those from a failing step

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* chore(wac): keep the generated bun wrapper comment-free

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* fix(wac): park the child task-completion suspend and align error identity

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* test(wac): pin the TaskError identity of replayed step and task failures

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
2026-07-27 12:38:32 +02:00
Ruben Fiszel 78e115bee5 fix: datatable full schema hangs behind a transaction-pooling postgres proxy (#10352)
* fix: datatable full schema hangs behind a transaction-pooling postgres proxy

* test: pause the clock in the pg connection shutdown test
2026-07-27 12:32:44 +02:00