Release 2.3.0 - #74
Merged
Merged
Conversation
…#32) * fix(execution-worker): connect to TEMPORAL_ADDRESS instead of implicit localhost Worker.create without an explicit connection dials 127.0.0.1:7233, ignoring the TEMPORAL_ADDRESS env var — correct in local dev, broken in any deployment where Temporal is not on loopback. * fix(execution-worker): treat empty-conditions decision branch as catch-all The no_branch_matched error message and the Sales Inquiry reference template both treat a branch with no conditions as the explicit catch-all, but branchMatches returned false for it — any input classified outside the keyword branches failed the whole run. Supersedes the empty-conditions bullet of packages/execution-core/decision-no-match.decision-log.md (the strict fail-fast core of that decision is unchanged); see apps/execution-worker/decision-catch-all.decision-log.md. * feat(backend): add per-ip rate limit on the execute route Fixed-window, in-memory limiter (WB-229 abuse gate). Disabled unless RATE_LIMIT_EXECUTE_PER_MINUTE / RATE_LIMIT_EXECUTE_PER_DAY are set, so local dev is unaffected. TRUST_PROXY=true reads the client IP from X-Forwarded-For — only enable behind a proxy that sets it. * feat(deploy): containerize ai studio stack for production deployment deploy/ai-studio/: multi-target Dockerfile (runtime/migrate/web), production docker-compose (only nginx public, pinned images, automatic migrations), nginx SPA+API proxy with SSE tuning and per-request DNS re-resolution, .env.example with Mistral Small 3.2 default, DevOps README, and a decision log covering the architecture choices. tsx becomes a real dependency of backend and worker (start:prod runs without an .env file); .dockerignore now keeps **/.env out of build contexts. Verified end-to-end: Sales Inquiry Pipeline to execution_completed with live SSE through nginx; rate limiter returns 429 past the budget. * feat(deploy): add swarm overlay aligned with workflow-builder infra tools/deployment/ mirrors the workflow-builder repo's deployment path (build-docker.sh, deploy.sh, ansible deploy-application playbook) and consumes the same three images from deploy/ai-studio/Dockerfile — only the orchestration layer differs. Deviations forced by AI Studio being stateful: node-pinned volumes for Postgres/Temporal, post-deploy migration step (Swarm ignores depends_on), attachable internal network with short DNS aliases, and an AUTH_ENABLED-gated gatekeeper so the public demo stays login-free. Stack template render-verified in both auth modes; status 'Proposed' pending the DevOps conversation. * feat(backend): apply drizzle migrations on boot drizzle-orm's programmatic migrator runs the SQL files from apps/backend/drizzle/ before the server accepts traffic. A failure (database still starting) exits the process; container restart policies retry until it converges. drizzle-kit stays a devDependency — db:migrate remains available for out-of-band use. * refactor(deploy): drop the migrate service and image The backend migrates itself at boot, so the migrate Dockerfile target, compose service, and the Swarm playbook's post-deploy migration task (plus its attachable-network requirement) all go away. Two images remain: runtime and web. The worker now waits for the backend healthcheck so it never touches a pre-migration schema. Verified on a wiped stack: virgin database boots, backend logs 'database migrations applied' before listening, Sales Inquiry Pipeline runs to execution_completed over live SSE, rate limiter returns 429 past the budget. * style: trim comments to the non-obvious Keep only what the code cannot say itself: traps (Worker.create's implicit localhost, corepack/pnpm 10 failure, offline mode leaking into lifecycle scripts), constraints (single-replica migrator, X-Forwarded-For trust), and magic values. Drop the narration. * revert(execution-worker): move the decision catch-all fix to its own pr Reverts the empty-conditions-as-catch-all change (ccf7375) and its decision log. It changes execution semantics and supersedes a clause of decision-no-match.decision-log.md — that deserves a focused review, not a ride-along in a deployment PR. * docs(deploy): drop the deployment decision log AI Studio is a POC — the README and the comments on the non-obvious pieces carry what operators need; full architecture rationale is premature at this stage. * fix(deploy): add healthcheck, restart policies, and overlay driver to swarm stack Backend healthcheck (fetch /api/health) lets Swarm detect when migrations are done — without it the worker can hit a pre-migration schema. Explicit restart_policy on every service replaces the implicit Swarm default; crash-looping services (worker, temporal) get max_attempts. Internal network gets driver: overlay for clarity. * Add actions code * Remove old deployment code --------- Co-authored-by: Jan Librowski <jan.librowski@synergycodes.com> Co-authored-by: Jakub Kubacki <jakub.kubacki@synergycodes.com>
…ocales (#58) The selector matched the current option against the raw i18n.language, so a regional locale (e.g. pl-PL) - which equals neither 'en' nor 'pl' - fell back to the first option and displayed 'EN' while the UI rendered Polish. Match on i18n.resolvedLanguage (base language) instead. Adds a regression spec. Co-authored-by: Jan Librowski <jan.librowski@synergycodes.com>
* fix(sdk): drop the decision node's outer output port when branches exist Each branch renders its own source handle, so the node-level source port was a redundant, disconnected port on any decision node with branches. Branchless decision nodes keep it (existing diagrams route edges through it). * feat(sdk): forward maxRows on the TextArea uischema control overflow-ui's TextArea already supports it; the uischema type and control only exposed minRows, so consumers had to cap growth with CSS max-height. * fix(sdk): space out branch cards in the decision properties panel DecisionBranchesControl wrapped its cards and the add-branch button in an unstyled div, so they rendered glued together. Style the wrapper as a column with a gap, following the component-token pattern. * refactor(sdk): drop the accordion's classless-div layout hack The accordion content styled bare 'div:not([class])' children to compensate for controls with unstyled roots. DecisionBranches - the only such control - now styles its own wrapper with the same 0.75rem gap, so the selector had no remaining in-repo target and only masked missing control styling. * fix(sdk): remove the decision node's source handle entirely Execution routes only through branch handles - the decision executor sets nextPort to the matched branch or fails with no_branch_matched, so an edge from the bare source handle can never fire. Keeping it for branchless nodes only invited connections that silently dead-end; the demo's canned decision nodes are unaffected (they render as plain nodes, not this template). * docs: changesets are 1-2 sentence changelog entries Codify the rule in CLAUDE.md and tighten this branch's changesets (plus the verbose language-selector one already on main) to match: the consumer-visible change and any migration note only - rationale lives in commits and PRs. --------- Co-authored-by: Jan Librowski <jan.librowski@synergycodes.com>
The app bar hardcoded the Workflow Builder logo with no way to replace or link it, forcing consumers into hash-prefix CSS hides and fixed-position overlays. The props follow the existing render-body config-holder pattern. Co-authored-by: Jan Librowski <jan.librowski@synergycodes.com>
…search, richer templates (#48) * feat(ai-studio): auto-load flagship template and add first-visit disclaimer Replace the internal Synergy sales-inquiry template with a generic, relatable Customer Support Triage flagship (classify -> route by type -> specialist draft -> QA), built on the existing trigger/agent/decision nodes. Auto-load it on first visit via initialNodes/initialEdges on WorkflowBuilder.Root so visitors land on a runnable workflow instead of a blank canvas; a returning visitor's saved diagram still wins. Add a dismissible first-visit disclaimer modal stating the workflows run real OpenRouter calls, that the demo is not a model benchmark, and that its purpose is to showcase Workflow Builder. * chore(execution-worker): default to gemini-2.5-flash-lite for the demo Cheaper, fast default for the public demo (roughly an order of magnitude cheaper than claude-3.5-haiku). Quality-per-cost is what matters here - the model is the engine, not the product. Override with the AI_MODEL env var. * feat(backend): gate workflow execution with rate limit and Turnstile POST /api/workflows/:id/execute is the only endpoint that spends real LLM budget, so it gets a per-IP fixed-window rate limit plus an optional Cloudflare Turnstile check, applied right after authorization via guardExecution(). Both controls are no-ops when unconfigured (TURNSTILE_SECRET_KEY empty), so local dev runs unprotected; the rate limit is active out of the box as a budget backstop. Turnstile verification fails closed on a verifier error. * feat(ai-studio): attach Turnstile token to workflow execution Before the execute request, fetch a Turnstile token from an invisible widget and send it as the cf-turnstile-token header. Degrades gracefully: with no VITE_TURNSTILE_SITE_KEY the token is undefined, no header is sent, and the backend skips verification - so local dev needs no keys. * feat(ai-studio): add AI Debate, Content Repurposer and Meeting Notes templates Grow the picker into a small gallery of relatable, runnable examples beyond the flagship: AI Debate (parallel personas that fan out then converge on a verdict), Content Repurposer (one post fanned out to three channel variants), and Meeting Notes to Action Items (a linear summarize -> extract -> format chain). All use the existing trigger/agent/decision nodes. * refactor(ai-studio): rename markdown-preview node to visualize Generalize the on-canvas preview node from markdown-only to a future generic Visualizer: type ai-studio/markdown-preview -> ai-studio/visualize, palette label Visualize (Eye icon), worker domain VisualizeNode + executeVisualize + registry, flagship node preview-1 -> visualize-1. Rendering is still markdown for now; renderer set, format detection, charts, diagrams, export and expand land in the following commits. Includes the visualize plan and long-work backlog. * feat(ai-studio): detect output format for visualize Heuristic detectFormat(text) -> {renderer, data?, chartable?} mapping an output string to a renderer for the Visualize node's auto mode: mermaid->diagram, JSON->{chart for {label,value}/{type,data}, table for object arrays, stat-cards for flat scalar objects, json for nested}, CSV->table, else markdown. Conservative (chart/diagram only on clear signals), prose falls back to markdown. 11 unit tests. * feat(ai-studio): add mode param to visualize node Adds a 'Render as' select to the Visualize node: VISUALIZE_MODES = auto + markdown/text/json/table/stat-cards/chart/diagram, default auto. Auto detects the format; the rest force a specific renderer. * feat(ai-studio): json/table/text/stat-card renderers for visualize Add a renderer registry (getRenderer) with markdown, text, JSON tree (collapsible, hand-rolled), table (JSON array / CSV rows), and stat-cards (flat object) renderers. The visualize card now runs detectFormat (or the node's mode), picks the renderer, shows an 'Auto > X' badge, and renders into a framed body. chart and diagram fall back to table/text for now (real renderers land next). * feat(ai-studio): always-on visualize card with empty state The visualize card now renders for the node at all times with a fixed minimum size: an empty-state placeholder ('The visualization appears here after you run the workflow') before a run, a generating indicator while running, and the rendered output on completion. The reveal animation moved from the card frame to the content so it plays when the result arrives, not on every render. * feat(ai-studio): chart renderer (recharts) for visualize Add a lazy-loaded recharts renderer (bar/line/area/pie) for the chart mode and chart-spec envelopes ({type, data}) or {label,value}/{x,y} arrays. recharts only loads when a chart is shown (React.lazy + Suspense). The card shows a 'Try as chart' chip when auto-detected data is chartable but rendered as a table. * feat(ai-studio): mermaid diagram renderer for visualize Add a lazy-loaded mermaid renderer for the diagram mode: it renders a mermaid source string to SVG in the browser (securityLevel strict), and falls back to the raw text on a syntax error. mermaid (~150KB) only loads when a diagram is shown (React.lazy). * feat(ai-studio): export visualize output (png/svg/copy) Add export-visualization util (html-to-image): download PNG, copy image to clipboard (with a download fallback on browsers like Firefox that cannot write image blobs), copy source text, and download SVG (native serialization fast-path for chart/diagram). The card header now offers Copy image / Download PNG / Copy source actions over the rendered content. * feat(ai-studio): expand visualize to fullscreen modal Add an Expand action that opens the visualization full-size in a modal (rendered through a portal to document.body so its fixed overlay escapes the React Flow viewport transform). The modal renders the same renderer larger and offers PNG / SVG / copy-image / copy-source export. * docs(ai-studio): finalize visualize backlog and refresh getRenderer comment All visualize work items complete and verified (test/typecheck/lint/build). chart/diagram visual smoke deferred (needs a structured upstream); covered by unit tests + build (lazy chunks confirmed). * feat(ai-studio): render visualize output inside the node body Move the visualization from a detached floating panel into the node itself: the content renders in-flow inside the node body (via OptionalNodeContent), so the node grows vertically to contain it and reads as one cohesive card. Drops the redundant card title (the node header already shows it) in favor of a slim badge + export/expand toolbar; the body scrolls when the output is long. Empty state and the expand modal are unchanged. * fix(ai-studio): stop mermaid error graphics on non-diagram input Two causes of the giant 'Syntax error in text / mermaid version' graphics: - The diagram renderer called mermaid.render on invalid input, and mermaid injects its error graphic into the DOM on failure. Now it validates with mermaid.parse({ suppressErrors: true }) first and falls back to raw text (with a note) without ever calling render, so nothing is injected. - Auto-detection matched a bare leading word (graph/pie/timeline/journey), so prose starting with those was mis-detected as a diagram. Detection is now strict: a fenced ```mermaid block, or flowchart/graph WITH a direction, or a distinctive declaration keyword. Prose stays markdown. (+3 tests, 13 total) * feat(ai-studio): render embedded mermaid/json blocks in visualize Adapt mixed output to the right format without an LLM: the markdown renderer now renders a fenced ```mermaid block as a real diagram and a ```json block via the detected renderer (chart/table/...), so a markdown response with an embedded diagram renders it inline instead of as raw code. The diagram and chart renderers also extract a fenced block from a larger response when their mode is forced. * feat(ai-studio): AI adapt - LLM-convert output to the chosen format Adds an opt-in 'AI adapt' action on the Visualize node: it sends the upstream output to a new backend endpoint (POST /api/visualize/adapt) that uses an LLM to convert it into the active format (clean Mermaid / chart JSON / table / ...), then renders the result. The endpoint reuses the execution abuse gate (per-IP rate limit + optional Turnstile) and is disabled (501) when the backend has no OPENROUTER_API_KEY. Verified end-to-end: action-items prose -> clean mermaid. * feat(ai-studio): add aiAdapt toggle to visualize node config Adds an 'AI: adapt output to this format' Switch to the Visualize node's properties panel. When on, the node automatically LLM-converts the upstream output into the active render format on each run (no need to click the on-card button, which is hidden while the toggle is on). Off keeps the manual on-card adapt button for structured formats. * feat(backend): stronger visualize adapt prompts for better conversion The format-adapt prompts were terse and gave the model little guidance, so conversions were mediocre on a small model. Each format now has detailed, role-framed instructions (pick the fitting diagram type and quote labels safely; find a category + numeric measure and aggregate for charts; extract 2-8 KPIs for stat-cards; use only facts, no invention) plus temperature 0.2 and output trim. JSON renderers also strip a fenced block in case the model wraps the output. * feat(ai-studio): render markdown in table cells and stat-card values LLM-produced field values often contain markdown (bold, lists, links, inline code). A new RichText helper renders such strings as markdown in table cells and stat-card values, while leaving plain strings (e.g. 'user_id') untouched so they are not mangled. Raw HTML stays escaped (no rehype-raw) to avoid XSS from untrusted model output. * fix(ai-studio): execution-panel dark-mode contrast, modal heading, visualize label - Set explicit text color (theme token) on the Execution Log and node-detail panels so their text stays readable in dark mode instead of inheriting a dark color. - Align the welcome modal's icon and title on one horizontal row. - Shorten the Visualize node's palette description so its subtitle fits. * feat(ai-studio): linked CDN logo with theme-aware variants Hide the SDK app-bar logo (no prop to replace or link it yet) and render the Workflow Builder CDN logo over the slot, linked to workflowbuilder.io. Swap the transparent dark-text / white-text variants by the SDK theme so the logo reads on both light and dark app bars (the -solid asset bakes in a white background). Remove once the SDK exposes a logo/logoHref prop. * fix(ai-studio): keep app-bar Save button clear of the logo overlay display:none on the SDK logo collapsed its flex box, sliding the Save button left under the fixed logo overlay. Hide the logo with visibility and reserve its width instead so the nav-segment keeps its place. * feat(ai-studio): add Visualize node to AI Debate template End the debate flow in a Visualize node and shape the verdict as markdown (verdict line + For/Against table + reasoning) so it renders richly. * feat(ai-studio): add Visualize node to Meeting Notes template End the flow in a Visualize node and shape the recap as markdown with an action-items table (owner/task/due) so it renders as a structured artifact. * feat(ai-studio): converge Content Repurposer into a Visualize node Add a Content Pack agent that merges the three channel drafts into one sectioned markdown document, then a Visualize node to render it. Keeps the fan-out and gives the flow a single final artifact. * refactor(ai-studio): drop dead code and unused exports Remove the unused isTurnstileEnabled helper and de-export symbols that are only used within their own module (renderers, VISUALIZE_MODES/VisualizeMode, DetectResult, VisualizeNode). knip-clean across ai-studio, backend, worker. * chore(ai-studio): drop internal planning docs from the PR Remove the long-work backlog and crystallize plan; agent-process scratch, not product docs for the public repo. Net diff vs main no longer includes them. * fix(ai-studio): declare ai-agent output so node mentions resolve The ai-agent palette item had no outputSchema, so {{ nodes.<id>.response }} references (e.g. in decision conditions) fell through to the SDK's unresolved 'missing mention' label. Declaring the response output renders a clean 'Classify Ticket · Response' pill instead. * feat(ai-studio): web search tool for AI Agent nodes (Tavily) Add an opt-in 'Web search' toggle to the AI Agent node. When enabled and TAVILY_API_KEY is set, the executor gives the agent a Tavily-backed web_search tool via the AI SDK tool-calling loop (capped at a few steps). The loop runs inside the activity, so it needs no graph cycles and stays DAG-compatible. Without the key the node runs unchanged (tool simply not exposed). * feat(ai-studio): add Market Research template using web search A Trigger -> Research Agent (web search enabled) -> Visualize flow that showcases the AI Agent web-search tool: the agent searches and writes a sourced markdown brief, rendered in the Visualize node. Needs TAVILY_API_KEY to actually search; runs without it, just answers from the model. * feat(ai-studio): always AI-adapt visualize output, drop the toggle Remove the aiAdapt switch from the Visualize node. Structured formats (chart/diagram/table/json/stat-cards) are now always LLM-adapted to fit the selected format; markdown/text stay passthrough. The manual adapt button is gone too since adaptation is automatic. * refactor(ai-studio): remove the Error Policy feature entirely Drop the per-node Error Policy control (schema/uischema/defaults across all nodes + errorPolicy from every template) and the now-dead ErrorHandle decorator/component. Nodes rely on the engine default (fail on error). Simplifies the demo UI - the feature was underdeveloped and not worth keeping. * feat(ai-studio): default the demo to English The SDK i18n auto-detects the browser locale, so the public demo came up in Polish on PL machines. An inline script in index.html pins 'en' before the module (and the SDK i18n it loads) boots, unless the visitor made a clean en/pl choice via the selector. Placed in HTML because a bundler import can't be guaranteed to run before the SDK's i18n init. Pairs with the SDK selector fix (regional locales) tracked separately. * refactor(ai-studio): trim narration comments to a self-explanatory minimum Remove comments that restate code or justify changes across ai-studio, the execution worker and the backend; keep only terse notes for genuine traps and non-obvious constraints (single-instance rate limit, fail-closed verification, mermaid pre-validation, script ordering, browser quirks). Rationale lives in commit messages, not inline. No code changes. * feat(ai-studio): tidy node + form UI via SDK CSS overrides Widen decision-branch spacing, hide the decision node's unused outer output port (branches carry their own), and give prompt inputs a monospace font and a capped height. Consumer-side overrides on SDK tokens/classes, no SDK change. * feat(ai-studio): add undo/redo Port the undo-redo plugin from demo (app-bar buttons + Ctrl+Z / Ctrl+Shift+Z), register it on WorkflowBuilder.Root, and add its react-i18next dependency. * fix(ai-studio): make execution node highlight solid across all statuses Running/completed/failed rings mixed opacities (40/90/50%), so some looked half-transparent and others solid. Drop the transparency so every status ring is a consistent solid color. * feat(ai-studio): center execution log, drop the node-detail popup Move the execution log to the bottom center. Clicking a node's flag marker now reveals and flashes that node's entry in the log instead of opening a separate detail panel (that panel is removed). * fix(ai-studio): flag opens the log; node selection highlights its entry The flag marker now explicitly opens the log (store-owned collapsed state) so it works even when the log is already showing that node. Selecting a node on the canvas highlights its log entry without opening the log. Drops the select-driven auto-expand effect that could fight a manual collapse. * fix(ai-studio): center the icon inside node execution markers * refactor(backend): drop the in-house execute rate limit Rate limiting now comes solely from the shared execute rate-limit middleware (per-minute/per-day, proxy-aware, tested), which also covers the Visualize adapt endpoint via a shared instance so both LLM entry points draw from one budget. guardExecution keeps only the Turnstile check. * fix(ai-studio): drop the English pin, let the locale reflect reality With the SDK selector fix the displayed language matches what actually renders, so starting in the browser's language is correct behavior. * refactor(ai-studio): derive log highlight from canvas selection Clicking a node (its flag marker included) already selects it on the canvas, so the execution store's selectedNodeId, its mirror effect and the extra store write were redundant. The log derives the highlight from the SDK's single-selection hook - it now also clears on deselect - and the flag click only expands the log. * fix(ai-studio): cancel stale visualize adaptations, drop the chart chip Move the AI-adapt call into an effect with cleanup so an in-flight response can't overwrite a newer output (and no LLM call is wasted on it). Remove the 'Try as chart' chip and the chartable detection it hung on - always-on adapt covers it and the numbers-array path rendered as plain text anyway. VALID_MODES now derives from the schema's VISUALIZE_MODES instead of a hand copy. * fix(ai-studio): one undo per keypress, keep native text-field undo The SDK useKeyPress toggles on OS key-repeat, so holding Ctrl+Z undid many steps, and skipTarget hijacked Ctrl+Z inside text fields. Replace with a plain keydown listener guarded by event.repeat and text-target checks; adds Ctrl+Shift+Z as redo. * refactor(ai-studio): bundle the brand logo locally instead of the CDN * refactor(ai-studio): trim template noise and close latent races Drop redundant errors:[] from template data (the canonical demo templates omit it), serialize Turnstile token requests (the single widget can't handle overlapping calls), use useId for mermaid render ids (the module counter could collide across concurrent diagrams), and shorten the textarea font stack to ui-monospace/monospace. * docs(ai-studio): branch-gap override is app styling, not a pending SDK fix The SDK gap applies correctly but scales to about 2px at the demo zoom-to-fit, reading as no spacing; widening it is this app's presentation choice, so the SDK default stays untouched and the change was dropped from the SDK polish PR. * refactor(ai-studio): drop overrides superseded by SDK fixes The decision node's dead outer port and the branch-card panel spacing are fixed in the SDK, and prompt inputs cap their growth via the new maxRows uischema option instead of a CSS max-height. * docs(ai-studio): drop a narration comment from the app bootstrap * refactor(ai-studio): drop the branch-gap override The spacing complaint was about the properties panel, fixed in the SDK; the canvas override was a misdiagnosis artifact. * refactor(ai-studio): pass the brand logo through the SDK props The logo/logoHref props landed in the SDK, so the fixed-position overlay, the hash-prefix CSS hide and the theme-swap component all go away. --------- Co-authored-by: Jan Librowski <jan.librowski@synergycodes.com>
…sualize copy feedback (#62) * fix(backend): disable proxy buffering on the execution SSE stream A fronting proxy that buffers the stream delivers every event in one burst at stream close, so live node progress renders only after the run finishes. Send X-Accel-Buffering: no from the route and re-emit it from the deploy nginx (nginx hides upstream X-Accel-* headers), so a TLS-terminating proxy in front of the stack sees it too. * fix(ai-studio): drop copy-source and give copy-image visible feedback The visualize copy buttons gave no feedback at all, so a successful copy looked broken. Copy image now flips to a checkmark for 1.5s and is disabled while AI adaptation is in flight (its target element does not exist yet, so clicking was a silent no-op). Copy source is removed from both the card and the modal. * feat(ai-studio): visualize copy writes image and plain text together One clipboard entry with both image/png and text/plain: pasting yields the image where images are accepted and the raw result text in text-only fields. Copying only the image looked broken when pasted into a text field. * fix(ai-studio): set Render as to auto in template visualize nodes Palette drops get mode: 'auto' from defaultPropertiesData, but the hand-authored template nodes omitted it, so their Render as select showed an empty value. --------- Co-authored-by: Jan Librowski <jan.librowski@synergycodes.com>
The disclaimer showed only on first visit with no way back to it. When the modal is closed, an info button in the canvas's bottom-right corner brings it up again. Co-authored-by: Jan Librowski <jan.librowski@synergycodes.com>
* feat(ai-studio): dock execution log beside the properties panel The log is no longer a centered overlay covering the canvas. It floats bottom-right: against the left edge of the properties panel when the panel is expanded, at the viewport edge otherwise. - height grows with entries up to 430px instead of a fixed 60vh - auto-scroll follows the newest entry; manual scroll pauses it, returning to the bottom resumes it - collapse state persists in sessionStorage for the session - starting an execution reopens a collapsed log * fix(ai-studio): make the whole log entry a collapse toggle The gray detail box showed a pointer cursor but ignored clicks; only the entry header toggled. Now the entire entry (header + detail) is one toggle area. - text selection inside the entry does not trigger the toggle, so log content stays copyable - clicks on interactive elements (links, buttons) inside the detail do not propagate to the toggle * fix(ai-studio): hide the welcome reopen button when the corner is busy The floating info button shares the bottom-right corner with the execution log and overlapped the expanded properties panel footer. Hide it while the log is on screen or the properties panel is expanded; it returns once the corner is free. * style(ai-studio): cut comments down to the non-obvious * refactor(ai-studio): replace toggle guards and unit comment with self-evident code * style(ai-studio): restore rem unit for the log panel max-height * refactor(ai-studio): self-review pass on the execution log changes - full-word selector params (state, not s) across touched files - named constants for magic numbers: scroll bottom tolerance, detail preview length, node id preview length, expanded-panel height ratio - anchor hook decomposed into findRightPanel / measureAnchor / observeAnchor / sameAnchor instead of one closure with an alias - toggleLog reuses setLogCollapsed instead of a side effect inside the setState updater; persist helper renamed to persistLogCollapsed - clsx for conditional class lists instead of template strings - dropped a dead styles lookup (event--<type> classes do not exist) * fix(ai-studio): toggle log entries from the header only Clicking the detail box collapsed the entry under the cursor, which fought with reading and copying the content. The toggle now lives on the header row alone and the detail is plain selectable text without a pointer affordance. Refines the toggle behavior after hands-on testing; diverges from the ticket's whole-entry-toggle wording, ticket to be updated. * revert(ai-studio): restore the whole-entry log toggle Reverts the header-only constraint - the ticket spec is correct as written: header and detail box form one toggle area, with text selection and interactive elements guarded. * refactor(ai-studio): apply review feedback on the log changes - persist the log collapse state via zustand persist middleware with partialize and sessionStorage instead of hand-rolled helpers; resetExecution keeps the current value through the updater - is-prefix for boolean variables: isLogCollapsed, isPanelExpanded, isLogVisible, isOpen, isExpanded, isHighlighted, isCollapsed --------- Co-authored-by: Jan Librowski <jan.librowski@synergycodes.com>
…#65) * fix(ai-studio): re-adapt visualization when the render format changes The adapted content was cached in bare state and reset only when the source text changed, so switching the render format kept feeding the previous format's adaptation to the new renderer (raw JSON instead of a chart) and never called the AI again. The adaptation is now an async derived value keyed by (renderer, text) in a useAdaptedVisualization hook: a stale entry is ignored by the key check instead of being reset by an effect, and each format change triggers a fresh adapt for that format. * refactor(ai-studio): abort in-flight adapt calls, record failures as data The effect now uses an inner async function with an AbortController: switching formats mid-flight cancels the HTTP request instead of just ignoring its result, and the cancelled flag is gone. A failed adapt is cached as { key, output: null } - the raw-text fallback derives from data instead of a swallowed exception, so the catch block has real content and the failure is one selector away from the UI whenever we want to surface it. * refactor(ai-studio): return render-ready text from useAdaptedVisualization The hook now owns the raw-text fallback and returns renderText plus an isAdapted flag, so the caller no longer interprets a null convention spread across files. * refactor(ai-studio): return render-ready text from useAdaptedVisualization The hook now owns the raw-text fallback and returns renderText plus an isAdapted flag, so the caller no longer interprets a null convention spread across files. --------- Co-authored-by: Jan Librowski <jan.librowski@synergycodes.com>
* fix(deploy): pass OPENROUTER_API_KEY to the backend service The adapt endpoint runs its LLM call in the backend, not the worker, and answered 501 adapt_disabled on every request because only the worker received the key. Executions kept working, which masked it. * fix(deploy): wire TAVILY_API_KEY into the worker service The worker reads TAVILY_API_KEY to enable the AI Agent's web search tool, but the deploy compose never passed it, so web search was silently disabled on deployments: agents with the toggle on ran without the tool. Optional - an empty value keeps it off. * fix: unify the AI_MODEL default on the demo model Backend and worker code defaulted to google/gemini-2.5-flash-lite while the deploy stack defaults to mistralai/mistral-small-3.2-24b-instruct, so an unset AI_MODEL meant different models depending on where the process ran. One default everywhere now - the deployed demo already runs this model, so production behavior does not change. --------- Co-authored-by: Jan Librowski <jan.librowski@synergycodes.com>
* feat(sdk): reduce required peer dependencies * feat(sdk): re-export JsonForms authoring primitives
piotrblaszczyk
requested review from
librowski,
lukasz-jazwa and
szymon-t-sc
as code owners
August 12, 2026 08:43
librowski
approved these changes
Aug 12, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
No description provided.