mirror of
https://github.com/simstudioai/sim.git
synced 2026-09-22 05:19:54 +08:00
e08fb022e69b222598552dfcb97efd8f32f960f9
131
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
3143a15dde |
feat(uptimerobot): add UptimeRobot v3 integration (#5229)
* feat(uptimerobot): add UptimeRobot v3 integration
- 24 tools across monitors, incidents, maintenance windows, alert contacts,
public status pages, and account (UptimeRobot v3 REST API, Bearer auth)
- Block with operation-scoped subBlocks, status-page logo/icon file uploads
via internal multipart routes, and BlockMeta templates + skills
- Registered tools/block, added icon, generated docs
- Updated add-integration/add-block/validate-integration docs links to /integrations
* fix(uptimerobot): address review — heartbeat URL, file/JSON edge cases
- Block: URL is not required for HEARTBEAT monitors (no URL)
- buildMonitorBody: throw on malformed assignedAlertContacts/customHttpHeaders
JSON instead of silently dropping the field
- PSP route: error (400) when a supplied logo/icon cannot be resolved to a
stored file instead of silently omitting the image
- PSP route: guard success-path JSON parsing; return a controlled 502 on a
non-JSON provider response instead of an uncaught 500
* fix(uptimerobot): spec-conformance audit fixes
- pause/start monitor: send Content-Type: application/json (v3 spec requires it
on these POSTs even with an empty body)
- update maintenance window: drop autoAddMonitors (not in UpdateMaintenanceWindowDto);
gate the block field to create only
* fix(uptimerobot): rename monitor timeout param to avoid reserved name
The tool runner treats a top-level `timeout` param as the outbound HTTP-client
timeout (ms), so a monitor check-timeout of e.g. 30s would abort the API call in
30ms. Rename the input to `checkTimeout` (block subBlock, tool params, inputs,
numeric coercion) and map it to the API body's `timeout` key in buildMonitorBody.
* fix(uptimerobot): reject empty/non-object PSP responses
A successful PSP create/update must return the PspDto object; an empty or
non-object body now returns a controlled 502 instead of mapping a phantom
status page (id: 0, empty name, null images) back to the workflow.
* fix(uptimerobot): validate core PSP fields before mapping
Reject successful PSP responses that lack a positive numeric id and non-empty
friendlyName (a {} or metadata envelope) with a controlled 502, instead of
mapping a phantom status page.
|
||
|
|
6260eda226 |
fix(ssr): harden credential query-key factory + fetchers against the 'use client' stub bug (#5206)
* fix(ssr): move credential query-key factory + fetchers to non-client modules
Preventively closes the same 'use client' SSR client-reference-stub class that
crashed the tables page. Server-evaluated modules (the credential block def, the
workflow-comparison helpers) imported workspaceCredentialKeys /
fetchWorkspaceCredentialList / fetchCredentialSetById from 'use client' hook
modules, where they resolve to client-reference stubs on the server (a future
server call path would throw 'X is not a function').
Extract them into non-client hooks/queries/utils/{credential-keys,
fetch-workspace-credentials,fetch-credential-set}.ts (mirroring folder-keys.ts /
fetch-workflow-envelope.ts) and import from there. No behavior change — these
values were only ever called from browser paths.
* docs+ci: codify the 'use client' server-import rule + add check:client-boundary
Document the Next.js rule that server code can only render a 'use client'
export as a component, never call it (server imports resolve to client-reference
stubs that throw — the tables-page crash). Add the rule to
.claude/rules/sim-queries.md + a cross-ref in sim-architecture.md.
Add scripts/check-client-boundary-imports.ts (wired into CI as check:client-boundary)
that flags any value import from a 'use client' module in a server-evaluated,
non-JSX surface (prefetch / route handler / trigger / block definition), so this
class can't silently recur. Escape hatch: // client-boundary-allow: <reason>.
|
||
|
|
cff7a49310 |
feat(file): workspace-scoped inline images + public-share cascade (#5203)
* feat(file): workspace-scoped inline images + public-share cascade Embedded markdown images now resolve only within the document's workspace, and public file shares cascade to the images the shared document embeds. - New /api/workspaces/[id]/files/inline (in-app, workspace-scoped) and /api/files/public/[token]/inline (public cascade) routes; the public one serves an embed only when it is referenced-by-doc, same-workspace, and passes a magic-byte image sniff - Embed srcs (serve-key and view-id forms) rewrite through one scoped inline route; one shared isomorphic parser owns the embed grammar for both the frontend renderer and the server doc scan - Accept wf_ file ids on the view/export routes (were 400ing on .uuid()) * feat(file): add Image command to the markdown editor slash menu - New /Image slash command uploads an image via a file picker and inserts it at the caret (same upload+insert path as paste/drop) - Inserted src is the workspace serve URL, so it renders in-app and cascades to public shares like any other embed - Per-editor handler wired through slash-command storage (the extension set is a shared singleton); only active when the editor is editable * fix(file): export rewrites all embed forms; cap embedded refs combined Addresses PR review: - Markdown export now rewrites the in-app `/workspace/<ws>/files/<id>` embed form too (not just `/api/files/view/<id>`), so a bundled asset never leaves a broken link in an offline export (Bugbot) - extractEmbeddedFileRefs bounds total references (keys + ids) to 50 combined rather than 50 each, matching MAX_EMBEDDED_IMAGES intent |
||
|
|
8f312d299b |
feat(guardrails): PII redaction via Presidio sidecar (native VIN, per-rule language) (#5174)
* fix(logs): run PII redaction over HTTP and fix Presidio provisioning - resolve the guardrails venv via candidate paths and fail fast instead of silently falling back to system python3 (the misleading "Presidio not installed" that broke redaction and the guardrails block in deployed runtimes) - install the en_core_web_lg spaCy model in setup.sh and app.Dockerfile - route log redaction through an internal /api/guardrails/mask-batch endpoint so Presidio always runs in the app container, including async executions that persist inside the trigger.dev runtime * fix(guardrails): chunk + time-bound internal PII mask requests - chunk maskPIIBatchViaHttp by count (2000) and bytes (256KB) so large executions split across requests and never hit the contract's 100k cap - add AbortSignal.timeout(45s) per request so a slow/unreachable app container aborts and the caller scrubs, instead of hanging the trigger.dev job - catch maskPIIBatch failures in the route: log and return a structured 500 (broken venv fails loudly server-side; caller still scrubs, no leak) - add mask-client tests (order across chunks, count split, non-2xx, empty) * fix(guardrails): mint internal token per mask request A single token (5min TTL) could expire mid-batch when a large execution fans out into many sequential chunk requests; mint one per request instead. * feat(guardrails): run PII via Presidio sidecars + TS recognizer registry - replace the per-call python3 subprocess (cold spaCy load every call) with two long-lived Presidio sidecars (analyzer + anonymizer) reached over HTTP; the app image no longer carries Python/Presidio/venv - add PRESIDIO_ANALYZER_URL / PRESIDIO_ANONYMIZER_URL - move VIN out of Python into a TS recognizer (check-digit validated) behind a CUSTOM_RECOGNIZERS registry so new custom detectors are one entry; masking is handled uniformly by the anonymizer - drive the guardrails block's PII type picker from the shared pii-entities catalog (adds VIN, fixes drift) so block + Data Retention never diverge - delete validate_pii.py, requirements.txt, setup.sh and the Dockerfile venv step * fix(guardrails): bound-parallelize mask batch; refresh stale comments - maskPIIBatch runs per-string sidecar calls with bounded concurrency (8) via mapWithConcurrency, so a chunk of many small leaves finishes within the 45s request timeout instead of aborting and scrubbing; order + fail-on-error kept - drop stale comments referencing the deleted Python venv / 30s subprocess timeout * refactor(guardrails): single Presidio image, native VIN, per-rule redaction language - collapse the analyzer/anonymizer URLs into one PRESIDIO_URL (combined image serves /analyze + /anonymize) - remove the TS VIN recognizer (vin.ts, recognizers.ts) — VIN is now native + multi-language in the image; validate_pii is a thin analyze→anonymize client - trim KR_RRN/TH_TNIN from the catalog (no Korean/Thai model in the image) - add per-rule redaction language: PII_LANGUAGES catalog drives the contract enum, the Data Retention rule modal, and the guardrails block dropdown; resolver + logger thread it through to maskPIIBatch (default en), so non-English entity rules (e.g. ES_NIF) actually fire instead of silently no-op'ing under en * fix(guardrails): correct sidecar port (5001) + README for combined image The combined Presidio image (docker/pii.Dockerfile) serves /analyze + /anonymize on a single port 5001 with native VIN + multi-language recognizers. Fix the PRESIDIO_URL default (was 5002) and rewrite the README, which still described two stock containers and a TS VIN recognizer. * fix(guardrails): coerce stored redaction language in the resolver The persist-path resolver accepted any stored language string, so a stale/invalid code (e.g. a dropped locale) would reach Presidio and scrub the log even though the admin UI shows English. Coerce against the supported set via a shared coercePiiLanguage helper (now reused by the data-retention route too), falling back to en for unknown values. * fix(guardrails): rename PRESIDIO_URL env var to PII_URL Match the infra taskdef, which sets PII_URL on the app container for the combined Presidio sidecar. |
||
|
|
d8da1e2577 |
fix(state): align server/client state with best practices (query-key bugs, persist hygiene, useState) (#5166)
* fix(queries): close React Query key/fetch-arg drift cache collisions Several query hooks fetched with an identifier that was absent from their queryKey, so distinct fetch args shared one cache entry. Thread the missing args into the key factories and update all callsites/invalidations. - organization: useOrganization always fetched the ACTIVE org via getFullOrganization() while caching under detail(orgId). Pass orgId through to the better-auth call (query.organizationId); active-org behavior unchanged. - logs: logKeys.detail now keys on (workspaceId, logId) to prevent cross- workspace collision; updated useLogDetail, useLogByExecutionId, prefetchLogDetail, useCancelExecution optimistic path, and external callsites. - inbox: inboxKeys.taskList now includes cursor/limit (pagination args were sent but omitted from the key); keepPreviousData pagination UX preserved. - a2a: narrow create/update byWorkflows() invalidation to byWorkflow(ws, wf) since their responses reliably carry both ids; delete/publish stay broad. Not bugs (verified, left unchanged): - kb/connectors update/delete invalidate knowledgeKeys.detail(kbId), which is a prefix of connectorKeys.all(kbId) — connector list/detail are invalidated transitively by React Query prefix matching. Harness: add a key-fetch-arg-drift check to check-react-query-patterns.ts that flags a camelCase identifier the queryFn forwards into the fetch but is absent from the queryKey (excludes the requestJson contract arg, PascalCase/SCREAMING constants, and signal/pageParam machinery). Document the rule in sim-queries.md. tables.useTable annotated rq-lint-allow (tableId globally unique; workspaceId is only an authz scope). * fix(stores): whitelist durable fields in persist partialize chat/terminal/panel persist configs leaked actions and transient state into localStorage. Replace the chat full-state spread with an explicit durable whitelist, and add partialize to terminal and panel (which had none) so isResizing and _hasHydrated are no longer persisted. Panel keeps activeTab + panelWidth because the layout.tsx blocking script reads them from panel-state to set data-panel-active-tab before hydration (SSR tab-flash prevention). Harden sim-stores doctrine: persist MUST use an explicit partialize whitelist; never persist transient flags or _hasHydrated. * fix(state): model component useState as single source of truth - edit-knowledge-base-modal: reset fields on closed→open via prevOpenRef render idiom instead of mirroring props into state through useEffect (a prop change while open no longer clobbers in-progress edits) - use-verification: collapse contradictory isLoading/isVerified/isInvalidOtp booleans into a single status enum + errorMessage; consumer derives flags - contact-form / demo-request-modal: derive busy/success from the mutation object; delete duplicated submitSuccess local state - sim-hooks.md: add state-shape rule (no props-into-state, status enum, derive mutation state) * fix(verify): clear lingering message on complete OTP (restore parity) * docs(state): convert inline reset comment to TSDoc * docs(state): tighten harness rules for accuracy (queryFn forwards, partialize whitelist, mutation-flag caveat) * fix(verify): block auto-verify while a resend is in flight (restore parity) * fix(logs): key cancel optimistic detail by route workspaceId (not the log row) |
||
|
|
7349bf403f |
feat(files): password, email-OTP, and SSO auth for public file shares (#5140)
* feat(files): password, email-OTP, and SSO auth for public file shares * fix(files): suppress filename in share previews for email/sso, not just password * fix(files): normalize allow-list emails to lowercase; genericize shared SSO denial message * fix(security): make isEmailAllowed case-insensitive; normalize email at client gates * test(security): cover isEmailAllowed case-insensitive matching * fix(security): bind auth cookie to auth type; password endpoint rejects non-password shares * chore(db): format generated migration meta * fix(files): share upsert validation returns 400 not 500; disabling always succeeds * feat(access-control): org admins can restrict allowed file-share auth types |
||
|
|
5925651cbc |
feat(vfs): add lazy vfs + remove dynamic fields for prompt caching hits (#5138)
* feat(vfs): add lazy vfs + remove dynamic fields for prompt caching hits * feat(vfs): send typed workspace snapshot for append-only deltas Build the workspace inventory from the primary db (fixes replica-lag staleness) and emit it as a typed VfsSnapshotV1 `vfs` payload alongside the markdown, so the mothership can diff it into append-only baseline/delta messages. Generate the TS contract mirror from the Go-owned JSON schema (sync-vfs-snapshot-contract) and sort connector types so diffs stay byte-stable. * fix(lint): fix lint * fix(vfs): forward the typed snapshot through the branch payload builder The branch buildPayload implementations hand-list the params they pass to buildCopilotRequestPayload and forwarded workspaceContext but dropped vfs, so the typed snapshot never reached the Go request (req.Vfs was always nil and the append-only delta path never engaged). Forward vfs in both the workflow and workspace branches, and add a regression guard asserting the branch threads it through (the bug slipped past tests because post.test mocked the payload builder and payload.test called it directly, bypassing the branch). * improvement(contracts): update vfs contracts |
||
|
|
208d135dac |
feat(enrichment): add enrichment details sidebar with cost + provider cascade (#5139)
* feat(enrichment): add enrichment details sidebar with cost + provider cascade * fix(enrichment): address review — persist detail on cancel/skip, exclude not_run from ran count, refetch on panel open * fix(enrichment): keep cascade detail sticky on upsert; mark unattempted providers not_run on abort * fix(enrichment): show Cancelled in details panel for aborted runs |
||
|
|
f0b3550729 |
feat(files): public share links for workspace files (#5130)
* feat(files): public share links for workspace files * improvement(files): drop reserved public_share columns until used; sync audit mock * fix(files): share modal tracks authoritative saved state until toggled * feat(files): per-IP rate limit on public share endpoints * fix(files): address PR review — public CSV OOM, content cache, share FK, soft-delete filter, download anchor * fix(files): disable CSV import action in read-only preview (public share) * refactor(files): drive CSV preview import affordance off readOnly, not disableImport * fix(files): version public viewer caches by file updatedAt so edits aren't stale * fix(files): 409 (not corrupt source) when a shared generated doc has no compiled artifact * feat(files): gate public sharing behind an access-control permission |
||
|
|
63a3e6d2cb |
feat(files): stream large CSV previews and add import-as-table (#5125)
* feat(files): stream large CSV previews and add import-as-table * fix(files): validate fileId in csv-preview route, guard double-import, fix sniff perf and toggle flash * fix(files): scope mothership preview-toggle loading guard to CSV files only |
||
|
|
8b93e43037 |
improvement(integrations): validate BigQuery/Forms/PageSpeed + regenerate integration docs (#5109)
* improvement(integrations): validate BigQuery/Forms/PageSpeed + regenerate integration docs - BigQuery: mark null-defaulted outputs optional (get_table type/numRows/numBytes/creationTime/lastModifiedTime/location, list_datasets location, list_tables type, query totalBytesProcessed) - Google Forms: add response pagination (pageToken + filter params, nextPageToken output), fix pageSize visibility, advanced-mode pagination subBlocks + filter wandConfig - PageSpeed: add a 7th BlockMeta template (competitor benchmark) - Regenerate integration docs; add manual intro sections to new datagma/dropcontact/enrow/icypeas/leadmagic pages * fix(docs-gen): preserve apostrophes in tool descriptions when generating docs The doc generator extracted tool descriptions with a character class that excluded both quote types (['"]([^'"]...)['"]), so a double-quoted description containing an apostrophe (e.g. "Find someone's email") was truncated at the apostrophe — the generated docs/catalog showed stubs like "Find someone". Anchor extraction on the actual opening quote (single/double/backtick), matching the existing extractDescription helper, in both buildToolDescriptionMap and extractToolInfo. Regenerated docs restore full descriptions across all affected integrations (Apollo, Ahrefs, LeadMagic, Findymail, OpenAI, Slack, etc.). * fix(docs-gen): resolve tools defined in a sibling file + scope params per tool The doc generator located a tool's definition only by filename convention (decompress.ts / index.ts), so file_decompress — which lives in compress.ts alongside file_compress — fell back to index.ts and rendered an empty Input table. It also read the params block from the first tool in a multi-tool file, so every tool in such a file inherited the first tool's inputs/outputs. - getToolInfo: when no candidate file declares the exact tool ID, scan the whole tool-prefix directory for the file that does. - extractToolInfo: read the params block scoped to the specific tool, falling back to the full file for tools that inherit params via spread. Regenerated docs eliminate ~50 empty/incorrect input tables across integrations (clickhouse, rb2b, reddit, file, etc.); param-less OAuth-only tools correctly keep an empty input table. |
||
|
|
7b4626e547 |
improvement(perm-groups): allow workspace filter for permission groups (#5070)
* improvement(perm-groups): allow workspace filter for permission groups * show errors correctly * address comments * address concurrent edit concern * address locks * address comments" * index migration safety * address at route level |
||
|
|
05e8c7cd71 |
refactor(connectors): split client metadata from server runtime (#5076)
* refactor(connectors): split client metadata from server runtime + cover node:net in client bundle The browser build broke with `Cannot find module 'node:net'`. Server-only SSRF code in `input-validation.server.ts` (`dns/promises`, and since PR #5060 `undici` → `node:net`/`node:tls`) is statically reachable from the client bundle via the tool/connector registries, which the workflow editor imports for metadata. Node networking builtins have no browser shim, so Turbopack cannot compile them for the client. Two changes: 1. Split each connector's client-safe declarative metadata into a sibling `meta.ts` (`<name>ConnectorMeta`), mirroring the `XBlockMeta` / `BLOCK_META_REGISTRY` pattern. `connectors/registry.ts` is now the client-safe `CONNECTOR_META_REGISTRY` (+ `getConnectorMeta` / `getAllConnectorMeta`); the full registry with runtime fns moves to `connectors/registry.server.ts`. Client components consume the meta registry; the sync engine and knowledge API routes consume the server registry. This removes connectors from the client's server-only graph. Connector metadata is byte-for-byte identical before/after; runtime fns are untouched. 2. Extend the existing #4899 `turbopack.resolveAlias` browser stub — which already mapped `dns`/`dns/promises` to an empty module for the browser — to also cover `net`/`tls` (+ `node:` variants), since `undici` now pulls those in. The remaining tool/provider definitions still reach `input-validation.server` server-side; the browser-only stub keeps those Node builtins out of the client bundle while the real modules stay on the server, so SSRF validation and IP pinning are unaffected. Connector authoring/validation skills updated to teach the meta.ts split. * fix(icons): use Square logo glyph only, drop wordmark * fix(connectors): share Discord max-messages default across meta and runtime Discord defined DEFAULT_MAX_MESSAGES separately in meta.ts (config placeholder) and discord.ts (sync behavior), which could drift. Export it from meta.ts and import it in the runtime, matching the single-source pattern used by the other connectors (e.g. gmail, intercom). * refactor(tools): route grafana/agiloft egress server-side, drop SSRF browser shim Move the server-only SSRF-pinned fetch out of the grafana (update_dashboard, update_alert_rule) and agiloft (11 record/search tools) definitions and into internal API routes, the same pattern the rest of the server-side tools (and agiloft's own attach/retrieve) already use. The tool definitions are now purely declarative (request → internal route), so they no longer import `input-validation.server` and the tools registry is fully client-safe. With connectors (meta split) and these tools no longer reaching server-only code from the client bundle, the browser no longer pulls in `dns`/`net`/`tls`: - Add `import 'server-only'` to `input-validation.server.ts` so any future client import fails loudly at build time instead of silently bloating the bundle. - Remove the `turbopack.resolveAlias` browser stub and delete `empty-node-fallback.browser.ts` — the root cause is fixed, the shim is gone. Behavior is unchanged: each route runs the exact merge/validation/fetch logic the tool ran before (every header, param branch, JSON-parse guard, error string, and SSRF pinning preserved); only the location of execution moved from the client- bundled definition to a server route. * fix(connectors): move onedrive tagDefinitions into meta; drop server-only guard - onedrive's tagDefinitions lived in the runtime file, so the client meta registry returned undefined for it and the add-connector tag opt-out section stopped rendering for onedrive. Move it into meta.ts like the other connectors so client and server see identical metadata (verified across all 50). - Remove the 'server-only' import from input-validation.server.ts: the meta/route split already keeps it out of the client bundle, and blocks/tools registries don't use the guard either. * fix(grafana): surface upstream error when the prefetch GET fails Check response.ok on the existing-resource GET in both update routes and return the upstream status/body, matching how the tool framework surfaced GET errors before the move to internal routes (the framework checks response.ok before transformResponse). Without this, a failed prefetch produced a generic 'Failed to fetch existing ...' message and dropped Grafana's error detail. * fix(grafana): reject invalid panels JSON instead of silently ignoring it Grafana's dashboard API treats panels as a required array and returns 400 on invalid JSON; this route already errors on every other JSON param. Return 'Invalid JSON for panels parameter' instead of swallowing the parse error and proceeding with a misleading success. * fix(grafana): trim dashboard/alert-rule UID in route URLs (carry over #5082) PR #5082 added .trim() on dashboardUid/alertRuleUid in the original tool URL builders. Those tools now build their URLs in the internal routes, so apply the same trim there to preserve that behavior. * fix(grafana): route update_folder egress server-side (carry over #5082) #5082 added a grafana update_folder tool that does SSRF-pinned fetch in its postProcess, re-introducing the client-bundle leak. Convert it to the internal API route pattern like the other update tools so the def is declarative and input-validation.server stays out of the client bundle. * fix(grafana): surface route failures in transformResponse instead of masking them The grafana update tools' transformResponse hardcoded success: true and dropped the route's error, so an upstream/validation failure (HTTP 200 with { success: false, error }) was reported to the workflow as a success. Forward data.success and data.error (matching the agiloft tools) so failures propagate as before the move to internal routes. |
||
|
|
3fe061e3b3 |
feat(feature-flags): AppConfig-backed gated feature flags (#5059)
* feat(feature-flags): AppConfig-backed gated feature flags * fix(ci): repoint 'Validate feature flags' step to env-flags.ts after rename * improvement(feature-flags): drop in-code defaults; fallback resolves a per-flag secret, gating is AppConfig-only * improvement(feature-flags): make flag names a closed set so every flag requires a fallback secret * improvement(feature-flags): single FEATURE_FLAGS registry — each entry defines name, description, and fallback in one place * improvement(feature-flags): fallback is the env secret key (keyof typeof env), resolved to a boolean |
||
|
|
f277f5fba5 |
feat(db): zero-downtime migration safety lint + db-migrate skill (#5041)
* feat(db): zero-downtime migration safety lint + db-migrate skill Add scripts/check-migrations-safety.ts (check:migrations), a CI gate that classifies statements in newly-added migrations into hard errors (rewrite), annotate-to-acknowledge contract ops (`-- migration-safe: <reason>`), and backfill warnings. Wire it into test-build.yml. Add the /db-migrate skill as the judgment half (expand/contract phasing, app-code cross-ref, annotation authoring). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * feat(skills): run cleanup and db-migrate safety checks in /ship * fix(db): address review — DROP INDEX lock symmetry, RENAME CONSTRAINT false-positive, alter-type literal match - Non-concurrent DROP INDEX is now a hard error (ACCESS EXCLUSIVE lock), symmetric with CREATE INDEX; DROP INDEX CONCURRENTLY after a COMMIT passes clean. Removes the false-confidence annotate path. - RENAME rule narrowed to RENAME COLUMN / table RENAME TO; RENAME CONSTRAINT and ALTER INDEX ... RENAME (metadata-only) no longer flagged. - alter-type regex now requires TYPE to follow the column identifier, so it no longer matches TYPE inside a string default. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(db): enforce IF EXISTS on DROP INDEX CONCURRENTLY for replay idempotency Symmetric with the CREATE INDEX CONCURRENTLY rule: a post-COMMIT DROP INDEX CONCURRENTLY replays from the top on failure, so without IF EXISTS it aborts re-dropping an already-gone index. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * improvement(skills): gate /ship cleanup on UI changes; default migration base to staging - /ship runs /cleanup only when the diff touches UI code (.tsx or apps/sim/components|hooks|stores); the six passes are React-only. - /ship runs check:migrations against origin/staging (the PR base). - check:migrations default baseRef is now origin/staging instead of origin/main. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * docs(db-migrate): add contract-pending TODO convention for deferred drops Establishes a durable, greppable marker (`contract-pending(<precondition>): ...`) left on the legacy column in schema.ts when an expand defers a drop, so the contract phase doesn't rot. The outstanding-work list is `grep -rn contract-pending`; the contract PR's `-- migration-safe:` annotation references the expand and deletes the marker. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
dd32abef1e |
feat(jsm): add Atlassian Assets (Insight/CMDB) tools for asset management (#5072)
* feat(jsm): add Atlassian Assets (Insight/CMDB) tools for asset management
Add nine JSM Assets tools so workflows can read and write Atlassian Assets
(Insight/CMDB) objects — the foundation for keeping JSM asset tables in sync
for software/hardware asset management.
Tools (wired into the Jira Service Management block):
- jsm_list_object_schemas, jsm_get_object_schema
- jsm_list_object_types, jsm_get_object_type_attributes
- jsm_search_objects_aql (AQL search with pagination)
- jsm_get_object, jsm_create_object, jsm_update_object, jsm_delete_object
Each tool proxies through an internal route that resolves the Jira cloudId and
the Assets workspaceId, then calls the Assets API via the OAuth 2.0 (3LO)
gateway form (/ex/jira/{cloudId}/jsm/assets/workspace/{workspaceId}/v1).
Adds the CMDB OAuth scopes to the jira provider (read/write/delete cmdb-object,
read cmdb-schema/type/attribute) with descriptions, contract schemas for each
route, and block operations/subBlocks/outputs. Bumps the API-validation route
baseline for the nine new routes.
* refactor(jsm): harden Assets param coercion and response typing
- Add toOptionalInt helper so non-numeric pagination inputs never emit NaN
into the Assets query string (startAt/maxResults/page/resultsPerPage)
- Replace Record<string, any> in mapAssetObject with typed Raw* interfaces
* fix(jsm): validate Assets workspaceId and honor `last` pagination flag
Address review findings on the Assets tools:
- Add validateAssetsWorkspaceId and guard the workspaceId in every Assets
route before it is interpolated into the API path (mirrors the existing
cloudId guard) — prevents a crafted workspaceId from escaping the
workspace-scoped path
- Object schema list now falls back to the `last` flag when `isLast` is
absent, so pagination doesn't stop early
* feat(jsm): allow overriding the auto-resolved Assets workspace
Atlassian provisions one Assets workspace per site, so workspace discovery
uses values[0] by design. For the rare multi-workspace site, expose an
advanced "Assets Workspace ID" override on the block that flows through to
every Assets operation, and document the single-workspace assumption.
* refactor(jsm): include Assets responses in the JsmResponse union
Append the nine Assets tool response types to JsmResponse for completeness
and consistency with the rest of the JSM tool surface.
|
||
|
|
d538b76eda | feat(copilot): server-side mothership tool/vfs/file metrics (#5071) | ||
|
|
18edc94b2c |
fix(billing): deploy modal gates on workspace entitlement, not viewer plan (#5055)
* fix(billing): deploy modal gates on workspace entitlement, not viewer plan The deploy modal showed the upgrade wall to a free user in a PAID workspace, because it gated on the viewer's individual plan (useSubscriptionData) while the server gates on the workspace billed account (rolled-up plan). Add a workspace api-execution-entitlement endpoint that mirrors isWorkspaceApiExecutionEntitled, and gate the API/MCP/A2A tabs on it so the UI matches the server exactly. * fix(billing): key deploy gate on URL workspaceId + refetch entitlement on open Address review findings: - key useWorkspaceApiExecutionEntitlement on the URL workspaceId (available on mount) instead of workflowWorkspaceId (null until the workflow map resolves), so the gate fires immediately instead of leaving the tabs ungated until then - staleTime 0 so reopening the deploy modal refetches entitlement; a plan upgrade happens outside this query's invalidation graph, so the gate self-heals on open * refactor(billing): workspace owner access state instead of bespoke entitlement endpoint Replace the single-purpose api-execution-entitlement endpoint with a reusable workspace-owner billing/access concept — the workspace-scoped counterpart to the viewer-scoped useSubscriptionData: - getWorkspaceOwnerSubscriptionAccess(workspaceId): the billed account's rolled-up subscription access fields (mirrors getSimplifiedBillingSummary's flag derivation) - GET /api/workspaces/[id]/owner-billing + useWorkspaceOwnerBilling hook - deploy modal derives its gate via the existing getSubscriptionAccessState (hasUsablePaidAccess) on the owner data, exactly like every other paid feature Audited the rest of the app: no other UI gates on the viewer's plan where the server gates on the workspace owner — programmatic execution is the only workspace-owner-scoped feature; inbox/KB-live-sync/credential-sets all gate consistently on both sides. * fix(billing): deploy gate on owner isPaid, not hasUsablePaidAccess hasUsablePaidAccess rejects past_due and billing-blocked, but the server gate (isWorkspaceApiExecutionEntitled) allows any paid plan in an entitled status (active or past_due). Gate on the owner's isPaid so a past_due paid workspace isn't shown the upgrade wall while the API still works. |
||
|
|
cefb2dc239 |
improvement(mship): add enrichment tool, clean up dead tools (#5058)
* feat(mothership): add enrichment_run server tool for one-off lookups Implement the Sim-side handler for the copilot enrichment_run tool: runs the enrichment provider cascade for a single entity and returns the result inline, surfacing the hosted-key cost as _serviceCost for per-round billing (matching the media tools). Registered in the server-tool router. Regenerate the copilot tool catalog/schemas to include enrichment_run. * fix(mothership): remove leftover touch_plan tool references touch_plan was removed from the copilot tool catalog earlier, but the Sim side still referenced it. Regenerating the generated tool catalog (for enrichment_run) synced it to the current contract and dropped the stale TouchPlan export, which broke the build where router.ts still imported it. Remove the dead touch_plan server tool and its test, drop its router registration and WRITE_ACTIONS entry, simplify getServerToolRegistry (no more beta-gated server tools), and clean up stale "use touch_plan" guidance strings. * chore(mothership): trigger dev redeploy * improvement(mothership): log billed cost on enrichment_run lookups * fix(contracts): regenerate mship contracts * fix(contracts): fix mship contracts |
||
|
|
940506ad09 |
feat(square): add Square integration with 34 commerce operations (#5053)
* feat(square): add Square integration with 34 commerce operations Add a Square integration (API-key auth via personal access token) covering payments, refunds, customers, locations, orders, invoices, catalog, and inventory. Catalog image upload routes through an internal API endpoint using the shared UserFile handling pattern. Adds a dedicated square-errors extractor. * fix(square): correct catalog image part name and address review feedback - Fix catalog image upload: Square's multipart part for the binary is `file`, not `image_file` (per the live API cURL examples); this would have caused upload failures - Catalog image route: check response.ok before parsing, drop the unreachable legacy base64 path, derive MIME from the uploaded file - Block: split the search query field per operation so placeholders match each endpoint's schema; parse each JSON field individually so errors name the field - Round out coverage: complete_payment version_token; customer nickname/birthday; batch inventory states/updated_after/limit * fix(square): correct canonical file param usage and revert query split - Read the catalog image file from the canonical `params.file` (the basic/advanced inputs are collapsed before the params function runs) instead of the raw uploadFile/fileRef ids, which no longer exist at that point — fixes the Canonical Param Validation test and a latent upload bug - Revert the per-operation query split: canonicalParamId is only valid for basic/advanced pairs under one condition. Use a single query field with a schema-neutral placeholder and a wand prompt that covers each search operation * chore(square): trigger fresh review * fix(square): single-location invoice search and guard numeric coercion - SearchInvoices: Square's invoice filter accepts only one location, so take a single locationId (string) instead of an array and wrap it as query.filter.location_ids: [locationId] - Block: fail locally with a clear "<field> must be a valid number" error when amount/limit/version/orderVersion are non-numeric instead of forwarding NaN * fix(square): accept real booleans for autocomplete/includeRelatedObjects Coerce these from both the dropdown's string values and actual booleans (which can arrive via connected blocks or templated inputs), so true is not silently flipped to false. * fix(square): validate parsed JSON field shapes (array vs object) parseJsonField now enforces the expected shape so a valid-but-wrong-type value (e.g. a JSON string where an array is expected for locationIds/objectTypes/ paymentIds/catalogObjectIds/states, or a non-object for order/invoice/etc.) fails locally with a clear message instead of a confusing Square API error. |
||
|
|
eb1009da1c |
improvement(react-query): codebase-wide audit — server-state hooks, webhook coherence, resume migration (#5024)
* improvement(react-query): codebase-wide audit — server-state hooks, webhook coherence, resume migration * chore(react-query): add static pattern linter + address review feedback - add scripts/check-react-query-patterns.ts (staleTime/signal/key-factory/inline-key enforcement) wired into CI as check:react-query; strict zone hooks/queries/**, ratchet elsewhere - fix(resume): use same-origin relative path for resume POST (getBaseUrl could cross origin on whitelabel/preview hosts and drop session cookies) — Cursor Bugbot - remove explanatory inline comments in favor of TSDoc per repo convention |
||
|
|
58cff68b5e |
feat(deployments): add v1 deployment endpoints and Deployments block (#5009)
* feat(deployments): add v1 deployment endpoints and Deployments block * fix(deployments): require deployed workflow for rollback, normalize warnings, guard orphaned workspaceId * fix(deployments): workspace-bound tool routes, optional-body parsing, version bounds, and 404 masking - Tool routes now require the executing workspace ID and reject cross-workspace targets - v1 deploy/rollback read optional bodies via parseOptionalJsonBody (size-capped, 400 on malformed JSON) - Version numbers bounded to the Postgres integer range - v1 mutation routes mask access failures as 404, matching the v1 detail route - listWorkflowVersions returns description and normalizes admin-api deployedByName (parity with mothership get_deployment_log) - Workflow selector no longer auto-selects the first workflow (new autoSelectFirstOption opt-out) - Shared deployment version metadata field schemas across UI/v1/tool contracts * chore(api-validation): bump route baseline for rebased staging (826) * fix(docs): use real ID formats in OpenAPI examples Workflow, workspace, folder, knowledge-base, document, and execution IDs are plain UUIDv4; workspace file IDs are wf_<shortId>; table and row IDs are tbl_/row_ + de-dashed UUID. Replaces all fake prefixed example IDs (wf_abc123, ws_xyz789, exec_..., kb_..., etc.) accordingly and marks the deploy body description as nullable to match the shared schema. * feat(deployments): resolve workflow names in block UI, add workflow_undeployed Sim trigger event - Deployments block now uses the workflow-selector subblock (same as the Workflow block), so the canvas tile shows the workflow name instead of the raw ID; reverts the now-unneeded dropdown autoSelectFirstOption prop - Adds workflow_undeployed to the Sim workspace-event trigger, emitted by performFullUndeploy through a shared lifecycle-event dispatch loop |
||
|
|
636bd74f06 |
fix(integrations): resolve OAuth connect UI by service id instead of display name (#5001)
* fix(integrations): resolve OAuth connect UI by service id instead of display name * test(integrations): pin OAuth service resolution for all catalog integrations; fix credential branding reverse lookup * fix(docs-gen): blank string literals and comments before brace scanning in extractOAuthServiceId |
||
|
|
3db7161b1c |
feat(integrations): add Vanta integration with compliance, evidence file, people, vendor, vulnerability, and risk tools (#4993)
* feat(integrations): add Vanta integration with compliance, evidence file, people, vendor, vulnerability, and risk tools * fix(integrations): use write-only scope for vanta document submit and stream-cap document downloads * fix(integrations): vanta review feedback - unique svg ids, mime type for base64 uploads, auth check consistency * fix(integrations): bound vanta base64 fileContent size at the contract level * improvement(integrations): cache vanta tokens and retry once on revocation to avoid concurrent token races * improvement(integrations): deduplicate in-flight vanta token exchanges * fix(integrations): hash vanta client secret in token cache keys * improvement(integrations): expose vanta upload mime type in block and align fileContent bound with the 100MB cap * chore: resolve api-validation baseline after rebase onto staging (816 + 3 vanta routes) |
||
|
|
53fdcab5d6 |
feat(tables): background jobs (delete/export/backfill on trigger.dev) + tenant-scoped query performance (#4915)
* feat(tables): paginated background row-delete jobs via table_jobs
* fix(tables): address review on async row-delete (filtered count, scoped optimistic clear, Cmd+A select-all, hide delete from tray)
* improvement(tables): filter-aware select-all runs, delete-job read mask, keyset index + autovacuum tuning
* feat(tables): run import/delete/export/backfill jobs on trigger.dev with in-process fallback
* improvement(tables): raise delete page to 10k and export batch to 5k
* improvement(tables): raise CSV import batch to 5k rows (param-cap bounded)
* feat(tables): surface export jobs in the header tray with progress, cancel, and download
* improvement(tables): surface exports as derived tables-scoped toasts instead of the import tray
* Revert "improvement(tables): surface exports as derived tables-scoped toasts instead of the import tray"
This reverts commit
|
||
|
|
c3b98eb1c4 |
feat(integrations): add Daytona integration with sandbox lifecycle, code execution, and file tools (#4987)
* feat(integrations): add Daytona integration with sandbox lifecycle, code execution, and file tools * fix(daytona): address review feedback and harden edge cases - Pre-check file size via userFile.size before downloading from storage in the upload route - Tolerate empty response bodies in delete/start/stop sandbox tools - Preserve explicit timeout 0 for run_code and execute_command - Default missing exitCode to -1 so unknown state is distinguishable from success - Reject blank sandbox IDs, clamp list limit to 1-200, trim destination path - Clarify that toolbox operations require the sandbox ID (not name) - Bump contract route baseline to 812 for the new daytona upload route * fix(daytona): cap download size at 100MB and preserve sandbox identity on empty lifecycle responses * improvement(notion): black icon on white background to match brand * fix(daytona): reject oversized base64 uploads before decoding * improvement(landing): move integration last-updated below CTAs and de-emphasize it * fix(daytona): forward explicit zero cpu/memory/disk values in create sandbox |
||
|
|
977467970c |
improvement(integrations): overhaul landing FAQs for SEO/GEO and fix dynamic OG images (#4985)
* improvement(integrations): overhaul landing FAQs for SEO/GEO and fix dynamic OG images * improvement(integrations): trim comments and fold catalog updatedAt into integrations.json * fix(integrations): correct FAQ copy for zero-capability and single-tool integrations |
||
|
|
bc55fc3b50 |
improvement(docs): builder-first IA reorganization of the English docs (#4896)
* docs: reorganize into topic/ontology IA with a builder-first rewrite Restructure the English docs from internal product categories into a topic-based information architecture, and rewrite the conceptual pages to install a mental model first rather than enumerate features. Structure & navigation - Reorder the sidebar to follow how someone builds: Get Started -> Workflows -> Tables -> Files -> Knowledge Bases -> Logs -> Building agents -> Mothership -> Workspaces -> Platform -> Reference. - Demote the generated blocks/tools/triggers catalogs to a Reference section at the bottom. - Break up the monolithic execution/ folder into deployment/ and logs-debugging/; collapse connections/* and variables/* into single pages under workflows/. - Rename capabilities/ to building-agents/; relabel the integration catalog as "Integrations". Remove deprecated copilot and form deployment. Redirects added in next.config.ts for every moved URL. Conceptual rewrites - Workflows core (index, how-it-runs, data-flow, connections, variables): one mental model, one running example, terser prose. - New building-agents overview distinguishes an agent (a workflow you build) from an Agent block (one reasoning step), plus a "choosing what to use" guide. - Concept-trim passes on Knowledge Base, Tables, Blocks, Triggers overviews; new task pages for KB, Tables, and Files. - New code-verified Alerts page. Infrastructure - pageType frontmatter (concept/guide/reference) + badge render. - WorkflowPreview / OutputBundle components to embed real, app-styled workflow diagrams (adds framer-motion + reactflow to apps/docs). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * feat(docs): spec-driven BlockPreview for block reference heroes Replace the static screenshot hero on each block reference page with a <BlockPreview> that renders the block exactly as the builder canvas shows it — header icon, sub-block rows, and branch/error handles — from a hand-authored display spec. Static and non-interactive (no ReactFlow), so it can't be panned or dragged, and self-updating to edit. - block-display-specs.ts: one editable spec per block (rows, branches, handles) - block-preview.tsx: static scaled card renderer with decorative handles - block-icons.tsx: brand glyphs for the core block types; icons.tsx adds WaitIcon - 14 block + 3 trigger pages swapped from <Image> to <BlockPreview> Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(docs): correct stale navigation and removed-feature references Audited the docs against the product changelog (GitHub releases / staging git history) for content that misleads readers — features that moved, were renamed, or removed — rather than cosmetic drift. Fixes: - Skills: no longer a Settings tab. It was promoted to its own workspace page (#4354), so "Settings → Skills under the Tools section" sent readers to a tab that no longer exists. (skills/index.mdx) - Env vars: the workspace tab is "Secrets", not "Environment Variables" (credentials→secrets rename, #4364). (quick-reference/index.mdx) - Mothership FAQ pointed to "Settings → Credentials" for integration connections; integrations moved to their own page and there is no Credentials tab. (mothership/tasks.mdx) - Vision block was retired (#4684); a tip still named it. Reworded to "an Agent using a vision-capable model". (files/passing-files.mdx) - Getting-started FAQ told new users to "use the Copilot feature" to build in natural language — that surface is Mothership. (getting-started) - Removed the dead "Mod+Y → Go to templates" shortcut; the templates gallery was removed (#4354). (keyboard-shortcuts) Note: MCP "tools" (Settings → Tools, for consuming) and MCP "servers" (Settings → System, for exposing) are distinct surfaces — both doc references are correct and were intentionally left as-is. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(docs): repair broken /docs-prefixed enterprise links The enterprise overview linked to /docs/enterprise/* (access-control, sso, whitelabeling, audit-logs, data-retention, data-drains), but the docs site is served at root — those 6 links 404'd. Now root-relative /enterprise/*. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(docs): refresh stale workflow-preview example blocks The /workflows diagram blocks are hand-authored (separate from the spec-driven BlockPreview heroes) and had drifted from the real UI: - Agent color purple #6f3dfa -> green #33C482 (the var(--brand) rebrand) - Model gpt-4o -> claude-sonnet-4-6 (current default) - "Prompt" row -> "Messages" (the actual agent sub-block) - Start color #34B5FF -> #2FB3FF (real starter bgColor) Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(docs): align BlockPreview input/output handles to the card edge The header (input/output) handles are positioned relative to the card and used a -16px offset, so they floated 8px past the edge. Row/error handles are -16px relative to a row that's already inset 8px by content padding, so they sit correctly. Header handles are now -8px, so every handle sticks out the same 8px and hugs the block edge. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * docs(blocks): rewrite Agent reference to match the current block The page documented the old UI (System/User Prompt, no Files or Skills, Memory taught as a separate block — contradicting its own FAQ). Rewritten to the real sub-blocks (Messages, Model, Files, Tools, Skills, Memory, Response Format) in the builder voice of the workflows exemplars: oriented opening, agent vs Agent-block callout, outputs table, a live WorkflowPreview example, FAQ kept and corrected (tool control "Force", not "Required"). pageType: reference. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * docs(blocks): rewrite API reference to match the current block Tightened to the builder voice and the real config (URL, Method, Query Params, Headers, Body + Advanced timeout/retries/backoff). Dropped the off-topic "Dynamic URL Construction" / "Response Validation" sections (those are Function-block techniques, not API config). Outputs table, FAQ kept. The example is now a live WorkflowPreview (new API_FETCH_WORKFLOW in examples.ts, exported via the barrel). pageType: reference. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * docs(blocks): rewrite Condition reference to match the current block Tightened to the builder voice: oriented opening (branches on boolean expressions, no model call, vs Router), the real branch model (if / else if / else, checked top to bottom), connection-tag expression examples, an error-path callout, outputs table, and a live branching WorkflowPreview example (CONDITION_ROUTE_WORKFLOW). FAQ kept. pageType: reference. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * docs(blocks): restore Best Practices + multi-example workflows on Condition Recalibration: reference pages keep genuine substance (Best Practices, every distinct example), cutting only redundancy and verbose register. Restores the Best Practices section and turns the three use cases into three rendered WorkflowPreview examples (route by priority, moderate content, branch onboarding). Adds CONDITION_MODERATE_WORKFLOW and CONDITION_ONBOARD_WORKFLOW. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * docs(blocks): restore Best Practices on Agent reference Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * docs(blocks): restore Best Practices on API reference Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * docs(blocks): rewrite Function reference to match the current block Fixed the verbose register and dropped the duplicated outputs section + the stale Python screenshot/TODO, while keeping the real substance: JS vs Python (local vs E2B sandbox), the large-inputs sim.files/sim.values helpers, the worked loyalty-score example, and Best Practices. The use cases are now two rendered WorkflowPreview examples (reshape an API response, validate input). Adds FUNCTION_RESHAPE_WORKFLOW and FUNCTION_VALIDATE_WORKFLOW. pageType: reference. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * docs(blocks): rewrite Router reference to match the current block Cleaned the register, generalized the drifting model list, and folded the Router-vs-Condition guidance into a callout. Kept the substance (routes as output ports, NO_MATCH error path, all seven outputs, Best Practices, FAQ). The three same-shape use cases collapse to one rendered triage WorkflowPreview (ROUTER_TRIAGE_WORKFLOW), which the prose notes stands for the pattern. pageType: reference. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * docs(blocks): restore the classify and lead-qual examples on Router I wrongly folded two distinct Router scenarios into a note. Restored all three as their own rendered WorkflowPreview examples: triage a support ticket, classify feedback (to child workflows), qualify a lead (sales vs self-serve). Adds ROUTER_CLASSIFY_WORKFLOW and ROUTER_LEAD_WORKFLOW. (Also exports RESPONSE_API_WORKFLOW for the next page.) Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * docs(blocks): rewrite Response reference to match the current block Cleaned the register and broadened "Variable References" to connection tags (any output, not just workflow variables). Kept the substance: exit-point semantics, Builder/Editor mode, status codes, headers, the parallel-branch warning, Best Practices, FAQ. All three use cases are now rendered WorkflowPreview examples (API endpoint, webhook ack, status-per-branch). Adds RESPONSE_API/WEBHOOK/ERROR_WORKFLOW. pageType: reference. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * docs(blocks): rewrite Variables reference to match the current block Cleaned the register, corrected the outputs (each assignment is also exposed as <variables.name>, not "no outputs"), and kept the substance: assignments reference earlier outputs and current values, global <variable.name> access, Best Practices, FAQ. Two use cases now render as WorkflowPreview examples (count retries, hold config). Adds VARIABLES_RETRY_WORKFLOW and VARIABLES_CONFIG_WORKFLOW. pageType: reference. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * docs(blocks): rewrite Wait reference to match the current block Corrected a real staleness: the block now has an Async mode that suspends the run for minutes/hours/days (not a hard 10-minute cap), plus a resumeAt output. Documents Wait Amount / Unit / Async, the sync-vs-async distinction, all three outputs, Best Practices, and updated FAQ. Two rendered WorkflowPreview examples (space out API calls, delayed follow-up). Adds WAIT_RATELIMIT_WORKFLOW and WAIT_FOLLOWUP_WORKFLOW. pageType: reference. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * docs(blocks): polish Credential reference (frontmatter, fold redundant tabs) The page was already accurate to the block (Select/List operations, the outputs tabs, the wiring steps). Light touch only: added description + pageType, made the header consistent, and folded the two identical Gmail/Slack "how to wire" tabs into one line. Examples stay as labeled flows + the List/ForEach screenshot, since they use integration blocks and a Loop the WorkflowPreview can't render. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * docs(blocks): render the shared-credential example + icon fallback for integrations Addressing the gap: WorkflowPreview block nodes now fall back to the integration icon map, so diagrams can show Gmail/Drive/Slack/etc. with their real glyphs, not just core blocks. Renders the Credential "share one account across blocks" example as a WorkflowPreview (CREDENTIAL_SHARE_WORKFLOW). The multi-account and List+ForEach examples stay as labeled flows + screenshot (the latter uses a Loop container the preview can't render). Also exports EVALUATOR_GATE_WORKFLOW for the next page. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * docs(blocks): rewrite Evaluator reference to match the current block Cleaned the register, generalized the drifting model list, and documented the per-metric outputs (<evaluator.metricname>), which the page omitted. Kept the substance (metrics with name/description/range, structured-output guarantee, Best Practices, FAQ). The quality-gate example renders as a WorkflowPreview; the same shape covers the parallel-variations and support-QC patterns, noted in prose. pageType: reference. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * docs(blocks): render the Credential route-by-logic example too The icon fallback unblocked it: the "route to a different account by logic" example now renders as a WorkflowPreview (CREDENTIAL_ROUTE_WORKFLOW), a Condition selecting a production vs staging credential. The List + ForEach example stays a screenshot because it nests blocks in a Loop container the flat WorkflowPreview can't represent. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * docs(blocks): render Guardrails examples + light accuracy pass Kept the full substance (four validation types, PII entity/language detail, the PII screenshot and video, outputs, Best Practices, FAQ). Light fixes: frontmatter, and generalized the drifting model names (GPT-4o / Claude 3.7) to "a strong reasoning model" with the current default. The three use cases now render as WorkflowPreview examples (validate JSON, check grounding, block PII). Adds GUARDRAILS_JSON/HALLUCINATION/PII_WORKFLOW. pageType: reference. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * docs(blocks): render Human-in-the-Loop examples + frontmatter Kept all the substance (Display Data, Notification, Resume Form, the Approval Methods and API Execute Behavior tabs, outputs, the paused/resume example). Added frontmatter and rendered the use cases as WorkflowPreview examples (approve before publish, two-stage approval, verify extracted data); Quality Control folds into the approval note as the same approve-then-act shape. Adds HITL_APPROVAL/MULTISTAGE/VALIDATE_WORKFLOW. pageType: reference. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * docs(blocks): render Webhook examples + frontmatter The page was already accurate (Webhook URL/Payload/Signing Secret/Headers, the automatic-headers table, HMAC details, outputs, POST-only callout, FAQ). Added frontmatter and rendered the two use cases as WorkflowPreview examples (notify a service, fire on a check). Adds WEBHOOK_NOTIFY_WORKFLOW and WEBHOOK_TRIGGER_WORKFLOW. pageType: reference. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * docs(blocks): add example + pageType to Workflow block reference The page was already accurate and well-structured (Configure It, outputs, deployment-status badge, execution notes, FAQ). Added pageType: reference and a rendered WorkflowPreview example showing a parent calling the child workflow enrich-lead and reading its result. Adds WORKFLOW_CALL_WORKFLOW. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * docs(blocks): container rendering for Loop/Parallel + render the Loop example Adds subflow/container support to WorkflowPreview, modeled on the app's subflow-node.tsx: a solid-bordered box with a header (icon + name), an internal "Start" pill whose handle feeds the first nested block, and target/source handles at the vertical center. PreviewBlock gains size/parentId; edges gain an optional sourceHandle; nodes render nested children via React Flow parentNode. Renders the Loop reference's ForEach example (LOOP_WORKFLOW) and keeps the four loop-type sections + inside/outside referencing + caps. pageType: reference. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * docs(blocks): fix the Loop container's Start-pill connector The Start pill -> first-block edge wasn't rendering: it was a React Flow parent->child edge (unreliable), and the opaque container body hid it. Nested blocks now render as absolute-positioned top-level nodes (container below at zIndex 0, blocks above at zIndex 1), so the connector is an ordinary edge, and the container body is see-through so it's visible. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * docs(blocks): render the Parallel example + frontmatter (last core block) Reuses the container rendering for the Parallel reference. Kept all substance (count/collection types, inside/outside referencing, batch size of 20, instance isolation, the Parallel-vs-Loop table, Best Practices, FAQ). Added frontmatter and a rendered container WorkflowPreview (PARALLEL_WORKFLOW: distribute tasks, call concurrently, aggregate <parallel.results>); the two use cases stay as labeled flows. Adds PARALLEL_WORKFLOW. pageType: reference. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * docs(blocks): prose glow-up for Guardrails to match the agent/condition voice Rewrote the listy register (**Use Cases:** / **How It Works:** / **Configuration:** scaffolding, "Use this when you need to..." filler) into the plain builder voice, matching the depth of the Agent/Condition/Function rewrites. Kept every validation type, option, range, the full PII entity/region list, the screenshot and video, the outputs table, the rendered examples, Best Practices, and FAQ. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * docs(blocks): prose glow-up for Loop to match the agent/condition voice Rewrote into the plain builder voice and cut the filler: dropped the "Use this when you need to..." lines and the ASCII "Example: Iteration 1, 2, 3" pseudo-code, and folded the duplicated Inputs/Outputs tabs into Configuration + Referencing sections. Kept all four loop types with their screenshots, the inside/outside reference rules, the 1,000-iteration cap, sequential-vs-parallel guidance, the rendered example, and FAQ. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * docs(blocks): prose glow-up for Parallel to match the agent/condition voice Same treatment as Loop: plain builder voice, dropped the ASCII pseudo-code and the duplicated Inputs/Outputs tabs, folded the verbose Advanced Features into tight Configuration + Referencing sections. Kept both types with screenshots, the batch-size-of-20 cap, instance isolation, large-result indexing, the Parallel-vs-Loop table, the rendered example, and FAQ. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * docs(blocks): prose glow-up for Human-in-the-Loop Tightened the register: folded the pause sentence into the intro, made the section headers consistent (Configuration, Outputs), converted the bold-list Block Outputs into a table, condensed the Notification channel bullets to a line, and renamed the second "Example" so it no longer collides with the rendered Examples. Kept all the substance — Display Data / Notification / Resume Form, the Approval Methods and API Execute Behavior tabs, the portal video, and FAQ. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * docs(blocks): re-enrich Loop prose (fuller, explanatory — not terse) The first glow-up overcorrected into terse fragments. Restored proper docs-quality prose at the Agent/Condition level: each loop type now explains what it does, when to use it, and the relevant reference; Configuration, Referencing, nesting, and Best Practices give context and the "why," not just bullets. Same substance, readable depth. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * docs(blocks): re-balance Parallel prose to the Agent/Condition register Calibrated to the level signed off on elsewhere: each concept explained in a couple of clear sentences with a concrete detail — informative, not terse, not padded. Kept both types with screenshots, batch-size cap, isolation, large-result indexing, the Parallel-vs-Loop table, the rendered example, and FAQ. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * docs(blocks): restore the Notification channel detail on HITL The glow-up over-compressed: it flattened the five notification channels (each with what they do) into one sentence. Restored them as a list in plain voice — tightening register shouldn't drop genuinely useful reference detail. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * docs(blocks): builder-voice polish on the Credential intro Light touch only — the page was already well-structured and explanatory, so just led the intro with what the block does (and bolded the name) to match the other references. No content changed elsewhere. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * docs(triggers): rewrite Start trigger in the builder voice Tightened the register, swapped the <code><></code> noise for backticks, added pageType + an outputs table, and kept all substance: Input Format types, chat-only outputs (input/conversationId/files), the editor/API/chat tabs, and best practices. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * docs(triggers): rewrite Schedule trigger in the builder voice Plain voice and clean markdown (dropped the raw <ul>/<div> lists). Kept all substance: simple intervals, cron examples, timezone, deploy-tied activation, the 100-failure auto-disable, and FAQ. Added pageType. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * docs(triggers): refocus Webhook trigger on the generic (native) trigger Rewrote in the builder voice and separated out the integration content: the page now documents the generic Webhook trigger (URL, Input Format, auth, custom response, outputs, dedup/rate-limit/deploy/no-auto-disable). The "trigger mode for service blocks" section is reduced to a short pointer + the demo video, and the long supported-services catalog and vague use-case bullets are dropped in favor of the Triggers index. Fixed the title (Webhook) and added pageType. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * docs(triggers): builder-voice glow-up for RSS Light pass: added pageType + description, tightened the intro, and presented the output fields as an <rss.*> outputs table. Kept the polling config, use cases, the published-after-save callout, and the FAQ (poll cadence, dedup, 25-item cap, auto-disable, Atom support). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * docs(triggers): rewrite Table trigger off the auto-generated card Replaced the BlockInfoCard/'provides 1 trigger' auto-gen format with a real builder-voice page: a spec-driven BlockPreview hero (added a 'table' spec), plain-language Configuration (table, event type, watch columns, include headers), and a full <table.*> outputs table. pageType: reference. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * docs(triggers): frame the index around native triggers + separate the catalog Reframed "generic" as native (no connected account) and promoted RSS and Table into the native set alongside Start/Schedule/Webhook — cards, comparison table, and integration paragraph updated to match. In the sidebar, grouped the five native triggers under a "Native triggers" header and divided the ~44 service triggers under "Integration triggers" (nav-only — no files moved, URLs stable; the move to integrations/ is a later, separate change). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * docs: promote Core Blocks + Core Triggers into the Workflows area Restructured the Documentation sidebar (meta-only — no files moved, URLs stable): after Deployment, the 16 core block pages now live under a "Core Blocks" section and the 5 native trigger pages under "Core Triggers", instead of buried in the bottom Reference catalog. Removed the now-redundant blocks tree from Reference, and retitled the Reference triggers tree "Integration triggers" so it holds just the service catalog (the native ones are promoted up top). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * docs: merge block/trigger overviews into the Workflows overview; Core accordions Restructured the sidebar and overview hub (meta + content only, no integration files moved): - Folded the /blocks and /triggers overview pages into /workflows: the overview now carries the core-block catalog (do work / direct flow / shape run), the Integrations-and-triggers families framing, the native + integration trigger framing, the trigger comparison, manual-run priority, and email-polling groups. Deleted blocks/index.mdx and triggers/index.mdx as redundant. - Promoted the 16 core blocks into a "Core Blocks" folder accordion and the native triggers into a "Core Triggers" accordion, both under Workflows after Deployment. Integration triggers stay inside Core Triggers under a labeled divider, temporary until they move to integrations/<service> (tabs) later. - Repointed every /blocks and /triggers index link to the /workflows#blocks and /workflows#triggers sections. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * docs: split integration triggers into their own Reference accordion Core Triggers is now the 5 native triggers only. Moved the 43 service triggers out of triggers/ into a new integration-triggers/ folder, surfaced as an "Integration triggers" accordion under Reference (an accordion must be its own folder in Fumadocs). In Workflows, Core Triggers now sits before Core Blocks. URLs: /triggers/<service> -> /integration-triggers/<service> (native /triggers/* unchanged); the integrations/<service> tabbed-page migration remains the later step. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * docs(workflows): trim the overview back to an introduction It had drifted from a concept intro into a catalog. Kept the spine (the four parts with their previews, how-it-runs, workflows-in-context) and compressed the merged-in material: the full 16-block enumeration becomes a three-kind taxonomy with examples, the trigger section a short native/integration framing. Cut the anxious in-between — manual-run trigger priority, the niche email-polling-groups feature (belongs on the Gmail/Outlook trigger pages), the redundant block-def line, the Start-outputs callout half, the connections video, and the catalog-y FAQ items. Dropped the unused Video import. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * docs: relocate email-polling + trigger-priority out of the overview Moved the two bits cut from the workflows overview to durable, generator-safe homes: email-polling groups -> the Integrations (connecting accounts) page; manual-run trigger priority -> the Start trigger page. Also added 'table' to the generator's HANDWRITTEN_TRIGGER_DOCS / SKIP_TRIGGER_PROVIDERS so the hand-written Table trigger page is no longer overwritten by generate-docs. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * feat(docs-gen): emit per-service integration pages (actions + Trigger section) Rewrites the generator to output one page per service under integrations/ instead of split tools/ + triggers/. Block pass writes the service's actions; trigger pass appends a '## Triggers' section (badged) to the same page, or writes a standalone page for trigger-only services. Meta is written after both passes; hand-written integration pages are preserved; docsUrl repointed to /integrations. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * feat(docs): unify tools + triggers into per-service /integrations pages Encodes the ontology "everything is a block; some blocks are triggers." The generator now emits one page per service under integrations/ — the service's Actions plus, when it has one, a Triggers section on the same page — replacing the split tools/<service> + triggers/<service>. No "Tools" terminology. - generate-docs.ts: output to integrations/, merge trigger sections into each service page (standalone for trigger-only services), Actions heading, table block now generated, docsUrl -> /integrations, hand-written pages preserved. - Nuked tools/ (213) and the interim integration-triggers/ (43); moved the custom-tools guide to building-agents/; knowledge/memory/file/table links and meta repointed to /integrations. - Sidebar: integrations catalog now under Reference (was tools); removed the Workspaces integrations entry and the integration-triggers tree. - block-icons: wait uses lucide Clock (the generated icons.tsx no longer carries a hand-added WaitIcon). Landing integrations data regenerated. No redirects (fresh start). Native Core Blocks/Core Triggers unchanged. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(docs): recover the hand-written manual-content intros on integration pages The tools->integrations relocation generated fresh pages, so the generator never saw the old tools/<service>.mdx to preserve its {/* MANUAL-CONTENT */} sections — 198 curated intros (AgentMail, etc.) were dropped. Reseeded each integrations page from the pre-move tools page in git, re-ran the generator (which now merges the manual intro into the new Actions/Triggers format), and repointed /tools/ links inside the recovered prose. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * docs(scripts): rewrite the generator README for the integrations model Brings scripts/README.md current: integration pages are derived from the apps/sim block/tool/trigger registry (canonical-sources map), the golden rule not to hand-edit generated pages, the MANUAL-CONTENT escape hatch, which pages are hand-written/skipped, and the icons.tsx-overwrite gotcha. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * docs: regenerate integration docs from staging-synced apps/sim After merging staging, regenerated so the integration pages reflect current source: correct block colors/configs (e.g. Gmail #FFFFFF), the new integrations (sendblue, millionverifier, neverbounce, zerobounce), and staging's icon set. Pages for integrations staging hid are removed; manual-content intros preserved. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(docs-gen): don't let stale-doc cleanup delete hand-written integration pages Staging's cleanupStaleToolDocs removes any integrations/*.mdx that isn't a visible tools block — it only guarded `index`, so it deleted the hand-written google/atlassian service-account pages. Now guards all HANDWRITTEN_INTEGRATION_DOCS. Restored the two pages, and repointed /integrations/file links to /files (staging hides the file block, so it has no integration page). Note: staging recategorized a2a/mysql/postgresql tools -> 'blocks' (and hid file), so they correctly drop out of the integration catalog and are currently undocumented — an IA decision to revisit. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(docs-gen): stop cleanup/writer filter mismatch from eating manual content Comprehensive-review findings, all generator-consistency bugs: - cleanup used staging's isIntegrationBlock while the writer kept the legacy filter, so integrations/{knowledge,memory,table}.mdx were deleted then regenerated without their manual intros every run. Both now honor a shared NATIVE_RESOURCE_BLOCK_TYPES set; intros reseeded. - Trigger-only services (imap, circleback; category 'triggers') were likewise deleted each run; the canonical set now includes visible trigger-category blocks, the standalone writer preserves manual content, and their intros are reseeded. - Mapped jsm -> jira_service_management, so JSM triggers merge into the JSM integration page instead of an orphan jsm.mdx (removed). - Repointed lingering bare /tools links to /integrations; added missing pageType to integrations/index and building-agents/custom-tools. Double-regen is now churn-free (idempotent) with all manual content intact. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(docs): recover staging's enriched Table doc + never drop manual content The merge resolution deleted staging's relocated blocks/table.mdx, which carried substantial enrichment our integrations/table.mdx (reseeded from the older tools/ version) lacked: Creating Tables (column types/constraints), Filter Operators, Combining Filters, Sort Specification, Built-in Columns, Limits, and Notes. Recomposed integrations/table.mdx with that content — Creating Tables inside the intro manual section, the reference tail in a notes manual section. Generator fix uncovered en route: a manual section whose insertion anchor is missing in the generated markdown (e.g. notes with no "## Notes" heading) was silently dropped on regen. Unplaceable sections now append at the end instead — manual content is never lost. Verified idempotent across double regeneration. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * docs(workspaces): de-philosophize the fundamentals prose Rewrote in the plain register of the workflows overview: 'draws the boundary for access' / 'Nothing crosses the boundary' / 'follow the same edge' become direct statements (only members can access it; a workflow in one workspace cannot read a table in another). '## The boundary' is now '## Access and isolation'. All substance kept: every resource type, permission levels, personal/organization/grandfathered kinds, deployments callout, VISUAL markers. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(docs): restore #blocks and #triggers anchors on the workflows overview The editorial trim renamed '## Blocks' -> '## Kinds of blocks' and '## Triggers' -> '## How a workflow starts', silently breaking the ten /workflows#blocks and /workflows#triggers anchor links pointed there when the old index pages were folded in. Pinned the original ids with explicit heading anchors. Found by the comparative prose review. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * docs: restore the genuinely useful reference bits the rewrite dropped From the comparative prose review, restored in guidance register (no spec dumps): temperature tiers on Agent (low/middle/high with ranges), loop/parallel iteration references in the variables syntax-at-a-glance table, and a short "Test it" section on the Webhook trigger (curl + check the run in Logs). The fourth flagged loss (tag-resolver mechanics on connections) turned out to be already covered — name normalization, case-sensitive paths, missing-output behavior, and value formatting are all on the page; only the internal resolver precedence chain was dropped, deliberately. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * docs(blocks): rework the Agent intro — encyclopedia register Replaced the flat opening with a denser, factual one (no metaphor): what the block does, and its centrality stated as fact — 'Most workflows are built around one or more Agent blocks.' The agent-vs-Agent-block disambiguation moves from an info callout into a second paragraph on the block's role in building agents. Dropped the now-unused Callout import. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * docs(integrations): add the HubSpot setup guide for the Marketplace listing Addresses HubSpot Marketplace review item A1: a public, HubSpot-specific setup guide following their template — what the app does, install + connect through the current flow (sidebar Integrations page -> HubSpot -> Add to Sim -> connect dialog -> HubSpot OAuth), with real screenshots of each step and a placeholder for the scope-approval shot; configure in a workflow (one-click skills/templates + the HubSpot block + trigger mode), use, disconnect (with data consequences), uninstall from the HubSpot side, troubleshooting. Capability wording is by CRM object rather than scope enumeration, so it stays accurate after the A2 scope trim. Lives at /integrations/hubspot-setup, guarded as hand-written, cross-linked from the HubSpot reference page's intro. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * docs(integrations): rewrite the Integrations guide for the sidebar flow Integrations moved out of Settings to a top-level sidebar page. Rewrote the guide to the current journey: the Integrations page (Connected/Featured/search), service pages with one-click skills and templates, + Add to Sim -> connect dialog (display name + permissions) -> provider OAuth. Replaced the four Settings-era screenshots with current captures (connect dialog illustrated via HubSpot); block-side screenshots (account selector, manual credential ID) kept; one VISUAL marker for the connection detail view pending a fresh capture. Members/roles, credential-ID, reconnect/disconnect, email polling, and FAQ substance unchanged apart from navigation. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * docs: move Building agents directly after Workflows in the sidebar The agent-building journey follows straight from workflows (blocks, triggers, deployment) rather than after the tour of every resource type. Tables/Files/ Knowledge Bases/Logs now follow it. Meta-only reorder. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * docs: fill the visual slots coverable by existing components Six VISUAL markers filled with no new captures needed: - building-agents overview: rendered the minimal lead-scoring agent (Start -> Agent with tool chips -> Response, Agent highlighted) as a WorkflowPreview (BUILD_AGENT_WORKFLOW) - files guide: the read -> summarize -> write chain as a WorkflowPreview (FILE_SUMMARY_WORKFLOW) - tables guide: the query -> classify -> write-back roundtrip as a WorkflowPreview (TABLE_ROUNDTRIP_WORKFLOW) - choosing guide: the six-kind comparison grid as a markdown table - knowledgebase guide: the Knowledge block's output as an OutputBundle - workspace fundamentals: removed a duplicate nesting-diagram marker 42 -> 39 VISUAL markers remaining (screenshots + designed diagrams). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * docs(components): run-inspector OutputBundle + lightbox with block inspector Two visual-component upgrades, both mirroring the real app: - OutputBundle is now a miniature of the run inspector: a Logs column (block rows with icon chips and durations, source selected) beside the Output panel's typed tree — keys with the app's type-badge semantics (string green, number blue, object gray, array purple, boolean orange), chevrons, indent guides, primitive values. Styling lifted from the terminal's structured-output. Dropped the "Read one value by name" footer (the prose teaches the tag). The three usages (data-flow, tables, knowledgebase) get real typed trees; data-flow's stale purple/gpt-4o example corrected en route. - WorkflowPreview gains a lightbox + read-only block inspector: clicking a block (or the expand control) opens a 92vw/86vh overlay with zoom and pan, and a right-hand inspector panel showing the selected block's full configuration — canvas rows truncate, the inspector doesn't. Fields render as app-style controls (dropdown/textarea/input by heuristic) with dashed dividers, tool chips, and a Connections footer computed from the edges. Selection rings without dimming (new selectedBlock option in workflow-data). Esc/backdrop closes; body scroll locks while open. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * docs: regenerate after staging merge — AppConfig joins integrations/ Staging's new AWS AppConfig integration (#4928) generated its docs into the old tools/ layout; re-homed to integrations/appconfig.mdx (Actions heading, meta entry) via the generator. tools/ stays deleted. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * docs: redirect the retired tools/ and trigger URLs to integrations/ Revises the earlier fresh-start call: /tools/* are ~200 live, indexed URLs referenced by deployed app versions' docsLink fields and marketplace listings, so dropping them cold would 404 from the live product. next.config now 308s: - /tools -> /integrations, /tools/:slug -> /integrations/:slug (custom-tools -> building-agents/custom-tools first) - old /triggers/<service> -> /integrations/<service>, enumerated so the native trigger pages keep resolving; provider-slug mappings for jsm and the hyphenated Google/Microsoft slugs - /blocks and /triggers index URLs -> the workflows overview anchors Verified every class + native passthroughs against the dev server. Spec updated. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * docs(getting-started): rewrite — current UI, cut the post-tutorial padding The last old-guard page. Accuracy: Agent config now uses Messages (System/User message) instead of the removed System Prompt/User Prompt fields, the default model instead of GPT-4o, the banned 'no-code' phrasing is gone, the deploy card points at /deployment, and frontmatter gets description + pageType. Weight: cut the 'What You've Built' checklist, the 'Key Concepts You Learned' re-teach section, the duplicate 'Resources' links, the Start-block hand-holding, and ten dead icon imports; tightened every step preamble. 203 -> 113 lines with the full 5-step tutorial, videos, and FAQ intact. (Videos still show the old UI until the re-recording pass.) Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * docs: de-fluff the Tier-1 heavy pages (logging, mcp, passing-files, permissions) From the exhaustive fluff audit, keeping all substance: - logging: merged the duplicated Console/Logs-page structure, snapshot concept stated once instead of three times, cut the generic Best Practices, trivial tab walkthrough condensed. Frontmatter added. - mcp: intro + "What is MCP?" generic bullets folded into two sentences, cut the Common Use Cases catalog and the verify-your-config Troubleshooting checklists, merged the twice-stated Refresh behavior, security kept as one real warning. - passing-files: marketing opener replaced with a factual lead, fixed the stale retired-Vision-block reference (now Agent with a vision model), dropped the FAQ item that restated the block catalog verbatim. - permissions: heading-restating intro replaced with the two-layer model, cut the three "Perfect for: stakeholders..." persona lines and the generic Best Practices section, dropped the FAQ restating the limits table. - connectors: audit over-flagged it — the categorized support matrix, API-key table, and config examples are genuine reference; frontmatter only. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * docs: tier-2 fluff trims (costs, enterprise, mailer, skills) Conservative sweep from the audit, unambiguous cuts only: the costs CYA opener and formula restatement, the enterprise marketing intro (now a functional summary), mailer's restated convenience line and chat-upload comparison, and skills' third restatement of progressive disclosure. Audit flags screened out as misfires: mothership/tasks (immediate-vs-scheduled are two facts, not a duplicate), self-hosting telemetry (real sizing data), and the recently approved credential/HITL/workflow-block/trigger pages. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * docs(skills): update to the Skills tab on the Integrations page + document import Skills moved again — they now live on the Integrations page's Skills tab in the workspace sidebar (the doc said "Open the Skills page"). Updated the create flow (+ Add to Sim -> Add Skill dialog) with fresh screenshots of the tab and both dialog tabs, and documented the previously-missing Import flow: upload a .md with YAML frontmatter or a .zip containing SKILL.md, fetch from a GitHub URL, or paste SKILL.md content (verified against the import route/component; name 64 / description 1024 limits verified against the contract). Noted the curated skills suggested on integration pages, cross-linked the Skills tab from the Integrations guide, and refreshed the location FAQ. Mechanics (progressive disclosure, load_skill, agent-block attachment) unchanged and still accurate. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * docs(building-agents): render the lead-scorer running example on choosing The page narrated its running example through six sections without ever showing it. Authored LEAD_SCORER_WORKFLOW (Start -> Enrich workflow-as-tool -> Function reshape -> Agent with Search/Send Email/CRM tool chips -> Google Sheets append) and rendered it after the intro, with highlightBlock re-renders in the three sections that map to a node (deterministic block -> the Sheets append, agent tool -> the Agent, workflow-as-tool -> Enrich) — the same pattern as the workflows overview. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * docs(tables): rewrite workflow columns around the real lead-scoring example Rebuilt the page on the ai_startup_customers screenshots instead of captioning them onto the old hypothetical: one running example throughout — Company Domain fills domain, Company Info reads it into employee_count/description, Lead Score Enrichment writes lead_score/priority/score_reasoning. Every section now describes the actual UI: the grid with group headers, per-row run buttons, and the 21-running toolbar; the Configure workflow panel (picker, column inputs, output selection, Auto-run, Run after); the Company Info input/output mapping; Not found cells explained where the screenshot shows them; the cascade section describes the example itself. All placeholder markers on the page resolved. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * docs: regenerate after staging merge — Slack trigger update + file block re-visible Staging's mothership v0.2 (#4923) expanded the Slack trigger payload (interactivity, slash commands: event_type, command, action_id/value/actions, response_url, trigger_id, callback_id, ...) — regenerated so it lands on the unified integrations/slack page; the old-layout triggers/slack.mdx from staging's generator was dropped in the merge. The file block is visible again upstream, so integrations/file.mdx is back in the catalog. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * docs(tables): playbook prose pass on workflow columns + restore File block links Workflow columns, against the docs-writing playbook: killed the banned 'Term — desc' bullets in the Configure list (term + verb form), restored the one universal analog (spreadsheet macro), fixed the clipped 'On,/Off,' fragments, replaced an invented <start.companyDomain> tag with the verified description, and thinned em-dashes to four page-wide with no clustering. Also repointed [File] block mentions back to /integrations/file now that the page exists again (FileV5 is visible upstream); the Files-store links stay on /files. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * docs(tables): per-row execution inspection on workflow columns Two new captures: the cell menu (View execution, Re-run cell, row actions) and the Log Details trace for a single row's run. New 'Inspecting a row's run' section ties cell values to real, traceable runs; corrected the re-run guidance now that Re-run cell exists (the page previously said Run all rows was the only way to retry). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * docs(workflows): drop the confusing 'order by hand' sentence 'You never set the order by hand' read wrong (wiring connections is setting it by hand), and the replacement was over-explanation. The first sentence already carries it: Sim works out the order from the connections. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * docs(workflows): fix the over-claim about independent blocks 'Two blocks that don't depend on each other run at the same time' is wrong — independent blocks at different depths run at different times. Concurrency follows from readiness, not independence: blocks whose dependencies have all finished run together. Reworded to say that, tied to the image's two agents. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * docs(workflows): accuracy audit of how-it-runs against the executor Verified every claim on the page against apps/sim/executor. One claim was materially false: "a failed block stops its own path but leaves independent paths running" — in the engine, an unhandled block failure sets the error flag and stops scheduling entirely (in-flight blocks finish, nothing new starts); only a connected error port routes the failure and keeps the run alive. Now says that. Two imprecisions tightened: a join waits for every feeder *that is going to run* (deactivated-branch feeders don't hold it up, per the edge-manager cascade), and Loop also repeats while a condition holds. Confirmed accurate: per-block readiness scheduling (readyQueue + race, not layers), branch-skip cascade and empty tags, the 25-hop call-chain cap. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * docs(logs): real captures on the overview + prose matched to the UI The logs-debugging overview had six visual placeholders and no visuals. Three real captures placed: the workspace Logs page as the hero (rows with status, credits, trigger, duration), Log Details' Trace tab at the blocks section (the CRM sync run's spans, with a one-line read of where the time went), and the editor's live run console at the input/output section. Prose corrected to what the UI shows: cost is in credits, failed runs are badged Error (dropped the five-state enum the list doesn't display), and the Trace tab is named. The row-anatomy marker is covered by the hero; the two designed-diagram markers (debug-loop flowchart, failed-vs-success comparison) remain. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * docs(workflows): one reference syntax, named sources — untangle variables vs connection tags An exhaustive sweep of "connection tag" found the docs asserting both that a workflow variable is a connection tag (response.mdx used it as the umbrella for all angle-bracket references) and that it isn't (variables.mdx). Ruled the narrow definition canonical — a connection tag reads a block's output; the name follows the connection — and restructured around the real model: - variables.mdx: new "One syntax, named sources" section states that everything in angle brackets is one mechanism whose first segment names the source, with the load-bearing fact stated plainly: `variable` is literal, a connection tag starts with the block's own name. The syntax table drops the redundant dot-notation row, gets one row per source, and is ordered by resolution precedence with the order explained beneath it (absorbing the old Name conflicts section). The credentials pointer folds into the env-var section; trimmed the "never appears in outputs" overclaim. - response.mdx: no longer calls a workflow variable a connection tag. - connections.mdx: the owner page closes the loop — same syntax also reads variables and loop/parallel context; a connection tag is the block-output case. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * docs(workflows): verify the reference model against the resolver; fix one imprecision Checked every claim in the new 'One syntax, named sources' section against apps/sim/executor/variables: resolver chain order is Loop -> Parallel -> WorkflowVariables -> Env -> Block (matches the table); 'variable'/'loop'/ 'parallel' are literal prefixes (REFERENCE.PREFIX); block names normalize via toLowerCase + strip spaces; an unmatched reference is genuinely left in place (resolver returns undefined -> the replacer emits the raw match). One claim tightened: {{KEY}} is a different syntax and can never collide with angle-bracket references, so the precedence sentence now scopes collisions to the angle-bracket sources with a concrete example (a block named 'variable'). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * docs(building-agents): workflow-as-tool is agent-decided, not the Workflow block The choosing page defined workflow-as-tool as the Workflow block (path-decided), contradicting its own name and the comparison table's premise. Verified against the product: workflow_executor is an agent tool — you pick the workflow in the Agent block's tool list, the model decides when to call it and supplies the inputMapping (user-or-llm), inputs arrive at the child's Start trigger. Rewritten agent-first: the section defines it as a workflow handed to an agent as one callable tool, the lead scorer gains a Deep Enrich workflow tool chip on the agent (diagram updated), and the deterministic Workflow block becomes the explicit contrast in a callout — same child workflow, the difference is who decides, mirroring the block/agent-tool contrast. Table row corrected to "The agent"; the summary paragraph follows. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * docs: theme-aware previews + enrichments vs workflow groups split Light-mode support for every preview component (WorkflowPreview canvas, nodes, containers, edges, lightbox, BlockPreview, OutputBundle, BlockInspector): a wp-scope token block in the docs global stylesheet whose values mirror the OG repository's globals.css in both modes (surfaces, borders, --workflow-edge, text tiers, the --badge-* type-badge palette). Every hardcoded hex swapped to a --wp-* var; brand colors, selection blue, and error red stay literal. tables/workflow-columns: separated the two group kinds per the contract's workflowGroupType enum ('manual' | 'enrichment'). New "Two kinds of groups" section opens with the + New column menu capture (Enrichments above the types, Workflow below); Enrichments documented from the code-defined registry (company domain, company info, email verification, phone number, work email) including the provider-cascade behavior that produces Not found cells; the Company Info panel capture is now correctly labeled as an enrichment config; workflow groups keep the Configure workflow panel. Shared machinery generalized under "How groups run"; the cascade section names which stage is which kind; the two portrait screenshots render smaller. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * docs(tables): don't enumerate the enrichment catalog; don't assert a group's kind Two corrections on workflow columns: the prose no longer lists the enrichment catalog (growable, not procedurally tracked — it now describes the category and points at the Enrichments panel; the provider-cascade/Not-found explanation stays, it's behavior not catalog), and the page no longer asserts which kind the example's Company Domain / Company Info groups are (Company Info may be a user-built workflow, not the built-in). The input/output bindings capture moved to "How groups run" as the kind-agnostic illustration; only Lead Score — whose panel shows the workflow picker — is named as a workflow group. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * docs(components): per-branch source handles — conditions and routers finally branch WorkflowPreview's node only ever had one header source handle, so every condition/router example fanned both edges out of a single point and never showed the if/else rows the real canvas (and the BlockPreview hero specs) render. PreviewBlock now supports `branches` (each rendered as a row with its own right-edge source handle, id `branch-<id>`) and `showError` (red error handle), mirroring the executor's per-branch condition-true/condition-false and router-<route> handle model. A block with branches emits from them, not the header. Every affected example rewired (13 workflows): the three condition examples, status-per-branch, credential routing, and the webhook-trigger check route their edges through branch-if/branch-else with the expression on the If row and an explicit else; the three router examples list their actual routes as branch rows (Sales/Support/Billing, Product/Bug report, Enterprise/Self-serve); the terminal gates (variables retry, evaluator gate, the three guardrails gates) show dangling if/else branch rows like the canvas does. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * docs(components): inspector shows branch rows Moving condition expressions from rows into branches emptied the lightbox inspector for condition/router blocks — it only mapped rows to fields. Branches now map too: each branch renders as a field (If with its expression as code, else as an empty control, router routes by name). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * docs(components): branch handle ids match the app's workflow representation Verified against the source after the branch-handles work: the canvas emits condition-${cond.id} handles per condition row (workflow-block.tsx) and Router V2 uses router-${routeId} port handles, and edges carry those ids as sourceHandle — the docs' invented branch- prefix was a gratuitous divergence that the planned fromWorkflowState() adapter would have had to translate. The node now uses the authored branch id as the handle id directly, and every example authors ids in the app's own scheme (condition-if/condition-else, router-<route>), so example edges now match real workflow edges verbatim. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * docs: agent skills mint /integrations/ docs links and describe the new output The add-integration/add-block/validate-integration skills — what Claude Code follows when integrations land on staging — still taught the old layout: docsLink templates pointing at docs.sim.ai/tools/{service} and 'generates tools/{service}.mdx'. Updated so that once this PR merges, the instructions on staging produce the new way by themselves: /integrations/ docsLinks, the per-service page description, and the don't-hand-edit/manual-content pointer. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * docs(workflows): execution semantics, not simultaneity The concurrency section drifted into 'run at the same time' framing across two accuracy passes — but the semantics are non-blocking execution: a block starts the moment its dependencies finish and waits on nothing else. Section retitled 'Blocks run as soon as they can', the rule stated in two plain sentences, the duplicated pre-image example narration gone (the post-image caption carries it). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * docs(workflows): errors are execution semantics — own section on how-it-runs Failure behavior was buried inside 'Watching a run' (the live-UI section). Now a first-class 'When a block fails' section in the execution story: an error fails the run (in-flight blocks finish, nothing new starts) unless the block's error port is connected, in which case the run follows the error path. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * docs: data-driven additions from the platform-metrics read Three targeted edits from the sim-internals analysis, each carrying an inline {/* why */} provenance comment so future editorial passes know the data behind it: - workflows/how-it-runs gains "How long a run can take" — run timeouts are the only hard-error class provable at scale (2,415 five-minute timeouts in 14 days); limits verified in lib/core/execution-limits/types.ts (5 min free / 50 min paid sync, 90 min async, env-overridable). - getting-started gains an "if the run doesn't go green" callout at the Test step — the largest funnel drop is created-workflow -> first-successful-run (92% -> 49%), and this is the stall point. - function/api Best Practices: the existing error-path bullets get a guard comment (<1% of deployed workflows connect an error port — under-adopted, not under-needed) instead of duplicate bullets. - visuals manifest: capture priority reordered by integration adoption (Sheets, Gmail, Telegram, WhatsApp, ...). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * docs: regenerate after staging merge (integration validation batch + Gong tools) Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * docs: rename Building agents -> Agents; URLs match the settled IA The section's pages now live where the sidebar says they do: building-agents/ -> agents/, and the stray top-level /mcp and /skills fold in as /agents/mcp and /agents/skills (they were always part of the agents story — the URLs predated the IA settling). Sidebar section header is now "Agents", link labels updated, and every old URL 308s: /building-agents(/*) -> /agents(/*), /mcp, /skills, plus the existing capabilities/ and tools/custom-tools redirect destinations retargeted. Verified: all five new pages render and every old-URL class redirects correctly. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * docs(workflows): connections gets its video, an FAQ, and accurate output examples The reorg dropped two things from the old tags page that belonged on the connections reference: the connections.mp4 walkthrough (restored after the intro) and the FAQ (rebuilt in the robust JSX form — resolver order, name normalization, env-var syntax pointer, didn't-run behavior, array indexing, Function-block formatting; answers aligned with the since-verified resolver facts, including unmatched-references-left-in-place). Editorial/accuracy pass on the output-shape tabs while in there: stale gpt-4o and gpt-5 examples now claude-sonnet-4-6, the Agent tokens shape corrected to the verified { input, output, total } (the page contradicted blocks/agent), and the dubious cost: [] line dropped — the example now matches the real run inspector. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * docs: regenerate after staging merge — sim trigger, enrichment + logs blocks, re-shown DB integrations Staging's #4941 added the Sim workspace-event trigger (hand-written page adopted into Core Triggers), the Enrichment and Logs blocks (category 'blocks' — added to NATIVE_RESOURCE_BLOCK_TYPES so they live in the integrations catalog like table/knowledge/memory), and re-categorized mysql/postgresql/sftp/smtp/ssh back to visible tools (their pages return to the catalog). Generator sets merged as the union of both sides (sim in HANDWRITTEN_TRIGGER_DOCS + SKIP_TRIGGER_PROVIDERS, enrichment in the icon allowlist). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * docs: regenerate after staging merge (CodePipeline); suppress sim trigger from catalog The native Sim workspace-event trigger is documented at triggers/sim — the block writer no longer emits an integrations page for it (skip + canonical-set exclusion). CodePipeline (#4945) lands in the catalog in the Actions format. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * docs(blocks): cross-link the Memory block from the Agent memory section Final loss audit found the old page's pointer from built-in agent memory to the standalone Memory block had been dropped; one line restores it. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * docs: URLs now mirror the sidebar — sections own their pages Every page lives at a path matching its meta.json section, done now while none of these URLs are publicly live (the last free window before merge): - Workflows owns its accordions: /blocks/* -> /workflows/blocks/*, /triggers/{start,schedule,webhook,rss,table,sim} -> /workflows/triggers/*, /deployment/* -> /workflows/deployment/* - Mothership owns Mailer: /mailer -> /mothership/mailer - Workspaces & Access folds into Platform, sequenced concept-first with the reference tail last: /platform/{workspaces,organization,permissions, credentials,costs}, then platform/self-hosting/*, platform/enterprise/* (from /workspaces/fundamentals+organization, /permissions/roles-and- permissions, /credentials, /costs, /self-hosting/*, /enterprise/*) All internal links swept (0 broken in a full-tree resolver sweep), root meta.json repointed, and every previously-live URL 308s to its new home — including retargeted destinations of existing redirects so chains stay single-hop (verified: /execution/chat reaches /workflows/deployment/chat in one hop), and the native-trigger rule ordered after the enumerated integration-trigger redirects so /triggers/gmail still reaches /integrations/gmail. Production build passes. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * docs: untrack .plans/ (local agent planning files) Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * docs(preview): tool chips use the EMCN ChipTag chrome The canvas previews' tool chips were ad-hoc (5px radius, header surface, plain border). The app's canonical chip chrome is the ChipTag family: 20px tall, rounded-md, px-1, gap-1.5, --surface-5 light / --surface-4 dark with an inset --border-1 ring and --text-body label. Mirrored those values into --wp-chip-* tokens (both modes) and restyled the chip; the integration's brand-color icon square stays, sized to the chip. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * chore(blocks): one-time shift of all docsLinks to the new docs URLs Block definitions are the patterns coding agents copy from, so redirects alone leave new blocks minting dead conventions. Every docs.sim.ai link in apps/sim now points at the final URL scheme: /tools/<slug> -> /integrations/<slug> (433 links), /blocks/<core> -> /workflows/blocks/<core> (knowledge/enrichment/ logs -> /integrations/*), native /triggers/* -> /workflows/triggers/*, /mcp -> /agents/mcp, /self-hosting + /enterprise -> /platform/*, plus the llms.txt listings and the blocks.test.ts assertions. Verified every rewritten target against the docs tree: all resolve except ten hidden blocks (vision, spotify, thinking, tts...) and a2a whose links were already dead pre-reorg — no regressions introduced. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * docs: ignore .plans/ (local agent planning files) Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * docs(files): align every File-block claim with the shipped file_v5 block Accuracy audit against apps/sim/blocks/blocks/file.ts (FileV5Block, the visible block) and tools/file/*: - The block has FIVE operations, not four — Get Content was missing entirely. - Read outputs file objects only; the page claimed it also returned extracted text. Text comes from Get Content (contents, per file) or Fetch (combinedContent) — table, prose, and the Fetch callout corrected. - Functions CAN read files: sim.files.readText/readBase64 exist in the sandbox (isolated-vm-worker.cjs), so "doesn't reach into workspace storage" is gone; the section now teaches Get Content text or sim.files on the file object. - Workspace file IDs are wf_<shortId> (workspace-file-manager.ts:511), not f_. - Stale "such as Claude or GPT-4o" vision parenthetical dropped. - "File block reference" card pointed at /files (the section overview); now /integrations/file. - FILE_SUMMARY example agent consumed <file.combinedContent>, which Read never produces — now binds the file object to the Files input. - passing-files.mdx: combinedContent scoped to Fetch, contents documented. Verified intact: Write's numeric-suffix collision behavior, Fetch's auth headers, Append-by-name, and the file-object shape. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * docs: keyboard-shortcuts audited against the command registry; cut legacy workspace detail Every binding verified against commands-utils.ts (the global registry), workflow.tsx, and table-grid.tsx. Three fixes: tables Mod+A (select all rows) doesn't exist — the real bindings are Shift+Space (select row, was misworded as a toggle) and the undocumented Mod+Space (select column); the global Mod+Shift+A row conflated two commands — add-agent (Mod+Shift+A) and add-workflow (Mod+Shift+P) are separate. All 29 other documented shortcuts confirmed accurate, including tables clipboard (native copy/cut/paste events) and Mod+Y redo (tables only — correctly absent from the workflow editor section). Also drops the grandfathered_shared workspace paragraph — internal billing taxonomy, not something a reader can act on. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * docs: apply Theodore's accuracy feedback - getting-started: workflow creation is the + button next to Workflows in the sidebar (no "New Workflow" button exists); Exa/Linkup no longer need user-supplied API keys on hosted Sim (apiKey is hideWhenHosted in the Exa block) — step and FAQ updated. - workflows overview: chat and API are entry points of the Start trigger, not separate triggers — the "swap in a chat/API trigger" sentence now matches triggers/start's own model. - variables: names cannot contain periods — the resolver reads everything after the first dot as a path into the value (executor/variables/resolvers/ workflow.ts splits on dots) — constraint now stated where name normalization is taught. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * docs: Python sandbox package list (verified) + agent/agents cross-linking Function block: the Python callout's "common packages like matplotlib" becomes the actual package list, grouped by use. Sources verified 2026-06-10 and cited in an inline provenance comment: E2B's code-interpreter template requirements (the base Sim's mothership-shell template builds from) plus Sim's three pip additions (awscli/yq/csvkit, per the copilot repo's template.ts via sim-internals). Versions omitted so the list doesn't rot on routine bumps. Agent surfaces deduplicated by direction: blocks/agent's Tools section now links custom tools and MCP and points at the Agents concept page for tool sourcing; agents/index drops its duplicated Auto/Force/None enumeration in favor of the block reference, which owns config mechanics. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
1ff445ae80 |
feat(codepipeline): add AWS CodePipeline integration with tools and block (#4945)
* feat(codepipeline): add AWS CodePipeline integration with tools and block * fix(codepipeline): address review feedback on input coercion and error statuses * chore(hooks): restore use-inline-rename onSave type accidentally swept into previous commit |
||
|
|
6abcf82db2 |
feat(workflows): sim trigger, logs v2 block, toolbar renaming (#4941)
* feat(workflows): sim trigger, logs v2 block, toolbar renaming * fix(review): bound rule queries, canonical logs params, watched-workflow SQL scoping Code-review fixes: read the canonical workflowIds param in logs_v2 (the serializer deletes the source pair ids), aggregate failure-rate in the DB and switch rule windows to the indexed startedAt column, clamp rule config to the legacy contract bounds, push no_activity watch scoping into SQL before the LIMIT, fix the generated sim icon-map key, normalize docs wording, and drop dead exports. Co-authored-by: Cursor <cursoragent@cursor.com> * address comments * fix(review): integer rule rounding, success-gated workflow labels, display module hygiene Second-pass review fixes: round integer rule fields so fractional input never reaches SQL LIMIT, gate workflow-name readiness on a successful non-placeholder load in both editor and preview (errored loads mislabeled valid workflows as deleted), lazily read the variables store in preview rows, move the filter-field JSON preview into the shared display module and unexport its single-consumer helpers, and align >= boundary copy (failure rate, error count, cooldown window) with implementation. Co-authored-by: Cursor <cursoragent@cursor.com> * chore: sync lockfile after staging merge Co-authored-by: Cursor <cursoragent@cursor.com> * fix(workspace-events): keyset-paginate the no_activity subscription scan A fixed LIMIT 500 with no ORDER BY silently starved subscriptions beyond the cap once the global count exceeded it. The poll now pages by webhook id so every subscription is visited each cycle; pagination bounds memory, not total work. Co-authored-by: Cursor <cursoragent@cursor.com> * fix(workspace-events): keyset-paginate the watched-workflow scan The 500-row LIMIT silently and deterministically excluded high-id workflows from no_activity coverage in watch-everything subscriptions on large workspaces. The scan now pages by workflow id, mirroring the subscription scan; per-workflow checks move into a helper so the pagination loop stays flat. Co-authored-by: Cursor <cursoragent@cursor.com> * fix(workspace-events): skip no_activity subscriptions on the execution-completion path no_activity is poller-owned and can never fire from a completed execution, but it passed into the rule branch and cost a pointless cooldown point-read per subscription on the hottest path. Early-continue alongside the workflow_deployed guard. Co-authored-by: Cursor <cursoragent@cursor.com> * docs(sim-trigger): note failure-based alert conditions evaluate on failed runs Co-authored-by: Cursor <cursoragent@cursor.com> * fix(blocks): recategorize Data Enrichment as a core block It's a Sim-native capability (registry enrichments over a managed provider cascade, like Search), not a third-party integration. Moves it to Core Blocks in the toolbar, out of the integrations catalog, and relocates its docs page to blocks/ with the icon-map allowlist keeping the docs card icon. Co-authored-by: Cursor <cursoragent@cursor.com> * fix(blocks): recategorize MySQL, PostgreSQL, SFTP, SMTP, SSH as integrations External-system connectors with host/credential auth belong under Integrations, not Core Blocks — consistent with MongoDB, Redis, ClickHouse, and the other datastore integrations. They already carried integrationType and /tools docsLinks; the regenerated docs pages turn those previously-dangling links into real pages, and the blocks join the integrations catalog and icon maps. Co-authored-by: Cursor <cursoragent@cursor.com> --------- Co-authored-by: Cursor <cursoragent@cursor.com> |
||
|
+1 |
39418f9615 |
improvement(mothership): v0.2 (#4923)
* CONTRACTS * updates * Prompt caching * Fix regression * updates to prompt caching * Prompt caching trace * VFS updates * Changelog and plan * VFS update * Improvement/mothership (#4775) * ff * System role in cache * Fixes * Add dynamic user info * Improve tool search * improvement(platform): workspace UI/UX overhaul + integrations catalog Rework the workspace around the AI-workspace model: a Mothership home, a top-level Skills route, connected-credential and integration-detail pages, and a polished sidebar/settings surface. Replace the notifications store with a unified toast system (provider-level dismiss/pause, countdown ring). Integrations & catalog: - Add a BlockMeta layer (tags + catalog templates) scoped to catalog-visible integrations; every catalog integration carries >=7 grounded templates. - Rework the taxonomy: each block declares category tools|blocks|triggers. 3rd-party services are 'tools'; first-party primitives (postgres, mysql, knowledge, file, search, stt/tts, image/video generators, thinking, etc.) are 'blocks'. Versioned blocks follow the upgrade paradigm (old hidden, latest in toolbar/docs). - Generate integrations.json + tool docs canonically from block configs. Architecture & cleanup: - Consolidate block data extraction behind a single latest-version strategy (getCanonicalBlocksByCategory; version-consistent getBlockMeta). - Unify version-suffix handling in @sim/utils/string (stripVersionSuffix / isVersionedType, with tests); registry, generate-docs, tools/utils, and integrations all route through it. - Repair latent broken barrels, remove dead code, fix BlockMeta-related type errors and 5 broken docs links. Behavior-preserving for block execution and the toolbar's tool/block listing. * refactor(platform): remove forms, templates, and creators features Remove three standalone features and their supporting code: - Forms: form-deployment pages, API routes, execution path, and docs. - Templates: the template gallery (landing + workspace) and template APIs. - Creators: creator-profile routes and contracts. Add a super-user permissions module (lib/permissions/super-user) and an organizations API contract; update the audit/db/testing packages, billing, and the session/theme providers accordingly. * New doc setup * Fixes * Fixes * Logs tools * test(workflows): update archiveWorkflow update count after forms removal The forms feature was removed, dropping the form-table update from archiveWorkflow. Update the stale assertion from 8 to 7 tx.update calls. * Add finalization on error * Fixes * change dev CI to bun run db:push * Updates Please enter the commit message for your changes. Lines starting * Contrat update * improvement(nested): subagents * updates * upgrade * improvement(knowledge): polish tag filter dropdowns (#4816) * improvement(logs): object storage backed tracespans (#4787) * improvement(logs): obj storage backed tracespans * fix storage write context * fix tests * address comments * address comments * chore(db): remove migration 0219 to regenerate after staging merge Drops the 0219_robust_shard SQL, its snapshot, and the journal entry so the trace-spans/cost schema migration can be regenerated on top of the latest staging migration chain (avoids a number collision with staging's migrations). Co-authored-by: Cursor <cursoragent@cursor.com> * improvement(billing): accurate per-member usage via shared ledger helper Per-member/per-user usage in the org-member routes now adds the usage_log ledger to the currentPeriodCost baseline (which is no longer incremented), via a shared getOrgMemberLedgerByUser helper to avoid repeating the subscription→period→ledger lookup across the admin and member-facing routes. Co-authored-by: Cursor <cursoragent@cursor.com> * regen migrations * update migration * address comments * more code cleanup * incorrect type cast --------- Co-authored-by: Cursor <cursoragent@cursor.com> * improvement(providers): harden OpenAI-compatible providers + add tests (#4796) * improvement(providers): harden OpenAI-compatible providers + add tests * fix(vllm): let tool-loop errors propagate instead of returning silent partial success * fix(litellm): force tool_choice 'none' on final structured-output call The deferred final call used tool_choice 'auto', so the model could emit another tool_calls round instead of the structured answer, leaving content stale. Use 'none' (matching vLLM/Fireworks) on both the streaming and non-streaming final calls so the model must return the structured response. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * fix(providers/ollama): drop tools from post-tool streaming call Ollama ignores tool_choice (not in its supported fields), so vLLM/Fireworks' tool_choice:'none' guard is a no-op here. Omit tools from the final streaming payload instead so the summarization turn can't emit dropped tool calls. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * fix(litellm): spread payload into deferred final call so reasoning_effort carries over The non-streaming deferred finalPayload hand-picked fields and dropped reasoning_effort (and any future payload field), diverging from the streaming path which spreads ...payload. Spread payload here too for consistency. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * chore(providers/ollama): restore enrichment TSDoc block Keeps parity with sibling Chat Completions providers (cerebras/mistral/xai). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * docs(fireworks): restore TSDoc on utils helpers Restore the TSDoc blocks on supportsNativeStructuredOutputs, createReadableStreamFromOpenAIStream, and checkForForcedToolUsage — TSDoc is the codebase documentation standard and should not have been stripped. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * chore(litellm): remove inline rationale comments (codebase uses TSDoc) Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * chore(providers/ollama): drop orphaned enrichment TSDoc The block documented a function that now lives in trace-enrichment.ts, so it documents nothing in this file. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com> * chore(copilot): deprecate mcp server (#4797) * chore(copilot): deprecate mcp * update error codes * deprecate copilot api v1 route * feat(integrations): hosted API keys for Findymail, Prospeo, and Wiza (#4777) * feat(integrations): hosted API keys for Findymail, Prospeo, and Wiza Add hosted-key support across all credit-consuming Findymail, Prospeo, and Wiza operations so Sim provides the key when a workspace has not brought its own. Register the three BYOK providers, consolidate Wiza's two-step reveal into a single polling wiza_individual_reveal op, and hide the API key field on hosted Sim for hosted operations. * fix(integrations): harden Wiza reveal polling, soften enrichment getCost guards Address Greptile + Cursor Bugbot review on #4777: return explicit failures from the Wiza individual_reveal poller instead of throwing (thrown errors were swallowed into a false queued success), short-circuit when the initial reveal is already terminal, tolerate transient 5xx/429 during polling, and return 0 (not throw) from Findymail getCost when the contacts/employees array is absent. * chore(integrations): biome formatting after wiza merge resolution * fix(wiza): type isTerminalReveal param structurally for next build typecheck * feat(enrichments): add Findymail, Prospeo, Wiza to work-email waterfall * feat(enrichments): add Wiza + Prospeo phone reveal to phone-number waterfall * feat(enrichments): opportunistic identifiers + LinkedIn URL input across work-email & phone cascades * fix(tables): reduce column header chevron size and fix sidebar shadow bleed (#4800) * feat(slack): add install + privacy section to integration landing page (#4799) * feat(slack): add install + privacy section to integration landing page Adds a hand-authored, slug-keyed landing-content module (separate from the generated integrations.json so it survives regeneration) and renders an install walkthrough + privacy-policy link on integration pages when present. Also refreshes generated docs (data-enrichment entry, icon mappings, tool mdx). * fix(landing): render privacy section independently, align CTA analytics label * docs(landing): clarify the Slack install button is behind sign-in * refactor(landing): bake integration landing content into generated json via docs-gen Moves landing content (install walkthrough + privacy) out of a render-time augment and into the generation pipeline: generate-docs reads the pure-data content map and writes landingContent into integrations.json, so the page reads a single source (integration.landingContent). Canonical types live in integrations/data/types.ts. * improvement(enrichments): align enrichments sidebar with design system (#4801) * improvement(enrichments): align enrichments sidebar with design system * fix(enrichments): consistent close button pattern and fix url link hover * fix(misc): upgrade path change for new better-auth version, billing issue for workflow block agent usage (#4803) * fix(misc): upgrade path change for new better-auth version, double-billing for workflow block agent usage * fail loudly if stripe sub id missing * fix(copilot): seq migration (#4804) * chore(db): drop redundant idx_webhook_on_workflow_id_block_id index (#4809) Removed because (workflow_id, block_id) is a left-prefix of idx_webhook_on_workflow_id_block_id_updated_at_desc, which fully covers it. The dropped index was non-unique and enforced no constraint. * perf(copilot): read chat transcripts from copilot_messages (R+1 cutover) (#4808) * perf(copilot): read chat transcripts from copilot_messages, not JSONB Flip user-facing chat reads from the legacy copilot_chats.messages JSONB array (5.7GB, 99% TOAST) to the normalized copilot_messages table via a new loadCopilotChatMessages helper ordered by seq NULLS LAST, created_at, id — the verified canonical order. Both chat-detail getters (getAccessibleCopilotChat, getAccessibleCopilotChatWithMessages) now drop the messages column from their metadata select (no more whole-array detoast on every load) and assemble the transcript from the table after authorization. This cascades to the copilot + mothership GET endpoints and to resolveOrCreateChat's conversationHistory (the LLM payload). The normalize/effective-transcript pipeline is source-agnostic (copilot_messages.content == a JSONB array element), so transcripts are byte-identical. Dual-write and the JSONB column stay in place as the internal-logic source and fallback; removing JSONB writes is a later step. Prod integrity verified before cutover: 0 messages missing, 0 NULL-seq, 0 dup keys/seq, 0 orphans, order-parity vs JSONB = 0 mismatches. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * test(copilot): cover auth-deny on a found row skips the messages query Address PR review: exercise the `if (!authorized) return null` contract — when the chat row exists but authorization fails, the getter returns null and never issues the copilot_messages read. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com> * fix(tables): right-align run/stop in embedded toolbar; workflow cells format like normal cells (#4806) * fix(tables): right-align run/stop in the embedded table toolbar Add a right-aligned `trailing` slot to ResourceOptionsBar and move the embedded mothership table's run/stop control into it, so Filter + Sort stay left-aligned and run/stop sits opposite on the right. No-op for the search-bearing consumers (logs, resource list), which don't pass `trailing`. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(tables): workflow-output cells format values like normal cells Workflow-output columns short-circuited in resolveCellRender and rendered their value as plain text, so a sim-resource URL / external URL / JSON / date produced by a workflow never got the chip, favicon link, or typed formatting a normal cell gets. Factor value formatting into a shared `resolveValueKind` helper used by both the workflow-value branch and the plain-cell branch; the workflow branch keeps the typewriter reveal for plain streaming text via a `typewriter` flag. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(tables): detect resource/URL links on workflow output regardless of column type Workflow output columns default to `json` (columnTypeForLeaf), so routing their values through the type-based formatter (a) gated chip/URL promotion behind `column.type === 'string'` — a URL produced by a json-typed output never became a chip — and (b) JSON.stringify'd plain string values, adding quotes and losing the typewriter reveal. Detect links (sim-resource chip / favicon URL) on the value string directly for workflow outputs, falling back to the plain `value` kind; plain cells keep the type-based formatting. Addresses Greptile P2 on #4806. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(icons): repair broken integration icon rendering (#4810) * fix(icons): repair broken integration icon rendering Two distinct bugs left integration icons broken on the /integrations page (visible at 32-40px, hidden at the toolbar's 16px): 1. Corrupted SVG paths (Notion, Greptile, Granola, Calendly, Grafana, Bedrock): over-minified data dropped elliptical-arc flag digits (e.g. `A1 1 0 5.9 7` instead of `A1 1 0 0 0 5.9 7`); Granola's cubic stream was truncated. Browsers abort path parsing at the first invalid arc flag, so each rendered as a fragment or blank. Replaced with correct path data from canonical sources, preserving each icon's existing fill/gradient and bgColor. 2. Invisible glyph (Bright Data): its icon uses fill='currentColor' but bgColor was '#FFFFFF', and every surface forces text-white on the glyph - white-on-white. Changed bgColor to Bright Data's brand blue (#3d7ffc) so the white glyph reads, matching the white-glyph-on-brand-chip convention. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * fix(icons): restore Calendly dual-tone brand colors Addresses review feedback: the previous fix replaced the broken Calendly icon with a monochrome #006BFF path, dropping the cyan #0ae8f0 accent from the original dual-tone mark. Restored the two-tone logo (blue + cyan) using clean, valid path data, cropped to a tight square viewBox so it fills the chip. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * improvement(icons): enlarge icons, fix Zoom contrast and Quiver chip - Zoom: glyph was blue-on-blue (#0B5CFF on #2D8CFF chip); switched to currentColor so it renders as a white glyph on the blue chip. - Quiver: chip bgColor #000000 -> #FFFFFF to match the icon's near-white box, and enlarged the mark slightly (viewBox crop). - Enlarged (tightened viewBox, verified no clipping): RevenueCat, Prospeo, Granola, Firecrawl, Enrich.so, and the AWS icons (RDS, DynamoDB, SQS, CloudFormation, Athena, CloudWatch, SES, Bedrock, S3). - ZoomInfo left unchanged: it is a full red rounded-square logo that already fills its frame, so a crop would clip it. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * fix(icons): use Bright Data wordmark on white chip; repair Circleback - Bright Data: replaced the flame glyph with the official two-tone 'bright data' wordmark (provided asset), centered in a symmetric viewBox. Reverted the chip bgColor from #3d7ffc to #FFFFFF since the blue wordmark is invisible on a blue chip (the wordmark is designed for a light background). - Circleback: a minifier had rounded the pattern's image scale to scale(0), collapsing the embedded logo to zero size (invisible). Restored the correct scale (1/280 = 0.00357142857) so the C. mark renders. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * fix(docs): sync Quiver block color card to white chip Reflects the Quiver bgColor change (#000000 -> #FFFFFF) in the docs block info card. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * improvement(icons): enlarge AWS/Cloudflare/Dagster icons, fully white Zoom - Enlarged (tighter viewBox, render-verified, no clipping): Cloudflare, Dagster, and the red AWS icons AWS IAM, Identity Center, Secrets Manager, SES, STS. Identity Center was anomalously small (filled ~32% of its frame); the group is now sized consistently (~80% fill). - Zoom: the camera lens triangle was still #0B5CFF (blue-on-blue); switched it to currentColor so the whole camera renders white on the blue chip. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * docs(wiza): consolidate individual reveal into a single operation Merges the separate Start/Get Individual Reveal operations into one Individual Reveal operation in the Wiza docs and integrations data (operationCount 5 -> 4). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * improvement(icons): size remaining AWS icons to match the set (~80% fill) Bring RDS, DynamoDB, SQS, CloudFormation, Athena, CloudWatch and S3 up to the same ~80% fill as the AWS IAM/Identity Center/Secrets Manager/SES/STS group, so all AWS icons are visually consistent. Bedrock left as-is (already ~92% fill). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * fix(icons): use Bright Data flame mark, enlarge ZoomInfo - Bright Data: the full 'bright data' wordmark was illegible at chip size. Replaced with just the flame-'i' brand mark (blue #4280f6 on the white chip), centered. - ZoomInfo: cropped the viewBox toward the white 'Zi' so it's larger; the red rounded-square background still fills the chip. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * improvement(icons): enlarge CrowdStrike icon The falcon mark sat small in its chip because the icon used a wide 768x500 viewBox (letterboxed in the square chip). Switched to a square viewBox centered on the mark so it fills ~80%, consistent with the other icons. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com> * fix(tables): serialize schema mutations to prevent parallel column clobber (#4812) * Make workflow description nullable * fix(tables): serialize schema mutations to prevent parallel column clobber * fix(tables): load workflow outside schema lock; use DbOrTx for getTableById * fix(tables): scale idle timeout in updateColumnType to avoid aborting large type changes * fix(tables): skip stale remap types when workflowId changes concurrently * fix(tables): scale idle timeout in updateColumnConstraints for large tables * fix(wait): resume live/draft async waits and preserve cell context on chained waits (#4814) * Make workflow description nullable * fix(wait): resume live/draft async waits and preserve cell context on chained waits * improvement(knowledge): polish tag filter dropdowns * improvement(knowledge): soften filter section labels * improvement(knowledge): soften list filter labels * fix(security): harden SSO domain registration, webhook path isolation, and CSV export (#4813) * fix(security): harden KB file access, SSO domain registration, webhook path isolation, env secrets, and CSV export * fix(sso): scope domain conflict query with indexed lower(domain) filter Address PR review: avoid a full-table scan on every SSO provider registration by filtering candidate rows in SQL with lower(domain) = <normalized>, keeping the in-memory ownership check. Also tighten the normalizeSSODomain TSDoc. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * chore: condense env route security comments Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * icons update * chore(security): tighten inline comments in CSV export and KB file authorization Condense verbose comment blocks to concise TSDoc/single-line form; no behavior change. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * fix(security): validate internal serve origin in KB file authorization Replace the bypassable isInternalFileUrl substring check in resolveInternalKbKey with an origin allow-list (base URL, internal API base URL, TRUSTED_ORIGINS). A crafted external host whose path is /api/files/serve/<victim-key> no longer resolves to the victim key. Relative same-origin URLs are unaffected. * style(sso): use idiomatic sql lower() comparison for domain conflict query Match the repo's prevailing `sql`lower(col) = value`` idiom for the case-insensitive SSO domain conflict lookup. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * fix(security): align workspace env admin gate with hasWorkspaceAdminAccess Use the same admin check the secrets UI uses (owner, admin permission, or org-admin) so owners and org-admins are not wrongly denied their own decrypted workspace secrets, while read-only members remain restricted to names only. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * fix(sso): rely on lower(domain) match for conflict detection, drop dead in-memory recheck Address PR review: the SQL `lower(domain) = <normalized>` predicate already excludes rows that the in-memory `normalizeSSODomain(...) === domain` recheck claimed to catch, making that recheck dead/misleading code. Match on the canonical lower-cased domain and filter purely by ownership. Malformed legacy values (wildcards, schemes, ports) never match an email domain at sign-in, so excluding them is not a gap. Test DB mock now applies the lower() predicate so the casing-variant case is genuinely exercised. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * fix(security): scope webhook deploy path conflict to active webhooks findConflictingWebhookPathOwner omitted the isActive filter that the runtime dispatcher (findAllWebhooksForPath) applies, so an inactive but non-archived webhook from another workflow (e.g. after undeploy or failure auto-disable) would permanently block any new deployment on that path even though it never receives deliveries. Align the guard with the runtime isActive + archivedAt filter; the earliest-owner runtime check remains the authoritative cross-tenant protection. Also trims verbose TSDoc on the webhook path-isolation helpers. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * fix(security): exclude archived workflows from webhook deploy path conflict findConflictingWebhookPathOwner now joins workflow and filters isNull(workflow.archivedAt), matching the runtime dispatcher (findAllWebhooksForPath). A webhook on an archived workflow can never receive deliveries at runtime, so it must not block legitimate path reuse with a 409. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * fix(security): anchor KB file ownership to earliest document in any state A KB file's owner is now the earliest document referencing its key regardless of state (active/archived/deleted/excluded); access is granted only when that owning document is still active. Closes the residual where an attacker could plant an active document to claim a file whose original document was archived or deleted. * updated greptile icon * revert(security): drop KB file authorization changes Reverts the knowledge-base file-access work (origin-pinning / owner-pinning / origin allow-list in verifyKBFileAccess) and its test. The other hardening fixes (SSO domain registration, webhook path isolation, workspace env secrets, CSV export) are unchanged. apps/sim/app/api/files/authorization.ts is restored to its origin/staging baseline. * fix(sso): treat caller's own user-scoped provider as owned during conflict check Self-hosters often register SSO user-scoped via the CLI script (no SSO_ORGANIZATION_ID). If they later enable organizations and reconfigure the same domain org-scoped through the UI, the conflict check previously treated their own user-scoped row as another tenant's and returned a misleading 409. Recognize the caller's own user-scoped provider as owned so that migration is allowed, while still blocking another user's or another org's domain. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * revert(security): remove workspace-env admin gate Defer to a credential-based access model (separate change). Restores GET /api/workspaces/[id]/environment to main behavior and removes the test. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * refactor(security): consolidate webhook path-collision check into one helper Extract findConflictingWebhookPathOwner to lib/webhooks/utils.server.ts as the single source of truth for cross-tenant path-collision detection, used by both webhook creation paths (deploy sync and the manual /api/webhooks route). This also repairs two latent issues in the manual route's previous inline check, which queried with limit(1) and only webhook.archivedAt: - limit(1) inspected one arbitrary row, so a same-workflow row could mask a foreign collision (false negative). The shared helper scans all matching rows. - It omitted isActive/workflow.archivedAt, so inactive or archived-workflow webhooks (which never receive deliveries) permanently blocked path reuse. The helper mirrors the runtime dispatcher's filter. Same-workflow webhook reuse for upsert is now a separate, explicit lookup. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com> * fix(security): block private/reserved IPs for hosted 1Password Connect SSRF (#4818) * fix(security): block private/reserved IPs for hosted 1Password Connect SSRF * test(security): use real isPrivateOrReservedIP and cover IPv6 edge cases * improvement(integrations): validate and expand devin, cursor, and greptile (#4820) * improvement(integrations): validate and expand devin, cursor, and greptile - devin: fix missing org_id path segment on all session endpoints, add 7 session sub-resource tools (list messages/attachments, get/append/replace tags, archive, terminate), pagination, and is_archived output - cursor: add get_api_key_info, list_models, list_repositories tools - greptile: align block and docs - normalize array outputs to default [] and tighten types * refactor(cursor): simplify list_repositories v2 array normalization Collapse the redundant `?? []` + `Array.isArray` double-guard into a single Array.isArray check, per PR review feedback. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * fix(devin): scope session-tag mapping to tag ops and normalize array tag inputs - Only map sessionTags into the tools tags param for append/replace operations, preventing stale sessionTags state from clobbering create_session tags - Fall back to a wired tags value when sessionTags is empty for tag operations - Normalize tag inputs (string or wired string[]) via normalizeTags so array values from other blocks no longer throw on .split Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * fix(cursor): restore base64 file data in legacy download_artifact metadata The legacy CursorBlock exposes only content + metadata (no v2 file output), so metadata.data was the only way legacy-block workflows could access downloaded artifact bytes. Restore the base64 data field and document it in the outputs/type instead of dropping it. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * fix(devin): coerce terminateArchive to archive flag for boolean-wired input * docs(integrations): regenerate tool docs for new devin and cursor operations --------- Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com> * fix(search-replace): don't auto-navigate when content edits invalidate the active match (#4819) * fix(search-replace): don't auto-navigate when content edits invalidate the active match * fix(search-replace): clear afterReplaceIndexRef on apply failure and zero matches * fix(search-replace): remove duplicate setActiveSearchTarget(null) on close * fix(search-replace): move afterReplaceIndexRef write inside handleApply past the guard * fix(search-replace): auto-navigate when hydration resolves with no prior active match * chore(search-replace): remove inline comments * fix(search-replace): revert !activeMatchId guard that caused immediate re-navigation after deselect * improvement(enrichments): limit company-info to fields both providers return (#4817) Hunter's company dataset returns null industry/foundedYear for many large companies (verified against the live API for Microsoft, Amazon, Google), so under the first-non-empty-wins cascade those columns appeared inconsistently across rows. Limit company-info outputs to employee count and description — the fields Hunter and PDL both reliably return — so every row is consistent. employeeCount is a string so Hunter's range bucket and PDL's exact count share the column. * fix(files): don't reject external URLs containing '..' in file parse validation (#4821) * fix(files): don't reject external URLs containing '..' in file parse validation The file block's file_fetch operation rejected any external URL whose path contained '..' (e.g. Slack files-pri slugs with a literal '...') with 'Access denied: path traversal detected'. Traversal checks only apply to local paths — external http(s) URLs are fetched with SSRF protection downstream and are never resolved against the filesystem, so they now short-circuit as valid. Internal /api/files/serve/ URLs keep full traversal protection. * test(files): fix external-URL assertion to handle undefined error * test(files): assert success explicitly in external-URL traversal test * fix(files): keep traversal protection for https URLs matching internal serve paths * feat(google-sheets): add row filtering to read with numeric operators (#4822) * feat(google-sheets): add row filtering to read with numeric operators Adds client-side row filtering to the Google Sheets read (v2) operation. Filter the returned rows by a header column using text operators (contains, not_contains, exact, not_equals, starts_with, ends_with) and numeric/ordering operators (gt, gte, lt, lte). Filtering lives in a pure, unit-tested helper (filterSheetRows) and runs over the fetched read range; an optional `filter` output reports whether the column was found and how many rows matched. Also hardens the surrounding tools: - trim spreadsheetId in write/update/append URL builders (matches read) - URL-encode the v1 read default range - expose valueInputOption for the update operation in the block Backwards compatible: with no filter requested, read output is byte- identical and the `filter` field is omitted. The filterMatchType union is widened additively (4 -> 10 values). * fix(google-sheets): correct filter metadata for missing column and header-only sheets - matchedRows is now 0 (not totalRows) when the filter column is not found, so it no longer contradicts applied=false / columnFound=false - columnFound now reflects an actual header lookup for empty/header-only sheets instead of being hardcoded true - add tests covering header-only and empty sheets with present/absent columns * fix(selectors): fetch all pages for paginated dropdown list routes (#4823) * fix(selectors): fetch all pages for paginated dropdown list routes Dropdown selectors fetched only the first page of paginated provider APIs, silently hiding results past page one. Add bounded server-side draining to the list routes across Microsoft Graph, Google, Notion, Atlassian, Linear, AWS CloudWatch, and offset/token REST APIs, plus a shared client-side drain cap in the selector hook. Response shapes, stored values, and tool execution are unchanged; CloudWatch list tools still honor a caller-supplied limit. Also fixes the Word file picker that was searching for .xlsx files. * fix(selectors): harden JSM and Monday pagination draining - JSM service-desk/request-type drains advance `start` by the actual row count returned (not the fixed page size) and stop on an empty page, so a short non-final page can't skip items. - Monday boards drain now checks `response.ok` per page, surfacing a mid-drain HTTP failure instead of treating it as an empty final page and returning a partial 200. * docs(selectors): clarify JSM drain advances start by actual row count The offset-advancement fix (advance `start` by the rows returned, not the fixed page size) landed in 7b19788a8; update the TSDoc to match so it no longer reads as advancing by `limit`. * fix(selectors): drain fetchPage in direct fetchList callers Making `fetchList` optional left three direct callers (outside the useSelectorOptions hook) calling it unguarded, which broke the build's type check. Route them through a shared `loadAllSelectorOptions` helper that uses `fetchList` when present and otherwise drains `fetchPage`. This also prevents a regression: `confluence.spaces` / `knowledge.documents` now paginate via `fetchPage` only, and these callers (search/replace, value resolution) would otherwise have silently returned no options. * chore(selectors): rename MAX_PAGE_PAGES to MAX_NOTION_PAGES for readability * fix(sso): re-check domain conflict before write and reject IP-address domains (#4825) * improvement(copilot): make copilot_messages the sole transcript store, remove JSONB dual-write (#4826) Stop writing/reading the legacy copilot_chats.messages JSONB column now that reads are cut over to copilot_messages. Make appendCopilotChatMessages the primary write (throws on failure instead of swallowing), repoint peripheral readers (workspace VFS, chat cleanup, data drains, fork, superuser import) to copilot_messages, and persist the assistant turn inside finalizeAssistantTurn's transaction so it commits atomically with the stream-marker clear. The column itself is dropped in a follow-up migration after this bakes. * feat(tables): expand filter operators (not-contains, starts/ends-with, not-in, empty) (#4827) Add does-not-contain ($ncontains), starts-with ($startsWith), ends-with ($endsWith), not-in-array ($nin, previously executed server-side but unexposed in the UI), and is-empty/is-not-empty ($empty) filter operators end-to-end — SQL builder, condition types, query-builder converters/constants, the filter UI, the Table tools/block descriptions, and docs. Also fix correctness bugs in the filter builder surfaced by the wider operator set: - Same-column AND rules (e.g. age > 18 AND age < 65, or name startsWith 'A' AND name endsWith 'Z') silently overwrote each other because the AND group was keyed by column name. They now merge into one operator object, which also makes Filter -> rules -> Filter round-trip losslessly for multi-operator columns. - $nin values were not split into an array like $in, and textual-match values like "123" were numeric-coerced (breaking the ILIKE path). - A non-boolean $empty operand from the raw API silently inverted the check; it now coerces 'true'/'false' strings and otherwise returns a 400. * improvement(copilot): stop persisting tool-call result outputs in transcripts (#4829) Opening a Mothership task could take many seconds because a single persisted assistant message in copilot_messages.content can reach hundreds of MB, almost entirely inside contentBlocks[].toolCall.result.output (e.g. a get_workflow_logs or run_workflow result). The DB query is ~2ms; the cost is detoasting that payload, shipping it to the browser, and parsing it. These outputs are dead weight on the Sim side: they are never rendered (the thread shows only tool name/title/status) and never replayed to the model (the upstream copilot service owns conversation memory). So drop result.output before it is persisted, keeping result.success/error plus the tool metadata. - add stripToolResultOutput() in persisted-message.ts - apply it in messages-store toRow (covers every write path) and in loadCopilotChatMessages (existing rows render fast on read) Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com> * feat(providers): add Together AI, Baseten, and Ollama Cloud model providers (#4830) * feat(providers): add Together AI, Baseten, and Ollama Cloud model providers * fix(providers): guard Ollama streaming fast-path with hasActiveTools Match Together/Baseten/Fireworks: when tools are supplied but all are filtered out (usageControl 'none'), take the single streaming call instead of an extra non-streaming round-trip. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * fix(providers): filter non-chat model types from Together model list * refactor(providers): dedupe Ollama Cloud upstream schema ollamaCloudUpstreamResponseSchema was byte-for-byte identical to ollamaUpstreamResponseSchema (both /api/tags endpoints return the same { models: [{ name }] } shape). Drop the duplicate and reuse the shared schema. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com> * fix(knowledge): calendar view sync, deduplicate popover animation classes, type-safe filter cast * cleanup(knowledge): remove TRIGGER_BORDER_CLASS duplication, inline displayLabel, drop enabledFilterParam alias --------- Co-authored-by: Vikhyath Mondreti <vikhyathvikku@gmail.com> Co-authored-by: Cursor <cursoragent@cursor.com> Co-authored-by: Waleed <walif6@gmail.com> Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com> Co-authored-by: Theodore Li <theo@sim.ai> Co-authored-by: andresdjasso <andresdjasso@users.noreply.github.com> * feat(blocks): add BlockMeta to Quiver and Linq; fix invalid block config fields; update skills Block fixes: - Add QuiverBlockMeta (tags + 3 templates: icon generator, diagram creator, vectorizer) - Fix QuiverBlock: remove invalid tags field from BlockConfig, IntegrationType.Design → IntegrationType.AI (Design doesn't exist in the enum) - Fix GreptileBlock: remove invalid tags field from BlockConfig, IntegrationType.DeveloperTools → IntegrationType.DevOps - Fix LinqBlock: remove invalid tags field from BlockConfig (tags belong only in BlockMeta) Skills: - add-block: add dedicated BlockMeta section with structure, rules, and registration pattern; add BlockMeta checklist items - add-integration: add BlockMeta to block structure template, add rules clarifying that tags must NOT appear on BlockConfig and integrationType must be a valid enum value; update registry snippet to include blocksMeta; add checklist items * fix(integrations): fix category dropdown by defining missing LANDING_INTEGRATIONS_DATA_PATH and regenerating integrations.json The staging merge introduced landing-content.ts but forgot to define LANDING_INTEGRATIONS_DATA_PATH in generate-docs.ts, causing the script to crash before writing integrations.json. The stale JSON had integrationTypes (plural array) from an older script version, while the Integration type and workspace UI both read integrationType (singular string) — so ALL_CATEGORY_SECTIONS bucketed to undefined and the category filters never appeared in the dropdown. Fixed by adding the missing path constant and re-running the generator. integrations.json now has 192 entries with the correct integrationType field. * fix(sidebar): restore resize handle on all pages commit |
||
|
|
540835a7a5 |
feat(integrations): add AWS AppConfig integration with tools, block, and docs (#4928)
* feat(integrations): add AWS AppConfig integration with tools, block, and docs * fix(integrations): preserve latestVersionNumber 0 and tighten locationUri type in AppConfig * fix(integrations): use valid IntegrationTag values in AppConfig BlockMeta * feat(appconfig): add list_hosted_configuration_versions operation * fix(appconfig): stringify configurationVersion in block params * feat(appconfig): add full CRUD for applications, environments, and configuration profiles Adds get/update/delete for applications, environments, and configuration profiles, plus delete_hosted_configuration_version — 10 tools rounding out the integration to management-grade CRUD completeness. --------- Co-authored-by: Theodore Li <theo@sim.ai> |
||
|
|
a72e35e2f4 |
feat(sendblue): add Sendblue iMessage/SMS integration with tools and triggers (#4917)
* feat(sendblue): add Sendblue iMessage/SMS integration with tools and triggers * fix(sendblue): address review — status-aware webhook dedup, shared routing map, uniform output casing, api-key authType * fix(docs-gen): skip nested array `items` descriptor in tool input tables * chore(sendblue): use SendblueSendStyle type, trim URL identifiers * fix(sendblue): keep is_outbound routing map local to the webhook handler Avoids a webhook-providers -> triggers cross-subgraph import (single source of truth in the handler, its only runtime consumer). * fix(sendblue): remove invalid `tags` from block config (belongs on BlockMeta) |
||
|
|
c90a1eb4a6 |
feat(tables): row-gutter drag-select, Cmd+F find, and select-all polish (#4901)
* feat(ui): allow dragging on row gutters * feat(tables): Cmd+F find across cells + row-gutter UI polish Find: - New GET /api/table/[tableId]/rows/find endpoint + contract + useFindTableRows hook - findRowMatches: case-insensitive substring search across every cell via a row_number() CTE + jsonb_each_text + ILIKE, returning each matching cell with its ordinal in the filtered/sorted view. Shared buildRowOrderBySql keeps the find ordinals aligned with the paginated list (with an id tiebreak). - Cmd/Ctrl+F floating find box (search-on-Enter), cell-by-cell next/prev that loads the target row then reveals the cell via the existing anchor scroll. Gutter UI: - Row number/checkbox centered in the region left of the run button; the select-all header checkbox centers in the same region so they line up. - emcn Checkbox gains an indeterminate (minus) state; select-all shows the minus on any partial selection and clears everything on click. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * feat(tables): inline rename from the list context menu Wire the existing "Rename" item in the per-table context menu to inline rename (useInlineRename + InlineRenameInput via the Resource name cell's `content` override), matching the Files list. Enter/blur saves, Esc cancels; replaces the prior modal. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * style(tables): restyle Cmd+F find box to match workflow search Reuse the workflow search visual language (surface-1 panel, emcn Input, muted "k of N" counter, size-8 ghost chevron buttons) instead of the flat custom input. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(resource): move "Clear sort" to top of the sort menu Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
0075ab9cf6 |
improvement(platform): remove tour, simplify sidebar/header, drop loading skeletons (#4354)
* improvement(platform): workspace UI/UX overhaul + integrations catalog Rework the workspace around the AI-workspace model: a Mothership home, a top-level Skills route, connected-credential and integration-detail pages, and a polished sidebar/settings surface. Replace the notifications store with a unified toast system (provider-level dismiss/pause, countdown ring). Integrations & catalog: - Add a BlockMeta layer (tags + catalog templates) scoped to catalog-visible integrations; every catalog integration carries >=7 grounded templates. - Rework the taxonomy: each block declares category tools|blocks|triggers. 3rd-party services are 'tools'; first-party primitives (postgres, mysql, knowledge, file, search, stt/tts, image/video generators, thinking, etc.) are 'blocks'. Versioned blocks follow the upgrade paradigm (old hidden, latest in toolbar/docs). - Generate integrations.json + tool docs canonically from block configs. Architecture & cleanup: - Consolidate block data extraction behind a single latest-version strategy (getCanonicalBlocksByCategory; version-consistent getBlockMeta). - Unify version-suffix handling in @sim/utils/string (stripVersionSuffix / isVersionedType, with tests); registry, generate-docs, tools/utils, and integrations all route through it. - Repair latent broken barrels, remove dead code, fix BlockMeta-related type errors and 5 broken docs links. Behavior-preserving for block execution and the toolbar's tool/block listing. * refactor(platform): remove forms, templates, and creators features Remove three standalone features and their supporting code: - Forms: form-deployment pages, API routes, execution path, and docs. - Templates: the template gallery (landing + workspace) and template APIs. - Creators: creator-profile routes and contracts. Add a super-user permissions module (lib/permissions/super-user) and an organizations API contract; update the audit/db/testing packages, billing, and the session/theme providers accordingly. * test(workflows): update archiveWorkflow update count after forms removal The forms feature was removed, dropping the form-table update from archiveWorkflow. Update the stale assertion from 8 to 7 tx.update calls. * upgrade * improvement(knowledge): polish tag filter dropdowns (#4816) * improvement(logs): object storage backed tracespans (#4787) * improvement(logs): obj storage backed tracespans * fix storage write context * fix tests * address comments * address comments * chore(db): remove migration 0219 to regenerate after staging merge Drops the 0219_robust_shard SQL, its snapshot, and the journal entry so the trace-spans/cost schema migration can be regenerated on top of the latest staging migration chain (avoids a number collision with staging's migrations). Co-authored-by: Cursor <cursoragent@cursor.com> * improvement(billing): accurate per-member usage via shared ledger helper Per-member/per-user usage in the org-member routes now adds the usage_log ledger to the currentPeriodCost baseline (which is no longer incremented), via a shared getOrgMemberLedgerByUser helper to avoid repeating the subscription→period→ledger lookup across the admin and member-facing routes. Co-authored-by: Cursor <cursoragent@cursor.com> * regen migrations * update migration * address comments * more code cleanup * incorrect type cast --------- Co-authored-by: Cursor <cursoragent@cursor.com> * improvement(providers): harden OpenAI-compatible providers + add tests (#4796) * improvement(providers): harden OpenAI-compatible providers + add tests * fix(vllm): let tool-loop errors propagate instead of returning silent partial success * fix(litellm): force tool_choice 'none' on final structured-output call The deferred final call used tool_choice 'auto', so the model could emit another tool_calls round instead of the structured answer, leaving content stale. Use 'none' (matching vLLM/Fireworks) on both the streaming and non-streaming final calls so the model must return the structured response. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * fix(providers/ollama): drop tools from post-tool streaming call Ollama ignores tool_choice (not in its supported fields), so vLLM/Fireworks' tool_choice:'none' guard is a no-op here. Omit tools from the final streaming payload instead so the summarization turn can't emit dropped tool calls. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * fix(litellm): spread payload into deferred final call so reasoning_effort carries over The non-streaming deferred finalPayload hand-picked fields and dropped reasoning_effort (and any future payload field), diverging from the streaming path which spreads ...payload. Spread payload here too for consistency. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * chore(providers/ollama): restore enrichment TSDoc block Keeps parity with sibling Chat Completions providers (cerebras/mistral/xai). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * docs(fireworks): restore TSDoc on utils helpers Restore the TSDoc blocks on supportsNativeStructuredOutputs, createReadableStreamFromOpenAIStream, and checkForForcedToolUsage — TSDoc is the codebase documentation standard and should not have been stripped. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * chore(litellm): remove inline rationale comments (codebase uses TSDoc) Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * chore(providers/ollama): drop orphaned enrichment TSDoc The block documented a function that now lives in trace-enrichment.ts, so it documents nothing in this file. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com> * chore(copilot): deprecate mcp server (#4797) * chore(copilot): deprecate mcp * update error codes * deprecate copilot api v1 route * feat(integrations): hosted API keys for Findymail, Prospeo, and Wiza (#4777) * feat(integrations): hosted API keys for Findymail, Prospeo, and Wiza Add hosted-key support across all credit-consuming Findymail, Prospeo, and Wiza operations so Sim provides the key when a workspace has not brought its own. Register the three BYOK providers, consolidate Wiza's two-step reveal into a single polling wiza_individual_reveal op, and hide the API key field on hosted Sim for hosted operations. * fix(integrations): harden Wiza reveal polling, soften enrichment getCost guards Address Greptile + Cursor Bugbot review on #4777: return explicit failures from the Wiza individual_reveal poller instead of throwing (thrown errors were swallowed into a false queued success), short-circuit when the initial reveal is already terminal, tolerate transient 5xx/429 during polling, and return 0 (not throw) from Findymail getCost when the contacts/employees array is absent. * chore(integrations): biome formatting after wiza merge resolution * fix(wiza): type isTerminalReveal param structurally for next build typecheck * feat(enrichments): add Findymail, Prospeo, Wiza to work-email waterfall * feat(enrichments): add Wiza + Prospeo phone reveal to phone-number waterfall * feat(enrichments): opportunistic identifiers + LinkedIn URL input across work-email & phone cascades * fix(tables): reduce column header chevron size and fix sidebar shadow bleed (#4800) * feat(slack): add install + privacy section to integration landing page (#4799) * feat(slack): add install + privacy section to integration landing page Adds a hand-authored, slug-keyed landing-content module (separate from the generated integrations.json so it survives regeneration) and renders an install walkthrough + privacy-policy link on integration pages when present. Also refreshes generated docs (data-enrichment entry, icon mappings, tool mdx). * fix(landing): render privacy section independently, align CTA analytics label * docs(landing): clarify the Slack install button is behind sign-in * refactor(landing): bake integration landing content into generated json via docs-gen Moves landing content (install walkthrough + privacy) out of a render-time augment and into the generation pipeline: generate-docs reads the pure-data content map and writes landingContent into integrations.json, so the page reads a single source (integration.landingContent). Canonical types live in integrations/data/types.ts. * improvement(enrichments): align enrichments sidebar with design system (#4801) * improvement(enrichments): align enrichments sidebar with design system * fix(enrichments): consistent close button pattern and fix url link hover * fix(misc): upgrade path change for new better-auth version, billing issue for workflow block agent usage (#4803) * fix(misc): upgrade path change for new better-auth version, double-billing for workflow block agent usage * fail loudly if stripe sub id missing * fix(copilot): seq migration (#4804) * chore(db): drop redundant idx_webhook_on_workflow_id_block_id index (#4809) Removed because (workflow_id, block_id) is a left-prefix of idx_webhook_on_workflow_id_block_id_updated_at_desc, which fully covers it. The dropped index was non-unique and enforced no constraint. * perf(copilot): read chat transcripts from copilot_messages (R+1 cutover) (#4808) * perf(copilot): read chat transcripts from copilot_messages, not JSONB Flip user-facing chat reads from the legacy copilot_chats.messages JSONB array (5.7GB, 99% TOAST) to the normalized copilot_messages table via a new loadCopilotChatMessages helper ordered by seq NULLS LAST, created_at, id — the verified canonical order. Both chat-detail getters (getAccessibleCopilotChat, getAccessibleCopilotChatWithMessages) now drop the messages column from their metadata select (no more whole-array detoast on every load) and assemble the transcript from the table after authorization. This cascades to the copilot + mothership GET endpoints and to resolveOrCreateChat's conversationHistory (the LLM payload). The normalize/effective-transcript pipeline is source-agnostic (copilot_messages.content == a JSONB array element), so transcripts are byte-identical. Dual-write and the JSONB column stay in place as the internal-logic source and fallback; removing JSONB writes is a later step. Prod integrity verified before cutover: 0 messages missing, 0 NULL-seq, 0 dup keys/seq, 0 orphans, order-parity vs JSONB = 0 mismatches. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * test(copilot): cover auth-deny on a found row skips the messages query Address PR review: exercise the `if (!authorized) return null` contract — when the chat row exists but authorization fails, the getter returns null and never issues the copilot_messages read. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com> * fix(tables): right-align run/stop in embedded toolbar; workflow cells format like normal cells (#4806) * fix(tables): right-align run/stop in the embedded table toolbar Add a right-aligned `trailing` slot to ResourceOptionsBar and move the embedded mothership table's run/stop control into it, so Filter + Sort stay left-aligned and run/stop sits opposite on the right. No-op for the search-bearing consumers (logs, resource list), which don't pass `trailing`. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(tables): workflow-output cells format values like normal cells Workflow-output columns short-circuited in resolveCellRender and rendered their value as plain text, so a sim-resource URL / external URL / JSON / date produced by a workflow never got the chip, favicon link, or typed formatting a normal cell gets. Factor value formatting into a shared `resolveValueKind` helper used by both the workflow-value branch and the plain-cell branch; the workflow branch keeps the typewriter reveal for plain streaming text via a `typewriter` flag. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(tables): detect resource/URL links on workflow output regardless of column type Workflow output columns default to `json` (columnTypeForLeaf), so routing their values through the type-based formatter (a) gated chip/URL promotion behind `column.type === 'string'` — a URL produced by a json-typed output never became a chip — and (b) JSON.stringify'd plain string values, adding quotes and losing the typewriter reveal. Detect links (sim-resource chip / favicon URL) on the value string directly for workflow outputs, falling back to the plain `value` kind; plain cells keep the type-based formatting. Addresses Greptile P2 on #4806. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(icons): repair broken integration icon rendering (#4810) * fix(icons): repair broken integration icon rendering Two distinct bugs left integration icons broken on the /integrations page (visible at 32-40px, hidden at the toolbar's 16px): 1. Corrupted SVG paths (Notion, Greptile, Granola, Calendly, Grafana, Bedrock): over-minified data dropped elliptical-arc flag digits (e.g. `A1 1 0 5.9 7` instead of `A1 1 0 0 0 5.9 7`); Granola's cubic stream was truncated. Browsers abort path parsing at the first invalid arc flag, so each rendered as a fragment or blank. Replaced with correct path data from canonical sources, preserving each icon's existing fill/gradient and bgColor. 2. Invisible glyph (Bright Data): its icon uses fill='currentColor' but bgColor was '#FFFFFF', and every surface forces text-white on the glyph - white-on-white. Changed bgColor to Bright Data's brand blue (#3d7ffc) so the white glyph reads, matching the white-glyph-on-brand-chip convention. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * fix(icons): restore Calendly dual-tone brand colors Addresses review feedback: the previous fix replaced the broken Calendly icon with a monochrome #006BFF path, dropping the cyan #0ae8f0 accent from the original dual-tone mark. Restored the two-tone logo (blue + cyan) using clean, valid path data, cropped to a tight square viewBox so it fills the chip. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * improvement(icons): enlarge icons, fix Zoom contrast and Quiver chip - Zoom: glyph was blue-on-blue (#0B5CFF on #2D8CFF chip); switched to currentColor so it renders as a white glyph on the blue chip. - Quiver: chip bgColor #000000 -> #FFFFFF to match the icon's near-white box, and enlarged the mark slightly (viewBox crop). - Enlarged (tightened viewBox, verified no clipping): RevenueCat, Prospeo, Granola, Firecrawl, Enrich.so, and the AWS icons (RDS, DynamoDB, SQS, CloudFormation, Athena, CloudWatch, SES, Bedrock, S3). - ZoomInfo left unchanged: it is a full red rounded-square logo that already fills its frame, so a crop would clip it. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * fix(icons): use Bright Data wordmark on white chip; repair Circleback - Bright Data: replaced the flame glyph with the official two-tone 'bright data' wordmark (provided asset), centered in a symmetric viewBox. Reverted the chip bgColor from #3d7ffc to #FFFFFF since the blue wordmark is invisible on a blue chip (the wordmark is designed for a light background). - Circleback: a minifier had rounded the pattern's image scale to scale(0), collapsing the embedded logo to zero size (invisible). Restored the correct scale (1/280 = 0.00357142857) so the C. mark renders. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * fix(docs): sync Quiver block color card to white chip Reflects the Quiver bgColor change (#000000 -> #FFFFFF) in the docs block info card. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * improvement(icons): enlarge AWS/Cloudflare/Dagster icons, fully white Zoom - Enlarged (tighter viewBox, render-verified, no clipping): Cloudflare, Dagster, and the red AWS icons AWS IAM, Identity Center, Secrets Manager, SES, STS. Identity Center was anomalously small (filled ~32% of its frame); the group is now sized consistently (~80% fill). - Zoom: the camera lens triangle was still #0B5CFF (blue-on-blue); switched it to currentColor so the whole camera renders white on the blue chip. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * docs(wiza): consolidate individual reveal into a single operation Merges the separate Start/Get Individual Reveal operations into one Individual Reveal operation in the Wiza docs and integrations data (operationCount 5 -> 4). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * improvement(icons): size remaining AWS icons to match the set (~80% fill) Bring RDS, DynamoDB, SQS, CloudFormation, Athena, CloudWatch and S3 up to the same ~80% fill as the AWS IAM/Identity Center/Secrets Manager/SES/STS group, so all AWS icons are visually consistent. Bedrock left as-is (already ~92% fill). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * fix(icons): use Bright Data flame mark, enlarge ZoomInfo - Bright Data: the full 'bright data' wordmark was illegible at chip size. Replaced with just the flame-'i' brand mark (blue #4280f6 on the white chip), centered. - ZoomInfo: cropped the viewBox toward the white 'Zi' so it's larger; the red rounded-square background still fills the chip. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * improvement(icons): enlarge CrowdStrike icon The falcon mark sat small in its chip because the icon used a wide 768x500 viewBox (letterboxed in the square chip). Switched to a square viewBox centered on the mark so it fills ~80%, consistent with the other icons. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com> * fix(tables): serialize schema mutations to prevent parallel column clobber (#4812) * Make workflow description nullable * fix(tables): serialize schema mutations to prevent parallel column clobber * fix(tables): load workflow outside schema lock; use DbOrTx for getTableById * fix(tables): scale idle timeout in updateColumnType to avoid aborting large type changes * fix(tables): skip stale remap types when workflowId changes concurrently * fix(tables): scale idle timeout in updateColumnConstraints for large tables * fix(wait): resume live/draft async waits and preserve cell context on chained waits (#4814) * Make workflow description nullable * fix(wait): resume live/draft async waits and preserve cell context on chained waits * improvement(knowledge): polish tag filter dropdowns * improvement(knowledge): soften filter section labels * improvement(knowledge): soften list filter labels * fix(security): harden SSO domain registration, webhook path isolation, and CSV export (#4813) * fix(security): harden KB file access, SSO domain registration, webhook path isolation, env secrets, and CSV export * fix(sso): scope domain conflict query with indexed lower(domain) filter Address PR review: avoid a full-table scan on every SSO provider registration by filtering candidate rows in SQL with lower(domain) = <normalized>, keeping the in-memory ownership check. Also tighten the normalizeSSODomain TSDoc. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * chore: condense env route security comments Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * icons update * chore(security): tighten inline comments in CSV export and KB file authorization Condense verbose comment blocks to concise TSDoc/single-line form; no behavior change. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * fix(security): validate internal serve origin in KB file authorization Replace the bypassable isInternalFileUrl substring check in resolveInternalKbKey with an origin allow-list (base URL, internal API base URL, TRUSTED_ORIGINS). A crafted external host whose path is /api/files/serve/<victim-key> no longer resolves to the victim key. Relative same-origin URLs are unaffected. * style(sso): use idiomatic sql lower() comparison for domain conflict query Match the repo's prevailing `sql`lower(col) = value`` idiom for the case-insensitive SSO domain conflict lookup. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * fix(security): align workspace env admin gate with hasWorkspaceAdminAccess Use the same admin check the secrets UI uses (owner, admin permission, or org-admin) so owners and org-admins are not wrongly denied their own decrypted workspace secrets, while read-only members remain restricted to names only. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * fix(sso): rely on lower(domain) match for conflict detection, drop dead in-memory recheck Address PR review: the SQL `lower(domain) = <normalized>` predicate already excludes rows that the in-memory `normalizeSSODomain(...) === domain` recheck claimed to catch, making that recheck dead/misleading code. Match on the canonical lower-cased domain and filter purely by ownership. Malformed legacy values (wildcards, schemes, ports) never match an email domain at sign-in, so excluding them is not a gap. Test DB mock now applies the lower() predicate so the casing-variant case is genuinely exercised. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * fix(security): scope webhook deploy path conflict to active webhooks findConflictingWebhookPathOwner omitted the isActive filter that the runtime dispatcher (findAllWebhooksForPath) applies, so an inactive but non-archived webhook from another workflow (e.g. after undeploy or failure auto-disable) would permanently block any new deployment on that path even though it never receives deliveries. Align the guard with the runtime isActive + archivedAt filter; the earliest-owner runtime check remains the authoritative cross-tenant protection. Also trims verbose TSDoc on the webhook path-isolation helpers. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * fix(security): exclude archived workflows from webhook deploy path conflict findConflictingWebhookPathOwner now joins workflow and filters isNull(workflow.archivedAt), matching the runtime dispatcher (findAllWebhooksForPath). A webhook on an archived workflow can never receive deliveries at runtime, so it must not block legitimate path reuse with a 409. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * fix(security): anchor KB file ownership to earliest document in any state A KB file's owner is now the earliest document referencing its key regardless of state (active/archived/deleted/excluded); access is granted only when that owning document is still active. Closes the residual where an attacker could plant an active document to claim a file whose original document was archived or deleted. * updated greptile icon * revert(security): drop KB file authorization changes Reverts the knowledge-base file-access work (origin-pinning / owner-pinning / origin allow-list in verifyKBFileAccess) and its test. The other hardening fixes (SSO domain registration, webhook path isolation, workspace env secrets, CSV export) are unchanged. apps/sim/app/api/files/authorization.ts is restored to its origin/staging baseline. * fix(sso): treat caller's own user-scoped provider as owned during conflict check Self-hosters often register SSO user-scoped via the CLI script (no SSO_ORGANIZATION_ID). If they later enable organizations and reconfigure the same domain org-scoped through the UI, the conflict check previously treated their own user-scoped row as another tenant's and returned a misleading 409. Recognize the caller's own user-scoped provider as owned so that migration is allowed, while still blocking another user's or another org's domain. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * revert(security): remove workspace-env admin gate Defer to a credential-based access model (separate change). Restores GET /api/workspaces/[id]/environment to main behavior and removes the test. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * refactor(security): consolidate webhook path-collision check into one helper Extract findConflictingWebhookPathOwner to lib/webhooks/utils.server.ts as the single source of truth for cross-tenant path-collision detection, used by both webhook creation paths (deploy sync and the manual /api/webhooks route). This also repairs two latent issues in the manual route's previous inline check, which queried with limit(1) and only webhook.archivedAt: - limit(1) inspected one arbitrary row, so a same-workflow row could mask a foreign collision (false negative). The shared helper scans all matching rows. - It omitted isActive/workflow.archivedAt, so inactive or archived-workflow webhooks (which never receive deliveries) permanently blocked path reuse. The helper mirrors the runtime dispatcher's filter. Same-workflow webhook reuse for upsert is now a separate, explicit lookup. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com> * fix(security): block private/reserved IPs for hosted 1Password Connect SSRF (#4818) * fix(security): block private/reserved IPs for hosted 1Password Connect SSRF * test(security): use real isPrivateOrReservedIP and cover IPv6 edge cases * improvement(integrations): validate and expand devin, cursor, and greptile (#4820) * improvement(integrations): validate and expand devin, cursor, and greptile - devin: fix missing org_id path segment on all session endpoints, add 7 session sub-resource tools (list messages/attachments, get/append/replace tags, archive, terminate), pagination, and is_archived output - cursor: add get_api_key_info, list_models, list_repositories tools - greptile: align block and docs - normalize array outputs to default [] and tighten types * refactor(cursor): simplify list_repositories v2 array normalization Collapse the redundant `?? []` + `Array.isArray` double-guard into a single Array.isArray check, per PR review feedback. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * fix(devin): scope session-tag mapping to tag ops and normalize array tag inputs - Only map sessionTags into the tools tags param for append/replace operations, preventing stale sessionTags state from clobbering create_session tags - Fall back to a wired tags value when sessionTags is empty for tag operations - Normalize tag inputs (string or wired string[]) via normalizeTags so array values from other blocks no longer throw on .split Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * fix(cursor): restore base64 file data in legacy download_artifact metadata The legacy CursorBlock exposes only content + metadata (no v2 file output), so metadata.data was the only way legacy-block workflows could access downloaded artifact bytes. Restore the base64 data field and document it in the outputs/type instead of dropping it. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * fix(devin): coerce terminateArchive to archive flag for boolean-wired input * docs(integrations): regenerate tool docs for new devin and cursor operations --------- Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com> * fix(search-replace): don't auto-navigate when content edits invalidate the active match (#4819) * fix(search-replace): don't auto-navigate when content edits invalidate the active match * fix(search-replace): clear afterReplaceIndexRef on apply failure and zero matches * fix(search-replace): remove duplicate setActiveSearchTarget(null) on close * fix(search-replace): move afterReplaceIndexRef write inside handleApply past the guard * fix(search-replace): auto-navigate when hydration resolves with no prior active match * chore(search-replace): remove inline comments * fix(search-replace): revert !activeMatchId guard that caused immediate re-navigation after deselect * improvement(enrichments): limit company-info to fields both providers return (#4817) Hunter's company dataset returns null industry/foundedYear for many large companies (verified against the live API for Microsoft, Amazon, Google), so under the first-non-empty-wins cascade those columns appeared inconsistently across rows. Limit company-info outputs to employee count and description — the fields Hunter and PDL both reliably return — so every row is consistent. employeeCount is a string so Hunter's range bucket and PDL's exact count share the column. * fix(files): don't reject external URLs containing '..' in file parse validation (#4821) * fix(files): don't reject external URLs containing '..' in file parse validation The file block's file_fetch operation rejected any external URL whose path contained '..' (e.g. Slack files-pri slugs with a literal '...') with 'Access denied: path traversal detected'. Traversal checks only apply to local paths — external http(s) URLs are fetched with SSRF protection downstream and are never resolved against the filesystem, so they now short-circuit as valid. Internal /api/files/serve/ URLs keep full traversal protection. * test(files): fix external-URL assertion to handle undefined error * test(files): assert success explicitly in external-URL traversal test * fix(files): keep traversal protection for https URLs matching internal serve paths * feat(google-sheets): add row filtering to read with numeric operators (#4822) * feat(google-sheets): add row filtering to read with numeric operators Adds client-side row filtering to the Google Sheets read (v2) operation. Filter the returned rows by a header column using text operators (contains, not_contains, exact, not_equals, starts_with, ends_with) and numeric/ordering operators (gt, gte, lt, lte). Filtering lives in a pure, unit-tested helper (filterSheetRows) and runs over the fetched read range; an optional `filter` output reports whether the column was found and how many rows matched. Also hardens the surrounding tools: - trim spreadsheetId in write/update/append URL builders (matches read) - URL-encode the v1 read default range - expose valueInputOption for the update operation in the block Backwards compatible: with no filter requested, read output is byte- identical and the `filter` field is omitted. The filterMatchType union is widened additively (4 -> 10 values). * fix(google-sheets): correct filter metadata for missing column and header-only sheets - matchedRows is now 0 (not totalRows) when the filter column is not found, so it no longer contradicts applied=false / columnFound=false - columnFound now reflects an actual header lookup for empty/header-only sheets instead of being hardcoded true - add tests covering header-only and empty sheets with present/absent columns * fix(selectors): fetch all pages for paginated dropdown list routes (#4823) * fix(selectors): fetch all pages for paginated dropdown list routes Dropdown selectors fetched only the first page of paginated provider APIs, silently hiding results past page one. Add bounded server-side draining to the list routes across Microsoft Graph, Google, Notion, Atlassian, Linear, AWS CloudWatch, and offset/token REST APIs, plus a shared client-side drain cap in the selector hook. Response shapes, stored values, and tool execution are unchanged; CloudWatch list tools still honor a caller-supplied limit. Also fixes the Word file picker that was searching for .xlsx files. * fix(selectors): harden JSM and Monday pagination draining - JSM service-desk/request-type drains advance `start` by the actual row count returned (not the fixed page size) and stop on an empty page, so a short non-final page can't skip items. - Monday boards drain now checks `response.ok` per page, surfacing a mid-drain HTTP failure instead of treating it as an empty final page and returning a partial 200. * docs(selectors): clarify JSM drain advances start by actual row count The offset-advancement fix (advance `start` by the rows returned, not the fixed page size) landed in 7b19788a8; update the TSDoc to match so it no longer reads as advancing by `limit`. * fix(selectors): drain fetchPage in direct fetchList callers Making `fetchList` optional left three direct callers (outside the useSelectorOptions hook) calling it unguarded, which broke the build's type check. Route them through a shared `loadAllSelectorOptions` helper that uses `fetchList` when present and otherwise drains `fetchPage`. This also prevents a regression: `confluence.spaces` / `knowledge.documents` now paginate via `fetchPage` only, and these callers (search/replace, value resolution) would otherwise have silently returned no options. * chore(selectors): rename MAX_PAGE_PAGES to MAX_NOTION_PAGES for readability * fix(sso): re-check domain conflict before write and reject IP-address domains (#4825) * improvement(copilot): make copilot_messages the sole transcript store, remove JSONB dual-write (#4826) Stop writing/reading the legacy copilot_chats.messages JSONB column now that reads are cut over to copilot_messages. Make appendCopilotChatMessages the primary write (throws on failure instead of swallowing), repoint peripheral readers (workspace VFS, chat cleanup, data drains, fork, superuser import) to copilot_messages, and persist the assistant turn inside finalizeAssistantTurn's transaction so it commits atomically with the stream-marker clear. The column itself is dropped in a follow-up migration after this bakes. * feat(tables): expand filter operators (not-contains, starts/ends-with, not-in, empty) (#4827) Add does-not-contain ($ncontains), starts-with ($startsWith), ends-with ($endsWith), not-in-array ($nin, previously executed server-side but unexposed in the UI), and is-empty/is-not-empty ($empty) filter operators end-to-end — SQL builder, condition types, query-builder converters/constants, the filter UI, the Table tools/block descriptions, and docs. Also fix correctness bugs in the filter builder surfaced by the wider operator set: - Same-column AND rules (e.g. age > 18 AND age < 65, or name startsWith 'A' AND name endsWith 'Z') silently overwrote each other because the AND group was keyed by column name. They now merge into one operator object, which also makes Filter -> rules -> Filter round-trip losslessly for multi-operator columns. - $nin values were not split into an array like $in, and textual-match values like "123" were numeric-coerced (breaking the ILIKE path). - A non-boolean $empty operand from the raw API silently inverted the check; it now coerces 'true'/'false' strings and otherwise returns a 400. * improvement(copilot): stop persisting tool-call result outputs in transcripts (#4829) Opening a Mothership task could take many seconds because a single persisted assistant message in copilot_messages.content can reach hundreds of MB, almost entirely inside contentBlocks[].toolCall.result.output (e.g. a get_workflow_logs or run_workflow result). The DB query is ~2ms; the cost is detoasting that payload, shipping it to the browser, and parsing it. These outputs are dead weight on the Sim side: they are never rendered (the thread shows only tool name/title/status) and never replayed to the model (the upstream copilot service owns conversation memory). So drop result.output before it is persisted, keeping result.success/error plus the tool metadata. - add stripToolResultOutput() in persisted-message.ts - apply it in messages-store toRow (covers every write path) and in loadCopilotChatMessages (existing rows render fast on read) Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com> * feat(providers): add Together AI, Baseten, and Ollama Cloud model providers (#4830) * feat(providers): add Together AI, Baseten, and Ollama Cloud model providers * fix(providers): guard Ollama streaming fast-path with hasActiveTools Match Together/Baseten/Fireworks: when tools are supplied but all are filtered out (usageControl 'none'), take the single streaming call instead of an extra non-streaming round-trip. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * fix(providers): filter non-chat model types from Together model list * refactor(providers): dedupe Ollama Cloud upstream schema ollamaCloudUpstreamResponseSchema was byte-for-byte identical to ollamaUpstreamResponseSchema (both /api/tags endpoints return the same { models: [{ name }] } shape). Drop the duplicate and reuse the shared schema. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com> * fix(knowledge): calendar view sync, deduplicate popover animation classes, type-safe filter cast * cleanup(knowledge): remove TRIGGER_BORDER_CLASS duplication, inline displayLabel, drop enabledFilterParam alias --------- Co-authored-by: Vikhyath Mondreti <vikhyathvikku@gmail.com> Co-authored-by: Cursor <cursoragent@cursor.com> Co-authored-by: Waleed <walif6@gmail.com> Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com> Co-authored-by: Theodore Li <theo@sim.ai> Co-authored-by: andresdjasso <andresdjasso@users.noreply.github.com> * feat(blocks): add BlockMeta to Quiver and Linq; fix invalid block config fields; update skills Block fixes: - Add QuiverBlockMeta (tags + 3 templates: icon generator, diagram creator, vectorizer) - Fix QuiverBlock: remove invalid tags field from BlockConfig, IntegrationType.Design → IntegrationType.AI (Design doesn't exist in the enum) - Fix GreptileBlock: remove invalid tags field from BlockConfig, IntegrationType.DeveloperTools → IntegrationType.DevOps - Fix LinqBlock: remove invalid tags field from BlockConfig (tags belong only in BlockMeta) Skills: - add-block: add dedicated BlockMeta section with structure, rules, and registration pattern; add BlockMeta checklist items - add-integration: add BlockMeta to block structure template, add rules clarifying that tags must NOT appear on BlockConfig and integrationType must be a valid enum value; update registry snippet to include blocksMeta; add checklist items * fix(integrations): fix category dropdown by defining missing LANDING_INTEGRATIONS_DATA_PATH and regenerating integrations.json The staging merge introduced landing-content.ts but forgot to define LANDING_INTEGRATIONS_DATA_PATH in generate-docs.ts, causing the script to crash before writing integrations.json. The stale JSON had integrationTypes (plural array) from an older script version, while the Integration type and workspace UI both read integrationType (singular string) — so ALL_CATEGORY_SECTIONS bucketed to undefined and the category filters never appeared in the dropdown. Fixed by adding the missing path constant and re-running the generator. integrations.json now has 192 entries with the correct integrationType field. * fix(sidebar): restore resize handle on all pages commit |
||
|
|
16954e46fe |
feat(integrations): add ClickHouse block and expand Dagster + Tinybird tools (#4883)
* feat(integrations): add ClickHouse block and expand Dagster + Tinybird tools
* fix(tinybird): fail loudly on invalid query_pipe parameters JSON
parsePipeParameters previously returned {} on any JSON parse error, so a
mistyped 'parameters' input produced a successful pipe call with the dynamic
filters silently dropped. Throw a clear error for non-empty, non-object input
instead; an omitted/empty value still means 'no parameters'.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
* fix(dagster): guard NaN numeric coercions and bound list_assets pagination
Address PR review:
- Route all block numeric coercions (list_runs limit/createdAfter/createdBefore,
get_run_logs logsLimit, list_assets assetsLimit) through a toFiniteNumber()
guard so invalid/wand-generated text becomes undefined instead of NaN.
- list_assets now applies a default page size (100) when no limit is given, so
paging stays bounded and hasMore is meaningful even when limit is omitted.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
* fix(dagster): make list_assets hasMore exact via fetch N+1
Address PR review (hasMore true on exact page): request one extra row
(pageSize + 1), use its presence as the authoritative hasMore, slice it off,
and derive the returned cursor from the last RETURNED asset's key path
(JSON-serialized; Dagster normalizes JS/Python whitespace on the way in).
This removes the false-positive hasMore when the final page is exactly full.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
* fix(clickhouse): enforce read-only query operation and harden WHERE-clause guard
* fix(dagster): make list_runs hasMore exact via fetch N+1
Address PR review (list runs false hasMore): request one extra row
(pageSize + 1), use its presence as the authoritative hasMore, and slice it
off before mapping. Removes the false-positive hasMore (and misleading cursor)
when the final page is exactly `limit` runs long. Mirrors the list_assets fix.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
* fix(clickhouse): restrict DROP PARTITION to literal values to prevent SQL injection
* fix(clickhouse): reject chained statements in read-only query operation
* fix(clickhouse): force JSON output on query path and ignore comments when detecting chained statements
* fix(tinybird): encode datasource/pipe names in URL paths to prevent traversal
A user-or-llm datasource/pipe name interpolated raw into the URL path (e.g.
'real_ds/../../other') is normalized by the WHATWG URL parser and can target a
different endpoint. Wrap the path segment with encodeURIComponent in the
truncate, delete, and query_pipe URLs. Events/append pass the name via
URLSearchParams, which already encodes, so they were unaffected.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
* fix(clickhouse): block WITH-led writes/DDL in read-only query operation
* fix(clickhouse): validate column types structurally and normalize FORMAT around SETTINGS
* fix(clickhouse): balance-check ORDER BY/PARTITION BY and skip leading comments in read-only guard
---------
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
|
||
|
|
3518b999af |
feat(tables): background import for large CSVs with live progress (#4861)
* feat(tables): background import for large CSVs with live progress * fix(tables): address review — import heartbeat, overlap guard, column/empty validation * fix(tables): guard sync import overlap, scope fileKey to workspace, delete-on-replace after download * fix(tables): stream large CSV imports from storage instead of buffering the whole file * test(tables): fix async-import route tests for workspace-scoped fileKey + name uniquification * fix(tables): append imports start after existing rows; reconcile missed import failures in the tray * fix(tables): delete the uploaded CSV from storage after the import finishes * fix(tables): validate replace before deleting rows; ignore stale replayed import events by importId * fix(tables): bind import worker to its importId (no stale-worker clobber/overlap) and destroy storage stream on failure * feat(tables): byte-based import progress, cancel support, and a start toast that opens the import view * fix(tables): don't emit ready after cancel; honor cancel during the upload phase * improvement(tables): use a stop (square) icon for canceling an active import * fix(tables): make markTableImporting an atomic claim to close the concurrent-import TOCTOU race * improvement(tables): preview CSV import from a slice, drop client row-count warning The import dialog parsed the entire file in the browser to show an exact row count and a row-limit warning. That holds the whole file in memory, blocks the main thread, and hits V8's ~512MB string ceiling — so the dialog capped the effective import size well below what the streaming importer handles. Parse only the first 512KB (headers + sample for the mapping); drop the exact count and the "would exceed the row limit by N" gate. The DB row-count trigger already enforces max_rows server-side, so an over-limit import fails fast during the run with a clear message instead of being blocked by an expensive parse. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(tables): gate import ownership every batch and stop canceled imports reappearing - Worker checked run ownership only at the progress cadence (~every 5k rows), so a canceled/superseded import could insert several more batches (incl. the final partial batch) before stopping. Move the updateImportProgress ownership gate to the top of every flush — a run that lost the table stops within one batch. - A list/dialog import canceled mid-upload left the server row `importing` until the in-flight server cancel landed; hydration re-seeded it from useTablesList, so the dismissed import flickered back. Flag the real table id canceled on the mid-upload cancel path, skip re-seeding flagged tables in hydration, and clear the flag once the server import is terminal. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * refactor(tables): drive import tray by polling derived from server, not SSE Import progress no longer holds an SSE connection per importing table. The tray now derives its importing rows live from the table list (React Query), polled only while an import is in flight; the table detail page keeps its own cell-state SSE for grid refresh. - store holds only client-only state now: optimistic uploads, which terminal completions to surface this session, canceled ids, menu open — no copied importStatus/rowsProcessed. - useWorkspaceImports is the single source: polls via a data-predicate refetchInterval, derives rows, and fires completion toasts on the importing -> terminal transition. - kickoff handlers use startUpload/setUploadPercent/endUpload; the invalidated list refetch surfaces the server row and polling takes over. - removes use-hydrate-import-tray + use-import-progress-tracker (folded in). - trims over-verbose comments across the import paths. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(tables): ignore superseded-run import events in the detail SSE cache applyImport applied every replayed import payload to the detail cache. The SSE buffer can replay a prior import's terminal event for the same table, stomping a newer in-flight import's UI. Lock to the active run's importId (and ignore a replayed terminal before the id is known), matching the guard the header tracker used to have. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(tables): close sync-import TOCTOU by claiming the atomic import gate The sync import route checked importStatus from a checkAccess snapshot, then parsed/validated/wrote seconds later without taking the atomic claim. A concurrent async kickoff (markTableImporting) could slip into that window and both writers would run together — for replace mode, two delete+insert passes leave the table indeterminate. Claim the same atomic gate (markTableImporting) right before the write and release it in the finally (before the response returns, so a client refetch never sees the transient status). A row-level FOR UPDATE was avoided on purpose: it would invert lock order against the position advisory lock / row-count trigger and risk a deadlock — markTableImporting is the established gate. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(multipart): keep abort wired after resolve so a mid-upload disconnect tears down the stream readMultipart resolves on the file-part header and hands the caller an un-drained stream, but settle() ran cleanup() and detached the abort listener on that path too. A client disconnect mid-upload then destroyed nothing — busboy never saw EOF, the file stream stalled, and the route's `for await` held a request slot until maxDuration (300s). Re-arm an abort handler scoped to the file stream on resolve, detached when the stream closes. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
5d9752d563 |
fix(mothership): connect integrations from chat without state_mismatch (#4848)
* fix(oauth): skipStateCookieCheck flag change * browser initated solution * fix draft timing issue |
||
|
|
3f3efc98c3 | chore(auth): remove deprecated OAuth MCP provider plugin and backing tables (#4847) | ||
|
|
e5a46d7959 | feat(linq): add Linq iMessage/SMS/RCS integration (34 tools, block, attachment upload) (#4831) | ||
|
|
403a02c3af |
feat(providers): add Together AI, Baseten, and Ollama Cloud model providers (#4830)
* feat(providers): add Together AI, Baseten, and Ollama Cloud model providers * fix(providers): guard Ollama streaming fast-path with hasActiveTools Match Together/Baseten/Fireworks: when tools are supplied but all are filtered out (usageControl 'none'), take the single streaming call instead of an extra non-streaming round-trip. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * fix(providers): filter non-chat model types from Together model list * refactor(providers): dedupe Ollama Cloud upstream schema ollamaCloudUpstreamResponseSchema was byte-for-byte identical to ollamaUpstreamResponseSchema (both /api/tags endpoints return the same { models: [{ name }] } shape). Drop the duplicate and reuse the shared schema. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com> |
||
|
|
e1e773f487 |
feat(slack): add install + privacy section to integration landing page (#4799)
* feat(slack): add install + privacy section to integration landing page Adds a hand-authored, slug-keyed landing-content module (separate from the generated integrations.json so it survives regeneration) and renders an install walkthrough + privacy-policy link on integration pages when present. Also refreshes generated docs (data-enrichment entry, icon mappings, tool mdx). * fix(landing): render privacy section independently, align CTA analytics label * docs(landing): clarify the Slack install button is behind sign-in * refactor(landing): bake integration landing content into generated json via docs-gen Moves landing content (install walkthrough + privacy) out of a render-time augment and into the generation pipeline: generate-docs reads the pure-data content map and writes landingContent into integrations.json, so the page reads a single source (integration.landingContent). Canonical types live in integrations/data/types.ts. |
||
|
|
4b0dab4682 |
chore(copilot): deprecate mcp server (#4797)
* chore(copilot): deprecate mcp * update error codes * deprecate copilot api v1 route |
||
|
|
7f24ae12fd |
feat(block): Add data enrichment block (#4774)
* feat(enrichment): workflow Enrichment block + /api/tools/enrichment/run Add a generic Enrichment workflow block that runs a code-defined enrichment (Work Email, Phone Number, Company Domain, Company Info, …) and returns its outputs — usable in workflows, not just tables. - New internal endpoint POST /api/tools/enrichment/run (checkInternalAuth + contract) runs the same runEnrichment provider cascade; injects the workspace's hosted/BYOK key via executeTool. - New tool enrichment_run posts to it and surfaces hosted-key cost on the output so the workflow logging session bills it. - New block blocks/blocks/enrichment.ts generated from the enrichment registry: operation dropdown = enrichments, per-enrichment conditional inputs, union of conditional outputs. New registry entries appear automatically. - EnrichmentRunContext.tableId/rowId made optional (workflow path has no row). - Register tool + block; bump api-validation route baseline; add EnrichmentIcon and generated docs page. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * chore: re-trigger CI * refactor(enrichment): share mapFieldType helper between block and tool * fix(enrichment): reserved output keys (matched/provider) win over enrichment outputs --------- Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
||
|
|
c898e2e623 |
feat(integrations): add ZoomInfo, align Wiza, audit Apollo, refresh docs (#4776)
* feat(integrations): add ZoomInfo, align Wiza, audit Apollo, refresh docs - Add ZoomInfo integration: search/enrich contacts & companies, intent, news (6 tools), proxy route, block, and icon - Validate and align Wiza tools/block/outputs against live API docs - Audit Apollo tools: tighten params, outputs, and types - Update tool docs (.mdx), icons, icon mappings, and integrations.json * fix(zoominfo): use useId for ZoomInfoIcon clipPath to avoid duplicate DOM ids Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * fix(apollo): address PR review on sequence add and bulk enrich - sequence_add_contacts: send large contact_ids/label_names arrays in the POST body (Rails merges query + body params) to avoid reverse-proxy URL length limits; keep scalar settings in the query string - organization_bulk_enrich: add back-compat shim mapping the legacy `organizations` ({name, domain}[]) subBlock value to the new `domains` string array so saved workflows keep running Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * fix(integrations): unique ZoomInfo icon clip id, numeric employee range filters - ZoomInfoIcon: derive clipPath id from useId() so multiple instances don't collide - ZoomInfo company search: send employeeRangeMin/Max as numbers, matching revenueMin/Max * fix(zoominfo): send employeeRange filters as strings per API schema Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * fix(zoominfo): send contactAccuracyScoreMin as string per Contacts Search schema Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * fix(apollo): harden people_search pagination, correct bulk-update output docs - people_search: read pagination from both the nested `pagination` object (legacy /mixed_people/search) and top-level fields, avoiding silent fallback to defaults - account_bulk_update: correct output descriptions — accounts support up to 1000 per request and async is opt-in (not auto-triggered at 100 like contacts) Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * fix(wiza): correct company enrichment credits shape in output docs Company enrichment returns api_credits { total, company_credits }, not the email/phone/scrape breakdown used by individual reveals. Description-only fix verified against docs.wiza.co. * fix(apollo): send sequence add contact_ids/label_names as query params per docs Apollo documents every field for emailer_campaigns/:id/add_contact_ids as a query parameter with no request body. Append contact_ids[]/label_names[] to the query string instead of the JSON body to match the documented contract. * feat(apollo): expose account_stage_id uniform field for bulk update accounts Apollo documents account_stage_id as a Body Param for /accounts/bulk_update ('when using account_ids, apply this account stage to all accounts'). Adds it to the tool params, body builder, type, block subBlock, and params mapper alongside name/owner_id. * docs(apollo): correct contact_update typed_custom_fields description Apollo's update-a-contact endpoint documents typed_custom_fields, so drop the inaccurate "not officially documented" caveat. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * fix(zoominfo): default required outputFields on enrich; parse nested API error object - ZoomInfo enrich endpoints require outputFields; send a curated default set when omitted so requests don't fail - extractZoomInfoError now reads the GTM REST nested error object ({error:{code,message}}) instead of dropping it to a generic HTTP message Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * improvement(wiza): add wandConfig to complex prospect-search filter fields Adds AI-assist wandConfig (json-object) with format examples to the structured filter inputs (job_title, job_company, past_company, company_industry, location, company_location) and the full filters object, completing the wandConfig checklist item for the Wiza block. * fix(findymail): surface API .error messages and alphabetize registry - transformResponse error branches now fall back to the response body's `error` field before the generic status string, so Findymail's actual messages ("Not enough credits" on 402, "Subscription is paused" on 423, "One identifier is required..." on 422) reach the user instead of a bare "Findymail API error: <status>". Applied to all 11 tools. - alphabetize the findymail entries in tools/registry.ts to match the already-alphabetical import block and the integration guideline. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com> |
||
|
|
81bf93b184 |
feat(litellm): add LiteLLM as AI gateway provider (#4739)
* feat: add LiteLLM as AI gateway provider * fix: add litellm to attachments, provider store, utils, and block guards * fix: add frontend model discovery pipeline for litellm provider Add API route, contract, query hook case, and ProviderModelsLoader entry so litellm models are fetched and synced to the store on workspace load, matching the vllm/ollama/openrouter/fireworks pattern. Also fixes defaultModel to empty string and adds litellm/ prefix early-return in blocks/utils.ts (reviewer feedback). * fix: remove azureEndpoint fallback from LiteLLM provider Copy-paste artifact from vLLM provider. LiteLLM should only use LITELLM_BASE_URL, not fall back to azureEndpoint which could cause requests to be routed to the wrong server. * fix(litellm): close audit gaps from PR #4644 - byok.ts: add litellm branch to getApiKeyWithBYOK so workflow block execution can resolve the proxy key instead of throwing "API key is required for litellm ..." - check-api-validation-contracts.ts: bump route baseline 755 -> 756 to account for the new /api/providers/litellm/models route - .env.example: document LITELLM_BASE_URL / LITELLM_API_KEY - copilot edit-workflow validation: include LiteLLM in the list of user-configured prefixed providers shown to the model - providers/utils.ts: drop stray optional-chain on providers.litellm to match the vllm pattern - lint: apply biome formatting fixes (multi-line if, SVG path, multi-line DYNAMIC_MODEL_PROVIDERS) * fix(litellm): final parity gaps from second audit - blocks/utils.ts getModelOptions(): include litellm models in the combined model dropdown — was previously dropping any proxy-discovered models from the agent block model picker. - get-blocks-metadata-tool.ts mockProvidersState: add litellm bucket so the server-side copilot block-metadata fallback can render model options when the providers store is not initialized. - blocks/utils.test.ts: add litellm to mock providers state (initial + beforeEach reset) and add a parallel store-bucket guard test mirroring the vLLM case. - providers/utils.test.ts: add parallel getApiKey test for litellm. * feat(litellm): use official LiteLLM brand icon and color - icons.tsx: replace the placeholder letterform with the official LiteLLM brand mark embedded as a PNG data URI in an SVG image. - models.ts: set color: #040229 on the litellm provider definition to match the brand background. * chore(litellm): validate /v1/models response with shared schema in initialize() Match the API route handler — both code paths now run the same vllmUpstreamResponseSchema.parse() over the upstream /v1/models JSON instead of a raw type-cast, so malformed upstream payloads surface a descriptive ZodError instead of a downstream TypeError. Addresses Greptile review feedback on PR #4739. --------- Co-authored-by: RheagalFire <arishalam121@gmail.com> |
||
|
|
21c956cf97 |
improvement(hubspot): OAuth-native polling trigger replacing webhook flow (#4705)
* improvement(hubspot): OAuth-native polling trigger replacing webhook flow * feat(hubspot): property autocomplete, multi-filter, property-changed, list-membership, pipeline/owner dropdowns * fix(hubspot): freeze cursor on failure + request full OAuth scopes * chore(api): bump API route baseline from 749 to 753 for HubSpot selector routes * fix(hubspot): make eventType required conditional on visibility * improvement(hubspot): align trigger name and longDescription with poll-trigger conventions * fix(hubspot): encodeURIComponent on search path segment for defense-in-depth * fix(hubspot): cursor-based seed for list_membership polling * fix(hubspot): Map-backed property snapshot + drop redundant filter parse |
||
|
|
47bd7fa345 |
fix(logs-cleanup): listing active workspaces into mem + download time streaming lims (#4692)
* fix(logs-cleanup): listing active workspaces into mem + download time streaming lims * fix * fix ci * address comments * add skill * fix client-server sep * fix parse bytes enforcement * address comments, antipatterns * address slides ssrf comment * more fixes * fix tests * fix |
||
|
|
46db40620f |
feat(mcp): OAuth 2.1 + PKCE for outbound MCP servers (#4441)
* feat(mcp): OAuth 2.1 support for outbound MCP servers
* fix(mcp): tighten OAuth refresh race and session-error detection
Re-load the OAuth row inside withMcpOauthRefreshLock so concurrent
callers observe predecessor-written tokens instead of a stale snapshot
loaded before lock acquisition. Without this, the second caller's
provider held a rotated-out refresh token and the SDK tripped
invalid_grant, forcing reauthorization.
Switch isSessionError to match the SDK's typed StreamableHTTPError
(code 404/400) instead of substring-checking arbitrary error messages,
removing false positives on URLs that happen to contain those digits.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
* refactor(mcp): tighten OAuth callback contract and registration metadata
- Validate callback query params via mcpOauthCallbackContract instead of
raw searchParams.get, matching the rest of the MCP route surface.
- Drop non-RFC-7591 application_type field from dynamic client registration
to avoid rejection by strict authorization servers.
- Collapse the pre-lock OAuth row load in createClient — the row is now
loaded exclusively inside withMcpOauthRefreshLock, removing a redundant
query and a stale-snapshot path.
* fix(mcp): narrow workspaceId before async closure in OAuth createClient
* fix(mcp): return authType from create-server endpoint
The POST /api/mcp/servers handler omitted authType from the success
response, so useCreateMcpServer always saw data.data.authType as
undefined and never triggered the OAuth popup after creating an
OAuth-protected server. Thread authType through performCreateMcpServer
into the response so the client can decide whether to auto-start OAuth.
* fix(mcp): mirror server null normalization in optimistic oauthClientId update
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
* fix(mcp): revert optimistic oauthClientId to undefined to match McpServer type
The response contract preprocesses null → undefined, so McpServer.oauthClientId
is string | undefined. Using null broke type checking.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
* fix(mcp): tighten OAuth probe signal and clear stale popup interval
- probe: only classify as OAuth on resource_metadata or scope params.
Bare `Bearer error="invalid_token"` is generic and used by API-key servers,
so it must not auto-flip the auth type to OAuth.
- popup hook: clear any existing close-watcher interval before overwriting
when startOauthForServer is invoked twice for the same serverId.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
* fix(mcp): normalize empty-string oauthClientId at route boundary
Orchestration already converts falsy → null via `|| null` (server-lifecycle.ts),
so the DB was never receiving an empty string. Tightening the route layer to
match the same convention keeps the boundary contract consistent and avoids
relying on downstream normalization.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
* feat(canvas): expand MCP tool params into per-row labels on block tile
The MCP Tool block on the workflow canvas previously crammed every selected-
tool parameter into a stringified blob under the `Tool` row. Now, when a tool
is selected, the tile reads the cached `_toolSchema` and emits one labeled
SubBlockRow per parameter (matching the Exa block's per-param layout). Labels
reuse `formatParameterLabel` for parity with the editor panel; values pass
through the existing `getDisplayValue` so booleans/numbers/arrays render
identically to other blocks. Deterministic tile height counts expanded rows
so the tile sizes correctly.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
* feat(logs): show MCP icon and strip prefix in trace tool spans
Tool spans for MCP calls were rendering the raw id (e.g.
`mcp-f908f259-planetscale_list_organizations`) with the default blank-
square icon. Now they read just the tool name and render the MCP block's
icon and bgColor, matching how workflow-execute tools render.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
* fix(logs): lift near-black trace icon backgrounds for dark-mode contrast
Block bgColors below a small luminance threshold (e.g. the MCP block's
#181C1E) rendered nearly invisible against the dark-mode surface
(--bg: #1b1b1b). Adds a tiny adjustBgForContrast helper that floors each
RGB channel at 0x33 only when luminance is below 30,000, leaving every
branded color above that band untouched. Applied to both the trace tree
row and the detail pane.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
* fix(logs): fall back to neutral gray for near-black trace icon bgs
#333333 was still too close to the dark-mode surface to read. For bgs
below the luminance threshold (e.g. the MCP block's #181C1E) we now fall
back to DEFAULT_BLOCK_COLOR (#6b7280) — the same neutral the renderer
uses for blocks with no distinct identity. Clearly visible in both
themes; brighter brand colors still pass through.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
* chore(db): drop 0209_mcp_oauth migration ahead of staging merge
Staging shipped 0209_smiling_fixer; the MCP OAuth migration will be
regenerated on top of staging as 0210.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
* chore(db): regenerate MCP OAuth migration as 0210
Re-runs drizzle-kit generate on top of staging's 0209_smiling_fixer.
Same schema (mcp_server_oauth table + mcp_servers.auth_type / oauth_*
columns) as the dropped 0209_mcp_oauth.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
* chore(audit): bump route baseline 748 → 749 after staging merge
The post-merge route count is 749 (this branch's OAuth start/callback
plus staging's new route). I had set the baseline to 748 in the merge
conflict resolution — bumping to match reality so the strict audit
passes.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
* chore: remove source-command skill files committed by accident
These were untracked-then-accidentally-staged in
|
||
|
|
f0311a6f5e |
feat(table): chunked dispatcher + workflow cascade (#4672)
* feat(table): chunked dispatcher for workflow-column runs
Replaces the all-rows-at-once runWorkflowColumn with a row-window dispatcher
backed by a new table_run_dispatches row. Each user click inserts a dispatch
row and triggers a trigger.dev task that crawls the table 20 rows at a time,
re-enqueueing itself between windows. The HTTP/Mothership entrypoints return
{ dispatchId } immediately instead of holding the request open for minutes
on multi-thousand-row dispatches.
- Per-row cancel stamps cancelledAt; the dispatcher skips cells whose
cancelledAt > dispatch.requestedAt so a mid-cascade cancel sticks even
under isManualRun.
- Table-wide cancel marks active dispatches cancelled atomically so the
dispatcher bails on its next iteration.
- New 'dispatch' SSE event variant plumbed; client ignores for v1.
* fix(table): eager bulk clear on column run so cells flip immediately
Run-column with run-mode 'all' wasn't visually flipping rows that already
had data — the cell renderer's "value wins" branch kept showing the prior
output behind the queued/running state. The dispatcher only cleared one
window of rows at a time, so most of the column stayed stale until the
cursor walked to it.
Now:
- Dispatcher's `pending → dispatching` transition runs a single SQL UPDATE
that wipes targeted `data` output columns and `executions[gid]` across
every targeted row (mode-aware: 'incomplete' skips fully-filled rows).
- Per-window clear in `dispatcherStep` is gone — rows are pre-cleared,
the loop only filters cancel tombstones / unmet deps and enqueues.
- Optimistic patch in `useRunColumn` mirrors the bulk clear by nulling
output values in the cached row, so the UI flips queued/running
instantly without waiting for the SSE catch-up.
* fix(table): bulk clear honors in-flight execs under mode: 'incomplete'
The eager bulk clear for mode: 'incomplete' only skipped rows that were
already fully filled, so two overlapping dispatches could race — dispatch B
would nuke executions[gid] on a row dispatch A had just stamped 'queued',
flickering the cell and potentially confusing the worker.
Skip any row whose targeted group is currently queued/running/pending — an
'incomplete' run shouldn't touch what another dispatch is actively working
on. The per-walk 'in-flight' eligibility skip already handles rows that
flip in-flight between the clear and the cursor reaching them.
* refactor(table): dispatcher uses batchTriggerAndWait + tag-based cancel
Switch the per-window cell fan-out from fire-and-forget tasks.trigger to
tasks.batchTriggerAndWait. The dispatcher is now a single long-lived
trigger.dev task that loops dispatcherStep until the table is exhausted;
trigger.dev CRIU-checkpoints the parent during each wait so we don't pay
compute while cells execute. Queue depth is bounded at WINDOW_SIZE per
dispatch — no more flooding trigger.dev with a million queued runs.
- dispatcher.ts builds payloads via the new shared buildPendingRuns helper
and calls tasks.batchTriggerAndWait directly. Pre-stamps each cell to
`queued` (jobId=null) so the UI flips instantly.
- table-run-dispatcher.ts is now a plain while-true loop. No
RUN_BUDGET_MS, no self-re-enqueue, no cold-start tax per window.
Cancel:
- New cancelCellRunsByTags(tags) paginates runs.list + runs.cancel(id).
- cancelWorkflowGroupRuns fires the tag-sweep alongside the per-jobId
queue.cancelJob path (preserved for auto-fire cells that have real
jobIds from single tasks.trigger calls).
- Trigger.dev acks the cancel → batchTriggerAndWait resumes → dispatcher
observes the dispatch-row cancel flag → exits.
Side fixes:
- getAsyncBackendType returns 'trigger-dev' whenever taskContext.isInsideTask
is true, regardless of TRIGGER_DEV_ENABLED env. The preview/dev-sim
worker silently routing cell jobs to DatabaseJobQueue (no poller) is
fixed without any env config change.
- runWorkflowColumn skips the dispatcher entirely when trigger.dev is
disabled, running cells inline via DatabaseJobQueue.runInline. HTTP
response returns dispatchId: null in that mode.
- runColumnContract response schema updated to dispatchId.nullable().
* fix(table): show Stop button on optimistic-pending row cells
isExecInFlight required a jobId for `pending` status, gating it as "real
backend pending" vs "optimistic flag only." The row-gutter Stop button
keyed on this — so a freshly clicked Play sat as `pending` (no jobId) and
the user couldn't cancel it until the server-side `queued` stamp arrived
via SSE. With the dispatcher pre-batch stamping cells as `queued` (not
`pending`) and no per-cell jobIds under batchTriggerAndWait, the gap was
worse.
Drop the jobId requirement. `pending` now counts as in-flight everywhere.
Cancel writes `cancelled` to the cell exec authoritatively whether or not
a real trigger.dev run exists yet — cancelling an optimistic cell means
"don't run this," which is correct.
Also collapse isOptimisticInFlight into isExecInFlight since the two
helpers are now identical.
* refactor(table): loop-in-cell cascade + dispatcher-everywhere routing
Two coupled changes:
1. Cell-task runs the row's full cascade in-process. executeWorkflowGroupCellJob
acquires a Redis lock per (tableId, rowId) with heartbeat (10s/30s TTL),
then loops through eligible workflow groups for the row. One cell-task =
one row's full cascade, not N. Resume worker holds the same lock and
continues the cascade after a HITL resume. Shared withCascadeLock helper
in lib/table/cascade-lock.ts.
2. Every cell-enqueue goes through the dispatcher. The implicit
scheduleRunsForRows reactor in service.ts is removed — 8 callsites
(insertRow, batchInsertRows, upsertRow, updateRowsByFilter,
batchUpdateRows, addWorkflowGroup, updateWorkflowGroup) now fire
runWorkflowColumn with mode: 'incomplete', isManualRun: false. HTTP
routes that call updateRow directly also fire runWorkflowColumn
afterwards. scheduleRunsForTable / scheduleRunsForRowIds deleted;
scheduleRunsForRows demoted to private (only the TRIGGER_DEV_ENABLED=false
fallback uses it). skipScheduler flag dropped from UpdateRowData /
BatchUpdateByIdData — no longer meaningful since there's nothing implicit
to suppress.
Plumbed isManualRun through the dispatch row (new is_manual_run column,
default true) so auto-fire callers honor autoRun: false and don't re-run
completed cells.
Stamp 'pending' (not 'queued', executionId: null) before
batchTriggerAndWait — cell-task writes its own 'queued' on lock acquire.
Small UI polish: row gutter Play button spacing, "Delete workflow" →
"Delete column" label, optimistic-pending cells now show Stop button
(isExecInFlight no longer requires jobId).
* fix(table): SQL cancellation guard allows worker to claim a null-execId cell
The dispatcher's pre-batch `pending` stamp leaves executionId unset so any
cell-task that wins the cascade lock can claim the cell. The cancellation-
guard SQL clause was rejecting these claims because it tested
`executions->gid IS NULL` (whole exec missing) but the pre-stamp leaves
the exec present with executionId=null.
Add a third carve-out: `executions->gid->>'executionId' IS NULL`. Now the
guard reads "write allowed if no exec exists, OR no executionId is set
yet, OR the executionId matches ours."
Symptom: every cell-task's first markWorkflowGroupPickedUp call would log
"SQL guard saw cancelled" and skip, leaving cells stuck at the dispatcher's
pending stamp.
* fix(table): dispatcher cursor starts at -1 so position 0 is included
The dispatcher's row-window SELECT is `position > cursor` for exclusive
lower-bound semantics. With cursor initialized to 0, position-0 rows were
never picked up — every dispatch silently skipped the table's first row.
Start cursor at -1 instead. First window's filter `position > -1` matches
position 0; subsequent iterations advance to `lastPosition` which then
correctly excludes already-processed rows.
* refactor(table): align optimistic UI with new dispatcher; sticky cancel via 'new' mode
Fix 0: new `DispatchMode = 'new'` for auto-fire callsites. Eligibility skips
rows with any prior `executions[gid]` entry — cancelled / errored / completed
cells stay sticky until a manual run. Dispatcher's windowed SELECT pushes
`NOT jsonb_exists_any(...)` to SQL so CSV imports into mostly-attempted
tables don't pay a per-window load+JS-filter. `batchInsertRows` drops its
`rowIds` payload (keeps dispatch scope tiny on big imports).
Fix A/B/D: client optimistic patches now mirror the backend's actual
invariants. `useCreateTableRow.onSuccess` stamps eligible groups via
`optimisticallyScheduleNewlyEligibleGroups` so newly-inserted rows show
`Queued` instantly. `useCancelTableRuns.onMutate` distinguishes optimistic-
only pending (`executionId == null` — strip silently) from real worker
claims (stamp cancelled; SSE will reconcile). Drop `onSettled` invalidation
on `useUpdateTableRow` / `useBatchUpdateTableRows` to kill the
delete-cell flicker.
Fix C: active-dispatches overlay. New `listActiveDispatches` helper,
contract, and `GET /api/table/[tableId]/dispatches` route. `kind:'dispatch'`
SSE events carry scope+cursor+mode on every transition. New
`useActiveDispatches` hook + `resolveCellExec` synthesize a virtual
`pending` exec for cells in an active dispatch's scope ahead of cursor —
queued indicators now survive page refresh during long Run-all dispatches.
`cancelWorkflowGroupRuns` emits `kind:'dispatch',status:'cancelled'`
events so the overlay clears without a refetch.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* refactor(table): unify trigger.dev and inline dispatcher paths
`runWorkflowColumn` now always inserts a `table_run_dispatches` row and
drives the dispatcher state machine. The trigger.dev / in-process branch
narrows to a single line: trigger.dev fires `tableRunDispatcherTask` (which
calls the new `runDispatcherToCompletion`), the inline path calls the same
helper fire-and-forget. Deletes `scheduleRunsForRows` and
`stampQueuedOrCancel` — the inline-fallback no longer duplicates window
walking, SSE emission, or cancel.
The dispatcher's window-execute call goes through `JobQueueBackend`:
- New `batchEnqueueAndWait` interface method.
- Trigger.dev impl wraps `tasks.batchTriggerAndWait` behind a
`taskContext.isInsideTask` guard (clear error if called from outside a
task).
- Database impl skips `async_jobs` entirely — `Promise.all` over
`options.runner(payload, signal)` per item, with per-cell AbortControllers
tracked by `cancelKey` for cancel.
`cancelInlineRun` moves to the interface as `cancelByKey` so
`cancelWorkflowGroupRuns` no longer reaches into the database backend.
Fix `mode: 'new'` SQL filter:
- `${array}::text[]` interpolated as a tuple-cast which Postgres rejected
("cannot cast type record to text[]") and every inline dispatch silently
failed. Switched to `ARRAY[${sql.join(...)}]::text[]`.
- Predicate was `jsonb_exists_any` ("any one targeted group present"),
which excluded rows that needed at least one group re-run after a
downstream output was deleted. Switched to `jsonb_exists_all` — per-group
JS eligibility handles the rest.
Cascade-loop workflowId bug: `runRowCascadeLoop` was not threading the new
group's `workflowId` when advancing across groups. The cell-task ran the
previous group's workflow against the next group's cell, terminating
`completed` with empty `accumulatedData`. Fixed by tracking
`currentWorkflowId` alongside `currentGroupId` / `currentExecutionId`.
Client optimistic-patch tightening:
- `useRunColumn.onMutate` mirrors server eligibility — skip cells with
unmet deps so unmet rows don't flash Queued and get stuck (no SSE will
arrive for cells the server skipped).
- `resolveCellExec` overlay synthesizes a virtual `pending` only when
`areGroupDepsSatisfied` is true. Rows with unmet deps render Waiting,
matching the dispatcher's actual behavior.
Cleanup from /simplify pass:
- Use `generateShortId(20)` instead of
`generateId().replace(/-/g, '').slice(0, 20)`.
- Inline `batchEnqueueAndWait` no longer allocates synthetic ids
(returned `string[]` is unused).
- Flattened the per-cell `tracked` array — only push entries that
registered controllers, drop the null placeholders.
- Extracted `runDispatcherToCompletion` to share the loop between the
trigger.dev wrapper and the in-process path.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* feat(table): backend running counter, dep-aware retrigger, sidebar polish
Counter (Fix 1): top-right "X running" + per-row badge are now
backend-bootstrapped via a count on `user_table_rows.executions ->> 'status'
= 'running'` returned alongside active dispatches. SSE `kind: 'cell'` events
compute a delta from `prev → next` status to keep the cache live; cell
events for rows outside the loaded page slice trigger a run-state refetch.
On `pruned` we invalidate the cache. Counts only worker-claimed `running`
cells — optimistic queued/pending no longer inflate the badge, and rows
outside the loaded page slice are counted too.
Sidebar (Fix 2 + 3a): `Run after` no longer ticks every column by default
for new groups (empty list). Save is disabled with an inline error when
auto-run is on with zero deps. `edit-group` mode anchors the left-of-current
filter to the group's leftmost column, so a workflow can only depend on
columns to its left.
Reorder scrub (Fix 3b): `updateTableMetadata` walks the schema's workflow
groups when `columnOrder` is in the patch and drops any dep whose new
position lands at or after the group's leftmost column (uses the existing
`stripGroupDeps` helper). Metadata + schema updates land atomically.
Server returns ordered columns (Fix 3b cont'd): `getTableById` /
`listTables` now sort `schema.columns` by `metadata.columnOrder` before
returning, via a new `applyColumnOrderToSchema` helper. Every consumer
(grid, sidebar, copilot, mothership) gets one ordered list — the sidebar's
leftmost-group-column anchor now points at the right index.
Dep-aware retrigger (Fix 4): editing a value that a downstream workflow
depends on now re-runs that workflow.
- `deriveExecClearsForDataPatch` returns
`{ executionsPatch, inFlightDownstreamGroups }`. Walks
`schema.workflowGroups[].dependencies.columns` for every column in the
patch, clears terminal-state downstream entries, and reports in-flight
entries.
- `updateRow` calls `cancelWorkflowGroupRuns` + `runWorkflowColumn`
(`mode: 'incomplete' + isManualRun: true`) for in-flight downstream
groups, then always fires `runWorkflowColumn({ mode: 'new' })` for the
cleared groups. Skips both when `executionsPatch` is provided by the
caller — those are cell-task / cancel writes that would otherwise spawn
a recursive flood of dispatches per partial-write.
- `cancelWorkflowGroupRuns(tableId, rowId, { groupIds? })` accepts a
per-group filter so the cancel only touches the affected groups, not
every in-flight cell on the row.
- `pickNextEligibleGroupForRow` now treats a dispatcher pre-stamp
(`pending` + `executionId: null`) as claimable — the cascade-loop is the
real owner. Without this, the dispatcher's pre-stamp of downstream
groups made the cascade-loop see them as "in-flight" and skip them,
stranding `pending` cells forever.
- `optimisticallyScheduleNewlyEligibleGroups` extends the cache patch to
flip dep-touched groups to `pending` regardless of their current status,
matching the server's cancel-then-rerun behavior.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* fix(table): paused workflow cells route through executeResumeJob; render Pending + viewable
Three connected issues with workflows that pause mid-cell (e.g. wait blocks):
1. `/api/resume/poll` (the time-pause auto-resumer) called
`PauseResumeManager.startResumeExecution` directly, bypassing
`executeResumeJob` from `background/resume-execution.ts`. The wrapper is
where the cell-context restoration + cascade-loop continuation lives —
without it, the resumed workflow ran to completion but never wrote the
terminal state back to the table cell. Cell stays `pending` forever
even though the underlying execution finished.
Fix: dynamically import `executeResumeJob` and use it for the
`'starting'` branch. Same primitive the trigger.dev `resumeExecutionTask`
wraps — calling it directly handles both trigger.dev-disabled local dev
and trigger.dev-enabled prod identically.
2. The cell renderer mapped `status: 'pending'` to `kind: 'queued'` (gray
"Queued" badge) regardless of whether the run had started. A HITL-paused
run has `status: 'pending'` + `jobId` prefixed `paused-` + a real
`executionId` — semantically very different from "queued, hasn't run."
Now renders as `pending-upstream` (the existing Pending pill) for
paused-jobId rows.
3. Right-click "View execution" was disabled for `pending` cells (gated to
`completed | error | running`), so users couldn't open the trace for a
paused execution. Paused runs have a viewable trace (the executionId is
real and the log row exists). Both the per-row context menu and the
action-bar derivation now recognize `pending` + `paused-` jobId as a
started run.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* feat(table): typewriter reveal for SSE-driven workflow cell values
Workflow-output cells now reveal their text character-by-character when an
SSE update lands, while page reloads and virtualization remounts still paint
the value instantly. A first-render guard inside the new useTypewriter hook
distinguishes hydration from live updates with no plumbing through the cell
tree.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* fix(table): address bugbot/greptile review feedback
Two P1 issues + one cleanup from the bot reviewers:
1. **Double-dispatch + completed-output wipe.** Both PATCH row routes
(`app/api/table/[tableId]/rows/[rowId]` and
`app/api/v1/tables/[tableId]/rows/[rowId]`) were firing a second
`runWorkflowColumn({ mode: 'incomplete' })` after `updateRow` returns.
`updateRow` already fires `mode: 'new'` internally for user edits, so
the second call created a concurrent dispatch. Worse, the
`mode: 'incomplete'` path's `bulkClearWorkflowGroupCells` wipes ALL
targeted output columns on any row where any one column is empty —
meaning sibling-group completed outputs could be erased. Removed both
route-level calls; auto-dispatch lives entirely in `updateRow`.
2. **`runWorkflowColumn` log-spamming on plain tables.**
`if (targetGroups.length === 0) throw new Error(...)` fired on every
row insert/update for tables without any workflow groups (the
majority). Every caller wraps with `.catch(logger.error)`, so each
PATCH produced an error-level log. Return `{ dispatchId: null }`
silently — manual `runWorkflowColumn` callers pass `groupIds`
explicitly so they can't reach this branch.
3. **`isManualRun` plumbed through dispatch SSE events.** Late-arriving
`kind: 'dispatch'` events for dispatches not in the initial fetch
were hardcoding `isManualRun: false`. Added the field to the event
shape, emit it from `dispatcherStep` (pending → complete, dispatching
transitions) and `markActiveDispatchesCancelled`, and consume it in
the SSE handler with a sensible fallback for legacy emits.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* refactor(table): row executions sidecar + left-to-right dep retrigger + cancel counter refresh
Split per-row workflow-group execution state out of the user_table_rows.executions
JSONB column into a new table_row_executions sidecar keyed by (row_id, group_id).
Dispatcher filters, "X running" counter, bulk clears, and the cancellation guard
all hit indexed columns instead of walking JSONB. Wire shape unchanged — server
merges sidecar rows back into row.executions on the way out.
Also:
- deriveExecClearsForDataPatch now walks workflowGroups left-to-right with a
propagating dirtied-column set so transitive dep chains (edit col A → group 1
re-runs → group 2 depends on group 1's output → group 2 re-runs) collapse to
a single forward pass.
- useCancelTableRuns.onSettled invalidates the activeDispatches query so the
top-right counter and row gutter Stop button refetch from the server after
any Stop (per-cell, row, or table-wide). countRunningCells is the source of
truth; client no longer needs duplicate state.
Three migrations on this branch (0209 + 0210 + new sidecar) collapsed into one
since the feature is unreleased.
* fix(table): address remaining cursor/greptile review feedback
- Mothership update_row no longer double-dispatches. updateRow already fires
the auto-cascade internally; the second `mode: 'incomplete'` call here
raced with it and could bulk-clear sibling-group outputs.
- SSE dispatch events no longer dropped when the activeDispatches cache is
cold. Seed an empty TableRunState if the initial fetch hasn't landed yet
so the queued overlay doesn't lose the first dispatch event.
- batchUpdateRows now runs cancel+rerun for per-row in-flight downstream
groups, mirroring updateRow. Without this, dep edits in a batch left
running workflows reading stale upstream values.
* fix(table): cancel prior runs, scope batch insert dispatch, recover orphan pre-stamps
Addresses cursor + greptile review feedback on table dispatcher edge cases:
- Manual table-wide Run-all / Run-column now cancels prior active dispatches
AND in-flight cell workers before bulk-clearing. Without this, mode:'all'
deleted running sidecar rows out from under their workers (which kept
writing into the wiped state) and a second Run-all could enqueue overlapping
cells racing on the same rows. Row-scoped manual calls (dep-edit cascade)
are excluded — those already cancel their own scope.
- batchInsertRowsWithTx now scopes its auto-dispatch to the newly-inserted
row ids. Without this, after the sidecar migration the NOT EXISTS filter
matches every existing row (zero sidecar entries), so a CSV import would
walk the entire table dispatching workflow runs on every pre-existing row.
- classifyEligibility carve-out: pending + executionId=null is an orphan
pre-stamp (cascade-lock contention, batchEnqueueAndWait failure, etc.),
treated as claimable so future dispatchers can re-stamp instead of skipping
it as 'in-flight' forever. Matches pickNextEligibleGroupForRow's logic.
- On batchEnqueueAndWait failure, dispatcherStep now sweeps the orphan
pre-stamps it wrote for the failed batch so the cells don't render Queued
forever; the next user action picks them up cleanly.
* fix(table): row-scoped Refresh cancels in-flight; counter includes queued/pending
- runWorkflowColumn now cancels prior in-flight cells for row-scoped manual
runs too (context-menu Refresh on a row subset, action-bar Refresh on
selected rows). Previously only the table-wide path cancelled, so a
row-scoped Refresh would bulk-clear running sidecar rows without aborting
workers. Per-row cancel skips markActiveDispatchesCancelled so unrelated
dispatches keep running.
- countRunningCells now counts all in-flight statuses (queued / running /
pending) instead of just running. The row gutter Run/Stop button reads
this map — with the old behavior, clicking Play during the queued window
would re-enqueue an already-queued cell. SSE applyCell handler updated
to use isExecInFlight so client deltas track the same semantics.
* fix(table): per-row Stop tombstones ahead-of-cursor rows during Run-all
Per-row Stop only cancelled sidecar rows already in flight. A row the
dispatcher hadn't reached yet had no exec record, so Stop was a no-op there
— the dispatcher would later walk to it, classify the group eligible, and
re-fire workflows the user thought they stopped.
cancelWorkflowGroupRuns now, for a per-row cancel, checks active dispatches
whose scope covers the row and writes `cancelled` tombstones (cancelledAt =
now) for the at-risk groups that don't already have a sidecar entry. The
dispatcher's existing `cancelledAt > dispatch.requestedAt` filter then skips
them when the cursor arrives. onConflictDoNothing guards against clobbering
a concurrently-written entry; the active-dispatch check avoids stamping
spurious cancels on idle rows.
* fix(table): seed dispatch overlay on Run; surface batch-enqueue failures as error
- useRunColumn.onSuccess invalidates the activeDispatches query so the
resolveCellExec queued overlay populates immediately for ahead-of-cursor
rows (scrolled-in / refetched), instead of waiting for the first dispatch
SSE. Targeted at activeDispatches only — the rows cache stays owned by
useTableEventStream.
- On batchEnqueueAndWait failure, dispatcherStep now flips the orphan
pre-stamps to a terminal `error` state and emits a cell SSE event, rather
than deleting them. The cursor still advances past the window, but the
dropped cells are now visible (Error pill) instead of silently empty, stay
out of the in-flight set, and re-run on the next manual run.
* fix(table): seed dispatch overlay on Run; surface batch-enqueue failures as error
- useRunColumn.onSuccess invalidates activeDispatches so the resolveCellExec
queued overlay populates immediately for ahead-of-cursor rows instead of
waiting for the first dispatch SSE. Rows cache stays owned by SSE.
- On batchEnqueueAndWait failure, dispatcherStep flips orphan pre-stamps to a
terminal error state (+ cell SSE) instead of deleting them, so the dropped
window is visible (Error pill) rather than silently empty and re-runs on the
next manual run.
---------
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|