Native fs events do not propagate from Windows hosts into Linux
containers, causing Vite's HMR to stop detecting file changes.
When the DOCKER environment variable is set, Chokidar now falls back
to polling with a 300ms interval, which reliably detects changes
across the Docker volume mount boundary.
Fixes#2456
An assistant message with several produced artifacts rendered one chip each in a
non-wrapping flex row, so 3+ chips overflowed and the bubble showed a horizontal
scrollbar. Add flex-wrap + gap-y-2 (the existing per-chip mr-2 keeps the
horizontal spacing) so the chips wrap to the next line, matching the other
artifact-chip render branch.
Add Material Symbols-style SVG icons (terminal / document / document-scanner) for
code_executor, artifact_generator, and read_document so they render with an icon
like the other tools. The ToolIcon import.meta.glob resolves tool_<name>.svg by
backend tool name automatically — no registration needed.
Rename the Artifact Generator display name to "Artifact" (the internal
artifact_generator key is unchanged) and tighten the user-facing one-line
descriptions for Code Executor, Artifact, and Read Document.
Enable code_executor and artifact_generator by default in chats (added to
DEFAULT_CHAT_TOOLS) — they load via the synthetic-id path user- and
conversation-scoped like scheduler, and persist artifacts (no user_tools FK).
Make read_document an internal agent-builtin flagged workflow_only so it appears
only in the workflow builder, not the classic agent picker or the Add-Tool
catalog (reuses the builtin synthetic-id path; still run-scoped and authz-gated).
Per decision, default-on code_executor runs sandboxed code without an approval
prompt (the sandbox is the trust boundary); this is documented in settings and
the threat model, and multi-tenant deployments should add per-tenant isolation
(Daytona / gVisor / egress policy).
Wrap a storage read in a context manager (close the file handle), add a comment
on the expected SandboxCapacityError in the churn test, and unify the
artifacts-routes test on a single import style. Also annotate the intentional
per-session sandbox workspace path with # nosec B108 (controlled dir inside the
runner container, not an insecure shared temp file).
When code_executor or read_document is given an input that doesn't resolve to an
existing artifact, it now falls back to the caller's own chat attachments,
bridges the referenced one into a conversation-scoped artifact (idempotent,
server-computed size/sha256, quota-respected), and stages it. This is lazy —
plain chat uploads are never bridged, only a file a tool actually references —
and conversation-scoped only (workflow nodes bridge attachments up front).
The match is confined to the request's own attachments and re-verified against
the user-scoped attachments repo, so a model-supplied name/id can only ever reach
the caller's own files. Only the current request's attachments are reachable (the
attachments table has no conversation column); prior-turn files are a follow-up.
Remove the integration tests that launch a real Jupyter Kernel Gateway or hit
Daytona (artifact_generator / code_executor / workflow-code-node e2e, the gateway
integration test, and the Daytona live test) — these belong in a separate e2e PR
with proper harnessing. The ephemeral-Postgres integration tests (artifacts
repository, run-scoped + input-document authz) stay: they run in CI without any
external service and hold the cross-tenant coverage. Trim the now-unused
test-only deps (jupyter-kernel-gateway, ipykernel, websocket-client); keep
jupyter-client for the retained kernelspec-resolution test.
Make the doc-driven Preview flow usable and surface every produced artifact:
- A Preview submit with attachments but no text now runs the workflow (opt-in on
MessageInput; no filler text is injected), so a doc-driven workflow can be run
by attaching its documents.
- The builder's global Escape no longer tears down the whole Preview/drawer, and
no longer fires from inside text fields.
- The Preview drawer has a visible close button, and the upload toast moves off
the attach/send controls (to the left) while the Preview is open.
- A turn that produces multiple artifacts now renders one chip per artifact
(labelled by tool, indexed when several), instead of exposing only the last.
The code node's Input files and the agent node's Documents now render the same
NodeDocumentsControl: an All/None/Choose toggle, a multiselect of upstream
document/artifact refs, and a free-text add-ref escape (a typed A1/id appears as
a removable chip). The control owns its toggle state so Choose is reachable from
an empty selection — retiring the per-node parent flag. File passing stays
agent-only; the code node keeps its inputs field name and stages the selected
refs as files in the sandbox.
Replace the sandbox Docling extractor with read_document, backed by the in-process
backend parser (the same one ingestion uses) and offloaded to a dedicated
'parsing' Celery queue so it can run on GPU-capable workers with predictable RAM.
The tool resolves the input ref under the run-scoped gate, enqueues the parse,
and awaits it with a timeout (degrading to an error rather than hanging); the
worker independently re-resolves the artifact through the same gate and never
trusts a raw path. Untrusted files get the upload path's safeguards (extension
whitelist, size cap, sanitized temp file, cleanup). Options: output
(markdown/text/structured/chunks), ocr, pages, engine, max_chars, include_tables,
persist, json_schema. The workflow native-file 'extract' fallback now uses the
same worker path, so document parsing no longer needs the sandbox and works on
every backend.
Also fixes the branch's periodic-task test (the sandbox reaper made it 12) and
points the dev and e2e Celery workers at the parsing queue.
Clicking "Choose…" with nothing selected now opens the document picker. The
mode was derived purely from the stored input_documents, so an empty selection
read back as None and the picker never appeared — leaving per-node document
selection unreachable unless a value was already set. An explicit per-node flag
now keeps Choose mode active even when empty, without leaking across nodes.
An input_documents entry with no matching upstream option (a renamed or deleted
upstream output variable, or a literal ref) now appears as a removable chip in
the agent node's Choose-mode document selector instead of silently vanishing,
so the stored selection stays visible and editable.
Adds withChosenDocumentOptions to merge stored selections into the multiselect
options, with tests.