* fix(ashby): add secretToken to webhook creation and fix trigger UX
* fix(toast): restore useMemo for context value to prevent unnecessary re-renders
* fix(notifications): track exit animation timeout so pauseAll can cancel it
* fix(notifications): use isPausedRef to guard exit timeout instead of synthetic timer keys
* fix(notifications): clear pending timers when notification stack empties
* improvement(mothership): message queueing for home chat
* fix(mothership): address PR review — move FileAttachmentForApi to types, defer onEditValueConsumed to effect, await sendMessage in sendNow
* fix(mothership): replace updater side-effect with useEffect ref sync, move sendMessageRef to useLayoutEffect
* fix(mothership): clear message queue on chat switch while sending
* fix(mothership): remove stale isSending from handleKeyDown deps
* fix(mothership): guard sendNow against double-click duplicate sends
* fix(mothership): simplify queue callbacks — drop redundant deps and guard ref
- Remove `setMessageQueue` from useCallback deps (stable setter, never changes)
- Replace `sendNowProcessingRef` double-click guard with eager `messageQueueRef` update
- Simplify `editQueuedMessage` with same eager-ref pattern for consistency
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix(mothership): clear edit value on nav, stop queue drain on send failure
- Reset editingInputValue when chatId changes so stale edit text
doesn't leak into the next chat
- Pass error flag to finalize so queue is cleared (not drained) when
sendMessage fails — prevents cascading failures on auth expiry or
rate limiting from silently consuming every queued message
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix(mothership): eagerly update messageQueueRef in removeFromQueue
Match the pattern used by sendNow and editQueuedMessage — update the
ref synchronously so finalize's microtask cannot read a stale queue
and drain a message the user just removed.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix(mothership): mark onSendNow as explicit fire-and-forget
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix(connectors): align connector scopes with oauth config and fix kb modal UX
* fix(connectors): restore onCheckedChange for keyboard accessibility
* feat(connectors): add dynamic selectors to knowledge base connector config
Replace manual ID text inputs with dynamic selector dropdowns that fetch
options from the existing selector registry. Users can toggle between
selector and manual input via canonical pairs (basic/advanced mode).
Adds selector support to 12 connectors: Airtable (cascading base→table),
Slack, Gmail, Google Calendar, Linear (cascading team→project), Jira,
Confluence, MS Teams (cascading team→channel), Notion, Asana, Webflow,
and Outlook. Dependency clearing propagates across canonical siblings to
prevent stale cross-mode data on submit.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* updated animated blocks UI
* fix(connectors): clear canonical siblings of dependents and resolve active mode values
Fixes three issues from PR review:
- Dependency clearing now includes canonical siblings of dependent fields
(e.g., changing base clears both tableSelector AND tableIdOrName)
- Selector context and depsResolved now resolve dependency values through
the active canonical mode, not just the raw depFieldId
- Tooltip text changed from "Switch to manual ID" to "Switch to manual input"
to correctly describe dropdown fallbacks (e.g., Outlook folder)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* chore: linter class ordering fixes and docs link update
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix(connectors): reset apiKeyFocused on connector re-selection
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* Fix lint
* improvement(sidebar): loading
* fix(sidebar): use client-generated UUIDs for stable optimistic updates (#3439)
* fix(sidebar): use client-generated UUIDs for stable optimistic updates
* fix(folders): use zod schema validation for folder create API
Replace inline UUID regex with zod schema validation for consistency
with other API routes. Update test expectations accordingly.
* fix(sidebar): add client UUID to single workflow duplicate hook
The useDuplicateWorkflow hook was missing newId: crypto.randomUUID(),
causing the same temp-ID-swap issue for single workflow duplication
from the context menu.
* fix(folders): avoid unnecessary Set re-creation in replaceOptimisticEntry
Only create new expandedFolders/selectedFolders Sets when tempId
differs from data.id. In the common happy path (client-generated UUIDs),
this avoids unnecessary Zustand state reference changes and re-renders.
* Mothership block logs
* Fix mothership block logs
* improvement(knowledge): make connector-synced document chunks readonly (#3440)
* improvement(knowledge): make connector-synced document chunks readonly
* fix(knowledge): enforce connector chunk readonly on server side
* fix(knowledge): disable toggle and delete actions for connector-synced chunks
* Job exeuction logs
* Job logs
* fix(connectors): remove unverifiable requiredScopes for Linear connector
* fix(connectors): remove legacy requiredScopes from Jira and Confluence connectors
Jira and Confluence OAuth tokens don't return legacy scope names like
read:jira-work or read:confluence-content.all, causing the 'Update access'
banner to always appear. Set requiredScopes to empty array like Linear.
* feat(tasks): add rename to task context menu (#3442)
* Revert "fix(connectors): remove legacy requiredScopes from Jira and Confluence connectors"
This reverts commit a0be3ff414.
* fix(connectors): restore Linear connector requiredScopes
Linear OAuth does return scopes in the token response. The previous
fix of emptying requiredScopes was based on an incorrect assumption.
Restoring requiredScopes: ['read'] as it should work correctly.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix(knowledge): pass workspaceId to useOAuthCredentials in connector card
The ConnectorCard was calling useOAuthCredentials(providerId) without
a workspaceId, causing the credentials API to return an empty array.
This meant the credential lookup always failed, getMissingRequiredScopes
received undefined, and the "Update access" banner always appeared.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* Fix oauth link callback from mothership task
* feat(connectors): add Fireflies connector and API key auth support (#3448)
* feat(connectors): add Fireflies connector and API key auth support
Extend the connector system to support both OAuth and API key authentication
via a discriminated union (`ConnectorAuthConfig`). Add Fireflies as the first
API key connector, syncing meeting transcripts via the Fireflies GraphQL API.
Schema changes:
- Make `credentialId` nullable (null for API key connectors)
- Add `encryptedApiKey` column (AES-256-GCM encrypted, null for OAuth)
This eliminates the `'_apikey_'` sentinel and inline `sourceConfig._encryptedApiKey`
patterns, giving each auth mode its own clean column.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix(fireflies): allow 0 for maxTranscripts (means unlimited)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* Add context
* fix(fireflies): correct types from live API validation (#3450)
* fix(fireflies): correct types from live API validation
- speakers.id is number, not string (API returns 0, 1, 2...)
- summary.action_items is a single string, not string[]
- Update formatTranscriptContent to handle action_items as string
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix(fireflies): correct tool types from live API validation
- FirefliesSpeaker.id: string -> number
- FirefliesSentence.speaker_id: string -> number
- FirefliesSpeakerAnalytics.speaker_id: string -> number
- FirefliesSummary.action_items: string[] -> string
- FirefliesSummary.outline: string[] -> string
- FirefliesSummary.shorthand_bullet: string[] -> string
- FirefliesSummary.bullet_gist: string[] -> string
- FirefliesSummary.topics_discussed: string[] -> string
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* feat(knowledge): add connector tools and expand document metadata (#3452)
* feat(knowledge): add connector tools and expand document metadata
* fix(knowledge): address PR review feedback on new tools
* fix(knowledge): remove unused params from get_document transform
* refactor, improvement
* fix: correct knowledge block canonical pair pattern and subblock migration
- Rename manualDocumentId to documentId (advanced subblock ID should match
canonicalParamId, consistent with airtable/gmail patterns)
- Fix documentSelector.dependsOn to reference knowledgeBaseSelector (basic
depends on basic, not advanced)
- Remove unnecessary documentId migration (ID unchanged from main)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* lint
* fix: resolve post-merge test and lint failures
- airtable: sync tableSelector condition with tableId (add getSchema)
- backfillCanonicalModes test: add documentId mode to prevent false backfill
- schedule PUT test: use invalid action string now that disable is valid
- schedule execute tests: add ne mock, sourceType field, use
mockReturnValueOnce for two db.update calls
- knowledge tools: fix biome formatting (single-line arrow functions)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* Fixes
* Fixes
* Clean vfs
* Fix
* Fix lint
* fix(connectors): add rate limiting, concurrency controls, and bug fixes (#3457)
* fix(connectors): add rate limiting, concurrency controls, and bug fixes across knowledge connectors
- Add Retry-After header support to fetchWithRetry for all 18 connectors
- Batch concurrent API calls (concurrency 5) in Dropbox, Google Docs, Google Drive, OneDrive, SharePoint
- Batch concurrent API calls (concurrency 3) in Notion to match 3 req/s limit
- Cache GitHub tree in syncContext to avoid re-fetching on every pagination page
- Batch GitHub blob fetches with concurrency 5
- Fix GitHub base64 decoding: atob() → Buffer.from() for UTF-8 safety
- Fix HubSpot OAuth scope: 'tickets' → 'crm.objects.tickets.read' (v3 API)
- Fix HubSpot syncContext key: totalFetched → totalDocsFetched for consistency
- Add jitter to nextSyncAt (10% of interval, capped at 5min) to prevent thundering herd
- Fix Date consistency in connector DELETE route
* fix(connectors): address PR review feedback on retry and SharePoint batching
- Remove 120s cap on Retry-After — pass all values through to retry loop
- Add maxDelayMs guard: if Retry-After exceeds maxDelayMs, throw immediately
instead of hammering with shorter intervals (addresses validate timeout concern)
- Add early exit in SharePoint batch loop when maxFiles limit is reached
to avoid unnecessary API calls
* fix(connectors): cap Retry-After at maxDelayMs instead of aborting
Match Google Cloud SDK behavior: when Retry-After exceeds maxDelayMs,
cap the wait to maxDelayMs and log a warning, rather than throwing
immediately. This ensures retries are bounded in duration while still
respecting server guidance within the configured limit.
* fix(connectors): add early-exit guard to Dropbox, Google Docs, OneDrive batch loops
Match the SharePoint fix — skip remaining batches once maxFiles limit
is reached to avoid unnecessary API calls.
* improvement(turbo): align turborepo config with best practices (#3458)
* improvement(turbo): align turborepo config with best practices
* fix(turbo): address PR review feedback
* fix(turbo): add lint:check task for read-only lint+format CI checks
lint:check previously delegated to format:check which only checked
formatting. Now it runs biome check (no --write) which enforces both
lint rules and formatting without mutating files.
* upgrade turbo
* improvement(perf): apply react and js performance optimizations across codebase (#3459)
* improvement(perf): apply react and js performance optimizations across codebase
- Parallelize independent DB queries with Promise.all in API routes
- Defer PostHog and OneDollarStats via dynamic import() to reduce bundle size
- Use functional setState in countdown timers to prevent stale closures
- Replace O(n*m) .filter().find() with Set-based O(n) lookups in undo-redo
- Use .toSorted() instead of .sort() for immutable state operations
- Use lazy initializers for useState(new Set()) across 20 components
- Remove useMemo wrapping trivially cheap expressions (typeof, ternary, template strings)
- Add passive: true to scroll event listener
* fix(perf): address PR review feedback
- Extract IIFE Set patterns to named consts for readability in use-undo-redo
- Hoist Set construction above loops in BATCH_UPDATE_PARENT cases
- Add .catch() error handler to PostHog dynamic import
- Convert session-provider posthog import to dynamic import() to complete bundle split
* fix(analytics): add .catch() to onedollarstats dynamic import
* improvement(resource): tables, files
* improvement(resources): all outer page structure complete
* refactor(queries): comprehensive TanStack Query best practices audit (#3460)
* refactor: comprehensive TanStack Query best practices audit and migration
- Add AbortSignal forwarding to all 41 queryFn implementations for proper request cancellation
- Migrate manual fetch patterns to useMutation hooks (useResetPassword, useRedeemReferralCode, usePurchaseCredits, useImportWorkflow, useOpenBillingPortal, useAllowedMcpDomains)
- Migrate standalone hooks to TanStack Query (use-next-available-slot, use-mcp-server-test, use-webhook-management, use-referral-attribution)
- Fix query key factories: add missing `all` keys, replace inline keys with factory methods
- Fix optimistic mutations: use onSettled instead of onSuccess for cache reconciliation
- Replace overly broad cache invalidations with targeted key invalidation
- Remove keepPreviousData from static-key queries where it provides no benefit
- Add staleTime to queries missing explicit cache duration
- Fix `any` type in UpdateSettingParams with proper GeneralSettings typing
- Remove dead code: loadingWebhooks/checkedWebhooks from subblock store, unused helper functions
- Update settings components (general, debug, referral-code, credit-balance, subscription, mcp) to use mutation state instead of manual useState for loading/error/success
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: remove unstable mutation object from useCallback deps
openBillingPortal mutation object is not referentially stable,
but .mutate() is stable in TanStack Query v5. Remove from deps
to prevent unnecessary handleBadgeClick recreations.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: add missing byWorkflows invalidation to useUpdateTemplate
The onSettled handler was missing the byWorkflows() invalidation
that was dropped during the onSuccess→onSettled migration. Without
this, the deploy modal (useTemplateByWorkflow) would show stale data
after a template update.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* docs: add TanStack Query best practices to CLAUDE.md and cursor rules
Add comprehensive React Query best practices covering:
- Hierarchical query key factories with intermediate plural keys
- AbortSignal forwarding in all queryFn implementations
- Targeted cache invalidation over broad .all invalidation
- onSettled for optimistic mutation cache reconciliation
- keepPreviousData only on variable-key queries
- No manual fetch in components rule
- Stable mutation references in useCallback deps
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: address PR review feedback
- Fix syncedRef regression in use-webhook-management: only set
syncedRef.current=true when webhook is found, so re-sync works
after webhook creation (e.g., post-deploy)
- Remove redundant detail(id) invalidation from useUpdateTemplate
onSettled since onSuccess already populates cache via setQueryData
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: address second round of PR review feedback
- Reset syncedRef when blockId changes in use-webhook-management so
component reuse with a different block syncs the new webhook
- Add response.ok check in postAttribution so non-2xx responses
throw and trigger TanStack Query retry logic
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: use lists() prefix invalidation in useCreateWorkspaceCredential
Use workspaceCredentialKeys.lists() instead of .list(workspaceId) so
filtered list queries are also invalidated on credential creation,
matching the pattern used by update and delete mutations.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: address third round of PR review feedback
- Add nullish coalescing fallback for bonusAmount in referral-code
to prevent rendering "undefined" when server omits the field
- Reset syncedRef when queryEnabled becomes false so webhook data
re-syncs when the query is re-enabled without component remount
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: address fourth round of PR review feedback
- Add AbortSignal to testMcpServerConnection for consistency
- Wrap handleTestConnection in try/catch for mutateAsync error handling
- Replace broad subscriptionKeys.all with targeted users()/usage() invalidation
- Add intermediate users() key to subscription key factory for prefix matching
- Add comment documenting syncedRef null-webhook behavior
- Fix api-keys.ts silent error swallowing on non-ok responses
- Move deployments.ts cache invalidation from onSuccess to onSettled
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: achieve full TanStack Query best practices compliance
- Add intermediate plural keys to api-keys, deployments, and schedules
key factories for prefix-based invalidation support
- Change copilot-keys from refetchQueries to invalidateQueries
- Add signal parameter to organization.ts fetch functions (better-auth
client does not support AbortSignal, documented accordingly)
- Move useCreateMcpServer invalidation from onSuccess to onSettled
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* ran lint
* Fix tables row count
* Update mothership to match copilot in logs
* improvement(resource): layout
* fix(knowledge): compute KB tokenCount from documents instead of stale column (#3463)
The knowledge_base.token_count column was initialized to 0 and never
updated. Replace with COALESCE(SUM(document.token_count), 0) in all
read queries, which already JOIN on documents with GROUP BY.
* improvement(resources): layout and items
* feat(knowledge): add v1 knowledge base API, Obsidian/Evernote connectors, and docs (#3465)
* feat(knowledge): add v1 knowledge base API, Obsidian/Evernote connectors, and docs
- Add v1 REST API for knowledge bases (CRUD, document management, vector search)
- Add Obsidian and Evernote knowledge base connectors
- Add file type validation to v1 file and document upload endpoints
- Update OpenAPI spec with knowledge base endpoints and schemas
- Add connectors documentation page
- Apply query hook formatting improvements
* fix(knowledge): address PR review feedback
- Remove validateFileType from v1/files route (general file upload, not document-only)
- Reject tag filters when searching multiple KBs (tag defs are KB-specific)
- Cache tag definitions to avoid duplicate getDocumentTagDefinitions call
- Fix Obsidian connector silent empty results when syncContext is undefined
* improvement(connectors): add syncContext to getDocument, clean up caching
- Update docs to say 20+ connectors
- Add syncContext param to ConnectorConfig.getDocument interface
- Use syncContext in Evernote getDocument to cache tag/notebook maps
- Replace index-based cache check with Map keyed by KB ID in search route
* fix(knowledge): address second round of PR review feedback
- Fix Zod .default('text') overriding tag definition's actual fieldType
- Fix encodeURIComponent breaking multi-level folder paths in Obsidian
- Use 413 instead of 400 for file-too-large in document upload
- Add knowledge-bases to API reference docs navigation
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix(knowledge): prevent cross-workspace KB access in search
Filter accessible KBs by matching workspaceId from the request,
preventing users from querying KBs in other workspaces they have
access to but didn't specify.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix(knowledge): audit resourceId, SSRF protection, recursion depth limit
- Fix recordAudit using knowledgeBaseId instead of newDocument.id
- Add SSRF validation to Obsidian connector (reject private/loopback URLs)
- Add max recursion depth (20) to listVaultFiles
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix(obsidian): remove SSRF check that blocks localhost usage
The Obsidian connector is designed to connect to the Local REST API
plugin running on localhost (127.0.0.1:27124). The SSRF check was
incorrectly blocking this primary use case.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* improvement(resources): segmented API
* fix(execution): ensure background tasks await post-execution DB status updates (#3466)
The fire-and-forget IIFE in execution-core.ts for post-execution logging could be abandoned when trigger.dev tasks exit, leaving executions permanently stuck in "running" status. Store the promise on LoggingSession so background tasks can optionally await it before returning.
* improvement(resource): sorting and icons
* fix(resource): sorting
* improvement(settings): fix mcp modal, add option to edit JSON and add Sim as an MCP client (#3467)
* improvement(settings): fix mcp modal, add option to edit JSON and add Sim as an MCP client
* added docs link in sidebar
* ack comments
* ack comments
* fixed error msg
* feat(mothership): billing (#3464)
* Billing update
* more billing improvements
* credits UI
* credit purchase safety
* progress
* ui improvements
* fix cancel sub
* fix types
* fix daily refresh for teams
* make max features differentiated
* address bugbot comments
* address greptile comments
* revert isHosted
* address more comments
* fix org refresh bar
* fix ui rounding
* fix minor rounding
* fix upgrade issue for legacy plans
* fix formatPlanName
* fix email dispay names
* fix legacy team reference bugs
* referral bonus in credits
* fix org upgrade bug
* improve logs
* respect toggle for paid users
* fix landing page pro features and usage limit checks
* fixed query and usage
* add unit test
* address more comments
* enterprise guard
* fix limits bug
* pass period start/end for overage
* fix(sidebar): restore drag-and-drop for workflows and folders (#3470)
* fix(sidebar): restore drag-and-drop for workflows and folders
Made-with: Cursor
* update docs, unrelated
* improvement(tables): consolidation
* feat(schedules): add schedule creator modal for standalone jobs
Add modal to create standalone scheduled jobs from the Schedules page.
Includes POST API endpoint, useCreateSchedule mutation hook, and full
modal with schedule type selection, timezone, lifecycle, and live preview.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* feat(schedules): add edit support with context menu for standalone jobs
* style(schedules): apply linter formatting
* improvement: tables, favicon
* feat(files): inline file viewer with text editing (#3475)
* feat(files): add inline file viewer with text editing and create file modal
Add file preview/edit functionality to the workspace files page. Text files
(md, json, txt, yaml, etc.) open in an editable textarea with Cmd/Ctrl+S save.
PDFs render in an iframe. New file button creates empty .md files via a modal.
Uses ResourceHeader breadcrumbs and ResourceOptionsBar for save/download/delete.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* improvement(files): add UX polish, PR review fixes, and context menu
- Add unsaved changes guard modal (matching credentials manager pattern)
- Add delete confirmation modal for both viewer and context menu
- Add save status feedback (Save → Saving... → Saved)
- Add right-click context menu with Open, Download, Delete actions
- Add 50MB file size limit on content update API
- Add storage quota check before content updates
- Add response.ok guard on download to prevent corrupt files
- Add skeleton loading for pending file selection (prevents flicker)
- Fix updateContent in handleSave dependency array
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix(files): propagate save errors and remove redundant sizeDiff
- Remove try/catch in TextEditor.handleSave so errors propagate to
parent, which correctly shows save failure status
- Remove redundant inner sizeDiff declaration that shadowed outer scope
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix(files): remove unused textareaRef
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix(files): move Cmd+S to parent, add save error feedback, hide save for non-text files
- Move Cmd+S keyboard handler from TextEditor to Files so it goes
through the parent handleSave with proper status management
- Add 'error' save status with red "Save failed" label that auto-resets
- Only show Save button for text-editable file types (md, txt, json, etc.)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* improvement(files): add save tooltip, deduplicate text-editable extensions
- Add Tooltip on Save button showing Cmd+S / Ctrl+S shortcut
- Export TEXT_EDITABLE_EXTENSIONS from file-viewer and reuse in files.tsx
instead of duplicating the list inline
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* refactor: extract isMacPlatform to shared utility
Move isMacPlatform() from global-commands-provider.tsx to
lib/core/utils/platform.ts so it can be reused by files.tsx tooltip
without duplication.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* refactor(files): deduplicate delete modal, use shared formatFileSize
- Extract DeleteConfirmModal component to eliminate duplicate modal
markup between viewer and list modes
- Replace local formatFileSize with shared utility from file-utils.ts
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix(files): fix a11y label lint error and remove mutation object from useCallback deps
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix(files): add isDirty guard on handleSave, return proper HTTP status codes
Prevents "Saving → Saved" flash when pressing Cmd+S with no changes.
Returns 404 for file-not-found and 402 for quota-exceeded instead of 500.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix(files): reset isDirty/saveStatus on delete and discard, remove deprecated navigator.platform
- Clear isDirty and saveStatus when deleting the currently-viewed file to
prevent spurious beforeunload prompts
- Reset saveStatus on discard to prevent stale "Save failed" when opening
another file
- Remove deprecated navigator.platform, userAgent fallback covers all cases
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix(files): prevent concurrent saves on rapid Cmd+S, add YAML MIME types
- Add saveStatus === 'saving' guard to handleSave to prevent duplicate
concurrent PUT requests from rapid keyboard shortcuts
- Add yaml/yml MIME type mappings to getMimeTypeFromExtension
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* refactor(files): reuse shared extension constants, parallelize cancelQueries
- Replace hand-rolled SUPPORTED_EXTENSIONS with composition from existing
SUPPORTED_DOCUMENT/AUDIO/VIDEO_EXTENSIONS in validation.ts
- Parallelize sequential cancelQueries calls in delete mutation onMutate
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix(files): guard handleCreate against duplicate calls while pending
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix(files): show upload progress on the Upload button, not New file
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix(files): use ref-based guard for create pending state to avoid stale closure
The uploadFile.isPending check was stale because the mutation object
is excluded from useCallback deps (per codebase convention). Using a
ref ensures the guard works correctly across rapid Enter key presses.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* cleanup(files): use shared icon import, remove no-op props, wrap handler in useCallback
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* improvement: tables, dropdown
* improvement(docs): align sidebar method badges and polish API reference styling (#3484)
* improvement(docs): align sidebar method badges and polish API reference styling
* fix(docs): revert className prop on DocsPage for CI compatibility
* fix(docs): restore oneOf schema for delete rows and use rem units in CSS
* fix(docs): replace :has() selectors with direct className for reliable prod layout
The API docs layout was intermittently narrow in production because CSS
:has(.api-page-header) selectors are unreliable in Tailwind v4 production
builds. Apply className="openapi-page" directly to DocsPage and replace
all 64 :has() selectors with .openapi-page class targeting.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix(docs): bypass TypeScript check for className prop on DocsPage
Use spread with type assertion to pass className to DocsPage, working
around a CI type resolution issue where the prop exists at runtime but
is not recognized by TypeScript in the Vercel build environment.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix(docs): use inline style tag for grid layout, revert CSS to :has() selectors
The className prop on DocsPage doesn't exist in the fumadocs-ui version
resolved on Vercel, so .openapi-page was never applied and all 64 CSS
rules broke. Revert to :has(.api-page-header) selectors for styling and
use an inline <style> tag for the critical grid-column layout override,
which is SSR'd and doesn't depend on any CSS selector matching.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix(docs): add pill styling to footer navigation method badges
The footer nav badges (POST, GET, etc.) had color from data-method rules
but lacked the structural pill styling (padding, border-radius, font-size).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* fix(docs): use named grid lines instead of numeric column indices (#3487)
Root cause: the fumadocs grid template has 3 columns in production but
5 columns in local dev. Our CSS used `grid-column: 3 / span 2` which
targeted the wrong column in the 3-column grid, placing content in
the near-zero-width TOC column instead of the main content column.
Fix: use `grid-column: main-start / toc-end` which uses CSS named grid
lines from grid-template-areas, working regardless of column count.
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* improvement(resource): layout
* improvement: icon, resource header options
* improvement: icons
* fix(files): icon
* feat(tables): column operations, row ordering, V1 API (#3488)
* feat(tables): add column operations, row ordering, V1 columns API, and OpenAPI spec
Adds column rename/delete/type change/constraint updates to the tables module,
row ordering via position column, UI metadata schema, V1 public API for column
operations with rate limiting and audit logging, and OpenAPI documentation.
Key changes:
- Service-layer column operations with validation (name pattern, type compatibility, unique/required constraints)
- Position column on user_table_rows with composite index for efficient ordering
- V1 /api/v1/tables/{tableId}/columns endpoint (POST/PATCH/DELETE) with rate limiting and audit
- Shared Zod schemas extracted to table/utils.ts using COLUMN_TYPES constant
- Targeted React Query invalidation (row vs schema mutations) with consistent onSettled usage
- OpenAPI 3.1.0 spec for columns endpoint with code samples
- Position field added to all row response mappings for consistency
- Sort fallback to position ordering when buildSortClause returns null
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix(tables): use specific error prefixes instead of broad "Cannot" match
Prevents internal TypeErrors (e.g. "Cannot read properties of undefined")
from leaking as 400 responses. Now matches only domain-specific errors:
"Cannot delete the last column" and "Cannot set column".
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix(tables): reject Infinity and NaN in number type compatibility check
Number.isFinite rejects Infinity, -Infinity, and NaN, preventing
non-finite values from passing column type validation.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix(tables): invalidate table list on row create/delete for stale rowCount
Row create and delete mutations now invalidate the table list cache since
it includes a computed rowCount. Row updates (which don't change count)
continue to only invalidate row queries.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix(tables): add column name length check, deduplicate name gen, reset pagination on clear
- Add MAX_COLUMN_NAME_LENGTH validation to addTableColumn (was missing,
renameColumn already had it)
- Extract generateColumnName helper to eliminate triplicated logic across
handleAddColumn, handleInsertColumnLeft, handleInsertColumnRight
- Reset pagination to page 0 when clearing sort/filter to prevent showing
empty pages after narrowing filters are removed
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: hoist tableId above try block in V1 columns route, add detail invalidation to invalidateRowCount
- V1 columns route: `tableId` was declared inside `try` but referenced in
`catch` logger.error, causing undefined in error logs. Hoisted `await params`
above try in all three handlers (POST, PATCH, DELETE).
- invalidateRowCount: added `tableKeys.detail(tableId)` invalidation since the
single-table GET response includes `rowCount`, which becomes stale after
row create/delete without this.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: add position to all row mutation responses, remove dead filter code
- Add `position` field to POST (single + batch) and PATCH row responses
across both internal and V1 routes, matching GET responses and OpenAPI spec.
- Remove unused `filterConfig`, `handleFilterToggle`, `handleFilterClear`,
and `activeFilters` — dead code left over from merge conflict resolution.
`handleFilterApply` (the one actually wired to JSX) is preserved.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: invalidateTableSchema now also invalidates table list cache
Column add/rename/delete/update mutations now invalidate tableKeys.list()
since the list endpoint returns schema.columns for each table. Without this,
the sidebar table list would show stale column schemas until staleTime expires.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: replace window.prompt/confirm with emcn Modal dialogs
Replace non-standard browser dialogs with proper emcn Modal components
to match the existing codebase pattern (e.g. delete table confirmation).
- Column rename: Modal with Input field + Enter key support
- Column delete: Modal with destructive confirmation
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* update schedule creation ui and run lint
* improvement: logs
* improvement(tables): multi-select and efficiencies
* Table tools
* improvement(folder-selection): folder deselection + selection order should match visual
* fix(selections): more nested folder inaccuracies
* Tool updates
* Store tool call results
* fix(landing): wire agent input to mothership
* feat(mothership): resource viewer
* fix tests
* fix(streaming): smoother streaming with throttled rendering, ResizeObserver scroll, and batched updates (#3471)
* fix(streaming): smoother streaming with throttled rendering, ResizeObserver scroll, and batched updates
- Add useThrottledValue hook (100ms trailing-edge throttle) to gate DOM re-renders during streaming across all chat surfaces
- Replace 100ms setInterval scroll polling with ResizeObserver-based auto-scroll, programmatic scroll timestamp tracking, and nested [data-scrollable] region handling
- Extract processContentBuffer from inline content handler for cleaner code organization in copilot SSE handlers
- Add RAF-based update batching (50ms max interval) to floating chat and home chat streaming paths
- Add useProgressiveList hook for progressive rendering of long conversation histories via requestAnimationFrame
Made-with: Cursor
* ack PR comments
* fix search modal
* more comments
* ack comments
* count
* ack comments
* ack comment
* improvement(mothership): worklfow resource
* Fix tool call persistence in chat
* Tool results
* Fix error status
* File uploads to mothership
* feat(templates): landing page templates workflow states
* improvement(mothership): chat stability
* improvement(mothership): chat history and stability
* improvement(tables): click-to-select navigation, inline rename, column resize (#3496)
* improvement(tables): click-to-select navigation, inline rename, column resize
* fix(tables): address PR review comments
- Add doneRef guard to useInlineRename preventing Enter+blur double-fire
- Fix PATCH error handler: return 500 for non-validation errors, fix unreachable logger.error
- Stop click propagation on breadcrumb rename input
* fix(tables): add rows-affected check in renameTable service
Prevents silent no-op when tableId doesn't match any record.
* fix(tables): useMemo deps + placeholder memo initialCharacter check
- Use primitive editingId/editValue in useMemo deps instead of whole
useInlineRename object (which creates a new ref every render)
- Add initialCharacter comparison to placeholderPropsAreEqual, matching
the existing pattern in dataRowPropsAreEqual
* fix(tables): address round 2 review comments
- Mirror name validation (regex + max length) in PatchTableSchema so
validateTableName failures return 400 instead of 500
- Add .returning() + rows-affected check to renameWorkspaceFile,
matching the renameTable pattern
- Check response.ok before parsing JSON in useRenameWorkspaceFile,
matching the useRenameTable pattern
* refactor(tables): reuse InlineRenameInput in BreadcrumbSegment
Replace duplicated inline input markup with the shared component.
Eliminates redundant useRef, useEffect, and input boilerplate.
* fix(tables): set doneRef in cancelRename to prevent blur-triggered save
Escape → cancelRename → input unmounts → blur → submitRename would
save instead of canceling. Now cancelRename sets doneRef like
submitRename does, blocking the subsequent blur handler.
* fix(tables): pointercancel cleanup + typed FileConflictError
- Add pointercancel handler to column resize to prevent listener leaks
when system interrupts the pointer (touch-action override, etc.)
- Replace stringly-typed error.message.includes('already exists') with
FileConflictError class for refactor-safe 409 status detection
* fix(tables): stable useCallback dep + rename shadowed variable
- Use listRename.startRename (stable ref) instead of whole listRename
object in handleContextMenuRename deps
- Rename inner 'target' to 'origin' in arrow-key handler to avoid
shadowing the outer HTMLElement 'target'
* fix(tables): move class below imports, stable submitRename, clear editingCell
- Move FileConflictError below import statements (import-first convention)
- Make submitRename a stable useCallback([]) by reading editingId and
editValue through refs (matches existing onSaveRef pattern)
- Add setEditingCell(null) to handleEmptyRowClick for symmetry with
handleCellClick
* feat(tables): persist column widths in table metadata
Column widths now survive navigation and page reloads. On resize-end,
widths are debounced (500ms) and saved to the table's metadata field
via a new PUT /api/table/[tableId]/metadata endpoint. On load, widths
are seeded from the server once via React Query.
* fix type checking for file viewer
* fix(tables): address review feedback — 4 fixes
1. headerRename.onSave now uses the fileId parameter directly instead
of the selectedFile closure, preventing rename-wrong-file race
2. updateMetadataMutation uses ref pattern matching mutateRef/createRef
3. Type-to-enter filters non-numeric chars for number columns, non-date
chars for date columns
4. renameValue only passed to actively-renaming ColumnHeaderMenu,
preserving React.memo for other columns
* fix(tables): position-based gap rows, insert above/below, consistency fixes
- Fix gap row insert shifting: only shift rows when target position is
occupied, preventing unnecessary displacement of rows below
- Switch to position-based indexing throughout (positionMap, maxPosition)
instead of array-index for correct sparse position handling
- Add insert row above/below to context menu
- Use CellContent for pending values in PositionGapRows (matching PlaceholderRows)
- Add belowHeader selection overlay logic to PositionGapRows
- Remove unnecessary 500ms debounce on column width persistence
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix cells nav w keyboard
* added preview panel for html, markdown rendering, completed table
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* fix(tables): one small tables ting (#3497)
* feat(exa-hosted-key): Restore exa hosted key (#3499)
Co-authored-by: Theodore Li <theo@sim.ai>
* improvement(ui): consistent styling
* styling alignment
* improvements(tables): styling improvements
* improve resizer for file preview for html files
* updated document icon
* fix(credentials): exclude regular login methods from credential sync
* update docs
* upgrade turbo
* improvement: tables, chat
* Fix table column delete
* small table rename bug, files updates not persisting
* Table batch ops
* fix(credentials): block usage at execution layer without perms + fix invites
* feat(hosted-key-services) Add hosted key for multiple services (#3461)
* feat(hosted keys): Implement serper hosted key
* Handle required fields correctly for hosted keys
* Add rate limiting (3 tries, exponential backoff)
* Add custom pricing, switch to exa as first hosted key
* Add telemetry
* Consolidate byok type definitions
* Add warning comment if default calculation is used
* Record usage to user stats table
* Fix unit tests, use cost property
* Include more metadata in cost output
* Fix disabled tests
* Fix spacing
* Fix lint
* Move knowledge cost restructuring away from generic block handler
* Migrate knowledge unit tests
* Lint
* Fix broken tests
* Add user based hosted key throttling
* Refactor hosted key handling. Add optimistic handling of throttling for custom throttle rules.
* Remove research as hosted key. Recommend BYOK if throtttling occurs
* Make adding api keys adjustable via env vars
* Remove vestigial fields from research
* Make billing actor id required for throttling
* Switch to round robin for api key distribution
* Add helper method for adding hosted key cost
* Strip leading double underscores to avoid breaking change
* Lint fix
* Remove falsy check in favor for explicit null check
* Add more detailed metrics for different throttling types
* Fix _costDollars field
* Handle hosted agent tool calls
* Fail loudly if cost field isn't found
* Remove any type
* Fix type error
* Fix lint
* Fix usage log double logging data
* Fix test
* Add browseruse hosted key
* Add firecrawl and serper hosted keys
* feat(hosted key): Add exa hosted key (#3221)
* feat(hosted keys): Implement serper hosted key
* Handle required fields correctly for hosted keys
* Add rate limiting (3 tries, exponential backoff)
* Add custom pricing, switch to exa as first hosted key
* Add telemetry
* Consolidate byok type definitions
* Add warning comment if default calculation is used
* Record usage to user stats table
* Fix unit tests, use cost property
* Include more metadata in cost output
* Fix disabled tests
* Fix spacing
* Fix lint
* Move knowledge cost restructuring away from generic block handler
* Migrate knowledge unit tests
* Lint
* Fix broken tests
* Add user based hosted key throttling
* Refactor hosted key handling. Add optimistic handling of throttling for custom throttle rules.
* Remove research as hosted key. Recommend BYOK if throtttling occurs
* Make adding api keys adjustable via env vars
* Remove vestigial fields from research
* Make billing actor id required for throttling
* Switch to round robin for api key distribution
* Add helper method for adding hosted key cost
* Strip leading double underscores to avoid breaking change
* Lint fix
* Remove falsy check in favor for explicit null check
* Add more detailed metrics for different throttling types
* Fix _costDollars field
* Handle hosted agent tool calls
* Fail loudly if cost field isn't found
* Remove any type
* Fix type error
* Fix lint
* Fix usage log double logging data
* Fix test
---------
Co-authored-by: Theodore Li <teddy@zenobiapay.com>
* Fail fast on cost data not being found
* Add hosted key for google services
* Add hosting configuration and pricing logic for ElevenLabs TTS tools
* Add linkup hosted key
* Add jina hosted key
* Add hugging face hosted key
* Add perplexity hosting
* Add broader metrics for throttling
* Add skill for adding hosted key
* Lint, remove vestigial hosted keys not implemented
* Revert agent changes
* fail fast
* Fix build issue
* Fix build issues
* Fix type error
* Remove byok types that aren't implemented
* Address feedback
* Use default model when model id isn't provided
* Fix cost default issues
* Remove firecrawl error suppression
* Restore original behavior for hugging face
* Add mistral hosted key
* Remove hugging face hosted key
* Fix pricing mismatch is mistral and perplexity
* Add hosted keys for parallel and brand fetch
* Add brandfetch hosted key
* Update types
* Change byok name to parallel_ai
* Add telemetry on unknown models
---------
Co-authored-by: Theodore Li <theo@sim.ai>
* improvement(settings): SSR prefetch, code splitting, dedicated skeletons
* fix: bust browser cache for workspace file downloads
The downloadFile function was using a plain fetch() that honored the
aggressive cache headers, causing newly created files to download empty.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix(settings): use emcn Skeleton in extracted skeleton files
* fix(settings): extract shared response mappers to prevent server/client shape drift
Addresses PR review feedback — prefetch.ts duplicated response mapping logic from client hooks. Extracted mapGeneralSettingsResponse and mapUserProfileResponse as shared functions used by both client fetch and server prefetch.
* update byok page
* fix(settings): include theme sync in client-side prefetch queryFn
Hover-based prefetchGeneralSettings now calls syncThemeToNextThemes, matching the useGeneralSettings hook behavior so theme updates aren't missed when prefetch refreshes stale cache.
* fix(byok): use EMCN Input for search field instead of ui Input
Replace @/components/ui Input with the already-imported EmcnInput for design-system consistency.
* fix(byok): use ui Input for search bar to match other settings pages
* fix(settings): use emcn Input for file input in general settings
* improvement(settings): add search bar to skeleton loading states
Skeletons now include the search bar (and action button where applicable) so the layout matches the final component 1:1. Eliminates layout shift when the dynamic chunk loads — search bar area is already reserved by the skeleton.
* fix(settings): align skeleton layouts with actual component structures
- Fix list item gap from 12px to 8px across all skeletons (API keys, custom tools, credentials, MCP)
- Add OAuth icon placeholder to credential skeleton
- Fix credential button group gap from 8px to 4px
- Remove incorrect gap-[4px] from credential-sets text column
- Rebuild debug skeleton to match real layout (description + input/button row)
- Add scrollable wrapper to BYOK skeleton with more representative item count
* chore: lint fixes
* improvement(sidebar): match workspace switcher popover width to sidebar
Use Radix UI's built-in --radix-popover-trigger-width CSS variable
instead of hardcoded 160px so the popover matches the trigger width
and responds to sidebar resizing.
* revert hardcoded ff
* fix: copilot, improvement: tables, mothership
* feat: inline chunk editor and table batch ops with undo/redo (#3504)
* feat: inline chunk editor and table batch operations with undo/redo
Replace modal-based chunk editing/creation with inline editor following
the files tab pattern (state-based view toggle with ResourceHeader).
Add batch update API endpoint, undo/redo support, and Popover-based
context menus for tables.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: remove icons from table context menu PopoverItems
Icons were incorrectly carried over from the DropdownMenu migration.
PopoverItems in this codebase use text-only labels.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: restore DropdownMenu for table context menu
The table-level context menu was incorrectly migrated to Popover during
conflict resolution. Only the row-level context menu uses Popover; the
table context menu should remain DropdownMenu with icons, matching the
base branch.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: bound cross-page chunk navigation polling to max 50 retries
Prevent indefinite polling if page data never loads during
chunk navigation across page boundaries.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: navigate to last page after chunk creation for multi-page documents
After creating a chunk, navigate to the last page (where new chunks
append) before selecting it. This prevents the editor from showing
"Loading chunk..." when the new chunk is not on the current page.
The loading state breadcrumb remains as an escape hatch for edge cases.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: add duplicate rowId validation to BatchUpdateByIdsSchema
Adds a .refine() check to reject duplicate rowIds in batch update
requests, consistent with the positions uniqueness check on batch insert.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: address PR review comments
- Fix disableEdit logic: use || instead of && so connector doc chunks
cannot be edited from context menu (row click still opens viewer)
- Add uniqueness validation for rowIds in BatchUpdateByIdsSchema
- Fix inconsistent bg token: bg-background → bg-[var(--bg)] in Pagination
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: remove duplicate rowId uniqueness refine on BatchUpdateByIdsSchema
The refine was applied both on the inner updates array and the outer
object. Keep only the inner array refine which is cleaner.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: address additional PR review comments
- Fix stale rowId after create-row redo: patch undo stack with new row
ID using patchUndoRowId so subsequent undo targets the correct row
- Fix text color tokens in Pagination: use CSS variable references
(text-[var(--text-body)], text-[var(--text-secondary)]) instead of
Tailwind semantic tokens for consistency with the rest of the file
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: remove dead code and fix type errors in table context menu
Remove unused `onAddData` prop and `isEmptyCell` variable from row context
menu (introduced in PR but never wired to JSX). Fix type errors in
optimistic update spreads by removing unnecessary `as Record<string, unknown>`
casts that lost the RowData type.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: prevent false "Saved" status on invalid content and mark fire-and-forget goToPage calls
ChunkEditor.handleSave now throws on empty/oversized content instead of
silently returning, so the parent's catch block correctly sets saveStatus
to 'error'. Also added explicit `void` to unawaited goToPage(1) calls
in filter handlers to signal intentional fire-and-forget.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: handle stale totalPages in handleChunkCreated for new-page edge case
When creating a chunk that spills onto a new page, totalPages in the
closure is stale. Now polls displayChunksRef for the new chunk, and if
not found, checks totalPagesRef for an updated page count and navigates
to the new last page before continuing to poll.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* Streaming fix -- need to test more
* Make mothership block use long input instead of prompt input
* improvement(billing): isAnnual metadata + docs updates (#3506)
* improvement(billing): on demand toggling and infinite limits
* store stripe metadata to distinguish annual vs monthly
* udpate docs
* address bugbot
* Add piping
* feat(clean-hosted-keys) Remove eleven labs, browseruse. Tweak firecrawl and mistral key impl (#3503)
* Remove eleven labs, browseruse, and firecrawl
* Remove creditsUsed output
* Add back mistral hosting for mistral blocks
* Add back firecrawl since they queue up concurrent requests
* Fix price calculation, remove agent since its super long running and will clog up queue
* Define hosting per tool
* Remove redundant token finding
---------
Co-authored-by: Theodore Li <theo@sim.ai>
* Update vfs to handle hosted keys
* improvement(tables): fix cell editing flash, batch API docs, and UI polish (#3507)
* fix: show text cursor in chunk editor and ensure textarea fills container
Add cursor-text to the editor wrapper so the whole area shows a text
cursor. Click on empty space focuses the textarea. Changed textarea from
h-full/w-full to flex-1/min-h-0 so it properly fills the flex container.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* improvement(tables): fix cell editing flash, add batch API docs, and UI polish
Fix stale-data flash when saving inline cell edits by using TanStack Query's
isPending+variables pattern instead of manual cache writes. Also adds OpenAPI
docs for batch table endpoints, DatePicker support in row modal, duplicate row
in context menu, and styling improvements.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: remove dead resolveColumnFromEvent callback
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: unify paste undo into single create-rows action
Batch-created rows from paste now push one `create-rows` undo entry
instead of N individual `create-row` entries, so a single Ctrl+Z
reverses the entire paste operation.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: validate dates in inline editor and displayToStorage
InlineDateEditor now validates computed values via Date.parse before
saving, preventing invalid strings like "hello" from being sent to the
server. displayToStorage now rejects out-of-range month/day values
(e.g. 13/32) instead of producing invalid YYYY-MM-DD strings.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: accept ISO date format in inline date editor
Fall back to raw draft input when displayToStorage returns null, so
valid ISO dates like "2024-03-15" pasted or typed directly are
accepted instead of silently discarded. Date.parse still validates
the final value.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: add ISO date support to displayToStorage and fix picker Escape
displayToStorage now recognizes YYYY-MM-DD input directly, so ISO
dates typed or pasted work correctly for both saving and picker sync.
DatePicker Escape now refocuses the input instead of saving, so the
user can press Escape again to cancel or Enter to confirm — matching
the expected cancel behavior.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: remove dead paste boundary check
The totalR guard in handlePaste could never trigger since totalR
included pasteRows.length, making targetRow always < totalR.
Remove the unused variable and simplify the selection focus calc.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* update openapi
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* fix dysfunctional unique operation in tables
* feat(autosave): files and chunk editor autosave with debounce + refetch (#3508)
* feat(files): debounced autosave while editing
* address review comments
* more comments
* fix: unique constraint check crash and copilot table initial rows
- Fix TypeError in updateColumnConstraints: db.execute() returns a
plain array with postgres-js, not { rows: [...] }. The .rows.length
access always crashed, making "Set unique" completely broken.
- Add initialRowCount: 20 to copilot table creation so tables created
via chat have the same empty rows as tables created from the UI.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* Fix signaling
* revert: remove initialRowCount from copilot table creation
Copilot populates its own data after creating a table, so pre-creating
20 empty rows causes data to start at position 21 with empty rows above.
initialRowCount only makes sense for the manual UI creation flow.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* improvement: chat, workspace header
* chat metadata
* Fix schema mismatch (#3510)
Co-authored-by: Theodore Li <theo@sim.ai>
* Fixes
* fix: manual table creation starts with 1 row, 1 column
Manual tables now create with a single 'name' column and 1 row instead
of 2 columns and 20 rows. Copilot tables remain at 0 rows, 0 columns.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: horizontal scroll in embedded table by replacing overflow-hidden with overflow-clip
Cell content spans used Tailwind's `truncate` (overflow: hidden), creating
scroll containers that consumed trackpad wheel events on macOS without
propagating to the actual scroll ancestor. Replaced with overflow-clip
which clips identically but doesn't create a scroll container. Also moved
focus target from outer container to the scroll div for correctness.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* Fix tool call ordering
* Fix tests
* feat: add task multi-select, context menu, and subscription UI updates
Add shift-click range selection, cmd/ctrl-click toggle, and right-click
context menu for tasks in sidebar matching workflow/folder patterns.
Update subscription settings tab UI.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix(credentials): autosync behaviour cross workspace (#3511)
* fix(credentials): autosync behaviour cross workspace
* address comments
* fix(api-key-reminder) Add reminder on hosted keys that api key isnt needed (#3512)
* Add reminder on hosted keys that api key isnt needed
* Fix test case
---------
Co-authored-by: Theodore Li <theo@sim.ai>
* improvement: sidebar, chat
* Usage limit
* Plan prompt
* fix(sidebar): workspace header collapse
* fix(sidebar): task navigation
* Subagent tool call persistence
* Don't drop suabgent text
* improvement(ux): streaming
* improvement: thinking
* fix(random): optimized kb connector sync engine, rerenders in tables, files, editors, chat (#3513)
* optimized kb connector sync engine, rerenders in tables, files, editors, chat
* refactor(sidebar): rename onTaskClick to onMultiSelectClick for clarity
Made-with: Cursor
* ack comments, add docsFailed
* feat(email-footer) Add "sent with sim ai" for free users (#3515)
* Add "sent with sim ai" for free users
* Only add prompt injection on free tier
* Add try catch around billing info fetch
---------
Co-authored-by: Theodore Li <theo@sim.ai>
* improvement: modals
* ran migrations
* fix(mothership): fix hardcoded workflow color, tables drag line overflowing
* feat(mothership): file attachment indicators, persistence, and chat input improvements
- Show image thumbnails and file-icon cards above user messages in mothership chat
- Persist file attachment metadata (key, filename, media_type, size) in DB with user messages
- Restore attachments from history via /api/files/serve/ URLs so they survive refresh/navigation
- Unify all chat file inputs to use shared CHAT_ACCEPT_ATTRIBUTE constant
- Fix file thumbnail overflow: use flex-wrap instead of hidden horizontal scroll
- Compact attachment cards in floating workflow chat messages
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* improvement: search modal
* improvement(usage): free plan to 1000 credits (#3516)
* improvement(billing): free plan to five dollars
* fix comment
* remove per month terminology from marketing
* generate migration
* remove migration
* add migration back
* feat(workspace): add workspace color changing, consolidate update hooks, fix popover dismiss
- Add workspace color change via context menu, reusing workflow ColorGrid UI
- Consolidate useUpdateWorkspaceName + useUpdateWorkspaceColor into useUpdateWorkspace
- Fix popover hover submenu dismiss by using DismissableLayerBranch with pointerEvents
- Remove passthrough wrapper for export, reuse Workspace type for capturedWorkspaceRef
- Reorder log columns: workflow first, merge date+time into single column
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* Update oauth cred tool
* fix(diff-controls): fixed positioning for copilot diff controls
* fix(font): added back old font for emcn code editor
* improvement: panel, special tags
* improvement: chat
* improvement: loading and file dropping
* feat(templates): create home templates
* fix(uploads): resolve .md file upload rejection and deduplicate file type utilities
Browsers report empty or application/octet-stream MIME types for .md files,
causing copilot uploads to be rejected. Added resolveFileType() utility that
falls back to extension-based MIME resolution at both client and server
boundaries. Consolidated duplicate MIME mappings into module-level constants,
removed duplicate isImageFileType from copilot module, and replaced hardcoded
ALLOWED_EXTENSIONS with composition from shared validation constants. Also
switched file attachment previews to use shared getDocumentIcon utility.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix(home): prevent initial view from being scrollable
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* autofill fixes
* added back integrations page, reverted secrets page back to old UI
* Fix workspace dropdown getting cut off when sidebar is collapsed
* fix(mothership): lint (#3517)
* fix(mothership): lint
* fix typing
* fix tests
* fix stale query
* fix plan display name
* Feat/add mothership manual workflow runs (#3520)
* Add run and open workflow buttons in workflow preview
* Send log request message after manual workflow run
* Make edges in embedded workflow non-editable
* Change chat to pass in log as additional context
* Revert "Change chat to pass in log as additional context"
This reverts commit e957dffb2f.
* Revert "Send log request message after manual workflow run"
This reverts commit 0fb92751f0.
* Move run and workflow icons to tab bar
* Simplify boolean condition
---------
Co-authored-by: Theodore Li <theo@sim.ai>
* feat(resource-tab-scroll): Allow vertical scrolling to scroll resource tab
* fix(remove-speed-hosted-key) Remove maps speed limit hosted key, it's deprecated (#3521)
Co-authored-by: Theodore Li <theo@sim.ai>
* improvement: home, sidebar
* fix(download-file): render correct file download link for mothership (#3522)
* fix(download-file): render correct file download link for mothership
* Fix uunecessary call
* Use simple strip instead of db lookup and moving behavior
* Make regex strip more strict
---------
Co-authored-by: Theodore Li <theo@sim.ai>
* improvement: schedules, auto-scroll
* fix(settings): navigate back to origin page instead of always going home
Use sessionStorage to store the return URL when entering settings, and
use router.replace for tab switches so history doesn't accumulate.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix(schedules): release lastQueuedAt lock on all exit paths to prevent stuck schedules
Multiple error/early-return paths in executeScheduleJob and executeJobInline
were exiting without clearing lastQueuedAt, causing the dueFilter to permanently
skip those schedules — resulting in stale "X hours ago" display for nextRunAt.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* feat(mothership): inline rename for resource tabs + workspace_file rename tool
- Add double-click inline rename on file and table resource tabs
- Wire useInlineRename + useRenameWorkspaceFile/useRenameTable mutations
- Add rename operation to workspace_file copilot tool (schema, server, router)
- Add knowledge base resource support (type, extraction, rendering, actions)
- Accept optional className on InlineRenameInput for context-specific sizing
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* revert: remove inline rename UI from resource tabs
Keep the workspace_file rename tool for the mothership agent.
Only the UI-side inline rename (double-click tabs) is removed.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* feat(mothership): knowledge base resource extraction + Resource/ResourceTable refactor
- Extract KB resources from knowledge subagent respond format (knowledge_bases array)
- Add knowledge_base tool to RESOURCE_TOOL_NAMES and TOOL_UI_METADATA
- Extract ResourceTable as independently composable memoized component
- Move contentOverride/overlay to Resource shell level (not table primitive)
- Remove redundant disableHeaderSort and loadingRows props
- Rename internal sort state for clarity (sort → internalSort, sortOverride → externalSort)
- Export ResourceTable and ResourceTableProps from barrel
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix(logs) Run workflows client side in mothership to transmit logs (#3529)
* Run workflows client side in mothership to transmit logs
* Initialize set as constant, prevent duplicate execution
* Fix lint
---------
Co-authored-by: Theodore Li <theo@sim.ai>
* fix(import) fix missing file
* fix(resource): Hide resources that have been deleted (#3528)
* Hide resources that have been deleted
* Handle table, workflow not found
* Add animation to prevent flash when previous resource was deleted
* Fix animation playing on every switch
* Run workflows client side in mothership to transmit logs
* Fix race condition for animation
* Use shared workflow tool util file
---------
Co-authored-by: Theodore Li <theo@sim.ai>
* fix: chat scrollbar on sidebar collapse/open
* edit existing workflow should bring up artifact
* fix(agent) subagent and main agent text being merged without spacing
* feat(mothership): remove resource-level delete tools from copilot
Remove delete operations for workflows, folders, tables, and files
from the mothership copilot to prevent destructive actions via AI.
Row-level and column-level deletes are preserved.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: stop sidebar from auto-collapsing when resource panel appears (#3540)
The sidebar was forcibly collapsed whenever a resource (e.g. workflow)
first appeared in the resource panel during a task. This was disruptive
on larger screens where users want to keep both the sidebar and resource
panel visible simultaneously.
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* fix(mothership): insert copilot-created workflows at top of list (#3537)
* feat(mothership): remove resource-level delete tools from copilot
Remove delete operations for workflows, folders, tables, and files
from the mothership copilot to prevent destructive actions via AI.
Row-level and column-level deletes are preserved.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix(mothership): insert copilot-created workflows at top of list
* fix(mothership): server-side top-insertion sort order and deduplicate registry logic
* fix(mothership): include folder sort orders when computing top-insertion position
* fix(mothership): use getNextWorkflowColor instead of hardcoded color
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* fix(stop) Add stop of motehership ran workflows, persist stop messages (#3538)
* Connect play stop workflow in embedded view to workflow
* Fix stop not actually stoping workflow
* Fix ui not showing stopped by user
* Lint fix
* Plumb cancellation through system
* Stopping mothership chat stops workflow
* Remove extra fluff
* Persist blocks on cancellation
* Add root level stopped by user
---------
Co-authored-by: Theodore Li <theo@sim.ai>
* fix(autolayout): targetted autolayout heuristic restored (#3536)
* fix(autolayout): targetted autolayout heuristic restored
* fix autolayout boundary cases
* more fixes
* address comments
* on conflict updates
* address more comments
* fix relative position scope
* fix tye omission
* address bugbot comment
* Credential tags
* Credential id field
* feat(mothership): server-persisted unread task indicators via SSE (#3549)
* feat(mothership): server-persisted unread task indicators via SSE
Replace fragile client-side polling + timer-based green flash with
server-persisted lastSeenAt semantics, real-time SSE push via Redis
pub/sub, and dot overlay UI on the Blimp icon.
- Add lastSeenAt column to copilotChats for server-persisted read state
- Add Redis/local pub/sub singleton for task status events (started,
completed, created, deleted, renamed)
- Add SSE endpoint (GET /api/mothership/events) with heartbeat and
workspace-scoped filtering
- Add mark-read endpoint (POST /api/mothership/chats/read)
- Publish SSE events from chat, rename, delete, and auto-title handlers
- Add useTaskEvents hook for client-side SSE subscription
- Add useMarkTaskRead mutation with optimistic update
- Replace timer logic in sidebar with TaskStatus state machine
(running/unread/idle) and dot overlay using brand color variables
- Mark tasks read on mount and stream completion in home page
- Fix security: add userId check to delete WHERE clause
- Fix: bump updatedAt on stream completion
- Fix: set lastSeenAt on rename to prevent false-positive unread
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: address PR review feedback
- Return 404 when delete finds no matching chat (was silent no-op)
- Move log after ownership check so it only fires on actual deletion
- Publish completed SSE event from stop route so sidebar dot clears on abort
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: backfill last_seen_at in migration to prevent false unread dots
Existing rows would have last_seen_at = NULL after migration, causing
all past completed tasks to show as unread. Backfill sets last_seen_at
to updated_at for all existing rows.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: timestamp mismatch on task creation + wasSendingRef leak across navigation
- Pass updatedAt explicitly alongside lastSeenAt on chat creation so
both use the same JS timestamp (DB defaultNow() ran later, causing
updatedAt > lastSeenAt → false unread)
- Reset wasSendingRef when chatId changes to prevent a stale true
from task A triggering a redundant markRead on task B
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: mark-read fires for inline-created chats + encode workspaceId in SSE URL
Expose resolvedChatId from useChat so home.tsx can mark-read even when
chatId prop stays undefined after replaceState URL update. Also
URL-encode workspaceId in EventSource URL as a defensive measure.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: auto-focus home input on initial view + fix sidebar task click handling
Auto-focus the textarea when the initial home view renders. Also fix
sidebar task click to always call onMultiSelectClick so selection state
stays consistent.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: auto-title sets lastSeenAt + move started event inside DB guard
Auto-title now sets both updatedAt and lastSeenAt (matching the rename
route pattern) to prevent false-positive unread dots. Also move the
'started' SSE event inside the if(updated) guard so it only fires when
the DB update actually matched a row.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* modified tasks multi select to be just like workflows
* fix
* refactor: extract generic pub/sub and SSE factories + fixes
- Extract createPubSubChannel factory (lib/events/pubsub.ts) to eliminate
duplicated Redis/EventEmitter boilerplate between task and MCP pub/sub
- Extract createWorkspaceSSE factory (lib/events/sse-endpoint.ts) to share
auth, heartbeat, and cleanup logic across SSE endpoints
- Fix auto-title race suppressing unread status by removing updatedAt/lastSeenAt
from title-only DB update
- Fix wheel event listener leak in ResourceTabs (RefCallback cleanup was silently
discarded)
- Fix getFullSelection() missing taskIds (inconsistent with hasAnySelection)
- Deduplicate SSE_RESPONSE_HEADERS to spread from shared SSE_HEADERS
- Hoist isSttAvailable to module-level constant to avoid per-render IIFE
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* feat(logs): add workflow trigger type for sub-workflow executions (#3554)
* feat(logs): add workflow trigger type for sub-workflow executions
* fix(logs): align workflow filter color with blue-secondary badge variant
* feat(tab) allow user to control resource tabs
* Make resources persist to backend
* Use colored squares for workflows
* Add click and drag functionality to resource
* Fix expanding panel logic
* Reduce duplication, reading resource also opens up resource panel
* Move resource dropdown to own file
* Handle renamed resources
* Clicking already open tab should just switch to tab
---------
Co-authored-by: Theodore Li <theo@sim.ai>
* Fix new resource tab button not appearing on tasks
* improvement(ui): dropdown menus, icons, globals
* improvement: notifications, terminal, globals
* reverted task logic
* feat(context) pass resource tab as context (#3555)
* feat(context) add currenttly open resource file to context for agent
* Simplify resource resolution
* Skip initialize vfs
* Restore ff
* Add back try catch
* Remove redundant code
* Remove json serialization/deserialization loop
---------
Co-authored-by: Theodore Li <theo@sim.ai>
* Feat(references) add at to reference sim resources(#3560)
* feat(chat) add at sign
* Address bugbot issues
* Remove extra chatcontext defs
* Add table and file to schema
* Add icon to chip for files
---------
Co-authored-by: Theodore Li <theo@sim.ai>
* improvement(refactor): move to soft deletion of resources + reliability improvements (#3561)
* improvement(deletion): migrate to soft deletion of resources
* progress
* scoping fixes
* round of fixes
* deduplicated name on workflow import
* fix tests
* add migration
* cleanup dead code
* address bugbot comments
* optimize query
* feat(sim-mailer): email inbox for mothership with chat history and plan gating (#3558)
* feat(sim-mailer): email inbox for mothership with chat history and plan gating
* revert hardcoded ff
* fix(inbox): address PR review comments - plan enforcement, idempotency, webhook auth
- Enforce Max plan at API layer: hasInboxAccess() now checks subscription tier (>= 25k credits or enterprise)
- Add idempotency guard to executeInboxTask() to prevent duplicate emails on Trigger.dev retries
- Add AGENTMAIL_WEBHOOK_SECRET env var for webhook signature verification (Bearer token)
* improvement(inbox): harden security and efficiency from code audit
- Use crypto.timingSafeEqual for webhook secret comparison (prevents timing attacks)
- Atomic claim in executor: WHERE status='received' prevents duplicate processing on retries
- Parallelize hasInboxAccess + getUserEntityPermissions in all API routes (reduces latency)
- Truncate email body at webhook insertion (50k char limit, prevents unbounded DB storage)
- Harden escapeAttr with angle bracket and single quote escaping
- Rename use-inbox.ts to inbox.ts (matches hooks/queries/ naming convention)
* fix(inbox): replace Bearer token auth with proper Svix HMAC-SHA256 webhook verification
- Use per-workspace webhook secret from DB instead of global env var
- Verify AgentMail/Svix signatures: HMAC-SHA256 over svix-id.timestamp.body
- Timing-safe comparison via crypto.timingSafeEqual
- Replay protection via timestamp tolerance (5 min window)
- Join mothershipInboxWebhook in workspace lookup (zero additional DB calls)
- Remove dead AGENTMAIL_WEBHOOK_SECRET env var
- Select only needed workspace columns in webhook handler
* fix(inbox): require webhook secret — reject requests when secret is missing
Previously, if the webhook secret was missing from the DB (corrupted state),
the handler would skip verification entirely and process the request
unauthenticated. Now all three conditions are hard requirements: secret must
exist in DB, Svix headers must be present, and signature must verify.
* fix(inbox): address second round of PR review comments
- Exclude rejected tasks from rate limit count to prevent DoS via spam
- Strip raw HTML from LLM output before marked.parse to prevent XSS in emails
- Track responseSent flag to prevent duplicate emails when DB update fails after send
* fix(inbox): address third round of PR review comments
- Use dynamic isHosted from feature-flags instead of hardcoded true
- Atomic JSON append for chat message persistence (eliminates read-modify-write race)
- Handle cutIndex === 0 in stripQuotedReply (body starts with quote)
- Clean up orphan mothershipInboxWebhook row on enableInbox rollback
- Validate status query parameter against enum in tasks API
* fix(inbox): validate cursor param, preserve code blocks in HTML stripping
- Validate cursor date before using in query (return 400 for invalid)
- Split on fenced code blocks before stripping HTML tags to preserve
code examples in email responses
* fix(inbox): return 500 on webhook server errors to enable Svix retries
* fix(inbox): remove isHosted guard from hasInboxAccess — feature flag is sufficient
* fix(inbox): prevent double-enable from deleting webhook secret row
* fix(inbox): null-safe stripThinkingTags, encode URL params, surface remove-sender errors
- Guard against null result.content in stripThinkingTags
- Use encodeURIComponent on all AgentMail API path parameters
- Surface handleRemoveSender errors to the user instead of swallowing
* improvement(inbox): remove unused types, narrow SELECT queries, fix optimistic ID collision
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix(inbox): add keyboard accessibility to clickable task rows
* fix(inbox): use Svix library for webhook verification, fix responseSent flag, prevent inbox enumeration
- Replace manual HMAC-SHA256 verification with official Svix library per AgentMail docs
- Fix responseSent flag: only set true when email delivery actually succeeds
- Return consistent 401 for unknown inbox and bad signature to prevent enumeration
- Make AgentMailInbox.organization_id optional to match API docs
* chore(db): rebase inbox migration onto feat/mothership-copilot (0172 → 0173)
Sync schema with target branch and regenerate migration as 0173
to avoid conflicts with 0172_silky_magma on feat/mothership-copilot.
* fix(db): rebase inbox migration to 0173 after feat/mothership-copilot divergence
Target branch added 0172_silky_magma, so our inbox migration is now 0173_youthful_stryfe.
* fix(db): regenerate inbox migration after rebase on feat/mothership-copilot
* fix(inbox): case-insensitive email match and sanitize javascript: URIs in email HTML
- Use lower() in isSenderAllowed SQL to match workspace members regardless
of email case stored by auth provider
- Strip javascript:, vbscript:, and data: URIs from marked HTML output to
prevent XSS in outbound email responses
* fix(inbox): case-insensitive email match in resolveUserId
Consistent with the isSenderAllowed fix — uses lower() so mixed-case
stored emails match correctly, preventing silent fallback to workspace owner.
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* Kb args
* refactor(resource): remove logs-specific escape hatches from Resource abstraction
Logs now composes ResourceHeader + ResourceOptionsBar + ResourceTable directly
instead of using Resource with contentOverride/overlay escape hatches. Removes
contentOverride, onLoadMore, hasMore, isLoadingMore from ResourceProps. Adds
ColumnOption to barrel export and fixes table.tsx internal import.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix(sim-mailer): download email attachments and pass to LLM as multimodal content
Attachments were only passed as metadata text in the email body. Now downloads
actual file bytes from AgentMail, converts via createFileContent (same path as
interactive chat), and sends as fileAttachments to the orchestrator. Also
parallelizes attachment fetching with workspace context loading, and downloads
multiple attachments concurrently via Promise.allSettled.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* feat(connector): add Gmail knowledge base connector with thread-based sync and filtering
Syncs email threads from Gmail into knowledge bases with configurable filters:
label scoping, date range presets, promotions/social exclusion, Gmail search
syntax support, and max thread caps to keep KB size manageable.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* feat(connector): add Outlook knowledge base connector with conversation grouping and filtering
Syncs email conversations from Outlook/Office 365 via Microsoft Graph API.
Groups messages by conversationId into single documents. Configurable filters:
folder selection, date range presets, Focused Inbox, KQL search syntax, and
max conversation caps.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* cleanup resource definition
* feat(connectors): add 8 knowledge base connectors — Zendesk, Intercom, ServiceNow, Google Sheets, Microsoft Teams, Discord, Google Calendar, Reddit
Each connector syncs documents into knowledge bases with configurable filtering:
- Zendesk: Help Center articles + support tickets with status/locale filters
- Intercom: Articles + conversations with state filtering
- ServiceNow: KB articles + incidents with state/priority/category filters
- Google Sheets: Spreadsheet tabs as LLM-friendly row-by-row documents
- Microsoft Teams: Channel messages (Slack-like pattern) via Graph API
- Discord: Channel messages with bot token auth
- Google Calendar: Events with date range presets and attendee metadata
- Reddit: Subreddit posts with top comments, sort/time filters
All connectors validated against official API docs with bug fixes applied.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix(inbox): fetch real attachment binary from presigned URL and persist for chat display
The AgentMail attachment endpoint returns JSON metadata with a download_url,
not raw binary. We were base64-encoding the JSON text and sending it to the
LLM, causing provider rejection. Now we parse the metadata, fetch the actual
file from the presigned URL, upload it to copilot storage, and persist it on
the chat message so images render inline with previews.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* added agentmail domain for mailer
* added docs for sim mailer
* fix(resource) handle resource deletion deletion (#3568)
* Add handle dragging tab to input chat
* Add back delete tools
* Handle deletions properly with resources view
* Fix lint
* Add permisssions checking
* Skip resource_added event when resource is deleted
* Pass workflow id as context
---------
Co-authored-by: Theodore Li <theo@sim.ai>
* update docs styling, add delete confirmation on inbox
* Fix fast edit route
* updated docs styling, added FAQs, updated content
* upgrade turbo
* fix(knowledge) use consistent empty state for documents page
Replace the centered "No documents yet" text with the standard Resource
table empty state (column headers + create row), matching all other
resource pages. Move "Upload documents" from header action to table
create row as "New documents".
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix(notifications): polish modal styling, credential display, and trigger filters (#3571)
* fix(notifications): polish modal styling, credential display, and trigger filters
- Show credential display name instead of raw account ID in Slack account selector
- Fix label styling to use default Label component (text-primary) for consistency
- Fix modal body spacing with proper top padding after tab bar
- Replace list-card skeleton with form-field skeleton matching actual layout
- Replace custom "Select a Slack account first" box with disabled Combobox (dependsOn pattern)
- Use proper Label component in WorkflowSelector with consistent gap spacing
- Add overflow badge pattern (slice + +N) to level and trigger filter badges
- Use dynamic trigger options from getTriggerOptions() instead of hardcoded CORE_TRIGGER_TYPES
- Relax API validation to accept integration trigger types (z.string instead of z.enum)
- Deduplicate account rows from credential leftJoin in accounts API
- Extract getTriggerOptions() to module-level constants to avoid per-render calls
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix(notifications): address PR review feedback
- Restore accountId in displayName fallback chain (credentialDisplayName || accountId || providerId)
- Add .default([]) to triggerFilter in create schema to preserve backward compatibility
- Treat empty triggerFilter as "match all" in notification matching logic
- Remove unreachable overflow badge for levelFilter (only 2 possible values)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix(settings): add spacing to Sim Keys toggle and replace Sim Mailer icon with Send
Add 24px top margin to the "Allow personal Sim keys" toggle so it doesn't
sit right below the empty state. Replace the Mail envelope icon for Sim
Mailer with a new Send (paper plane) icon matching the emcn icon style.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* standardize back buttons in settings
* feat(restore) Add restore endpoints and ui (#3570)
* Add restore endpoints and ui
* Derive toast from notification
* Auth user if workspaceid not found
* Fix recently deleted ui
* Add restore error toast
* Fix deleted at timestamp mismatch
---------
Co-authored-by: Theodore Li <theo@sim.ai>
* fix type errors
* Lint
* improvements: ui/ux around mothership
* reactquery best practices, UI alignment in restore
* clamp logs panel
* subagent thinking text
* fix build, speedup tests by up to 40%
* Fix fast edit
* Add download file shortcut on mothership file view
* fix: SVG file support in mothership chat and file serving
- Send SVGs as document/text-xml to Claude instead of unsupported
image/svg+xml, so the mothership can actually read SVG content
- Serve SVGs inline with proper content type and CSP sandbox so
chat previews render correctly
- Add SVG preview support in file viewer (sandboxed iframe)
- Derive IMAGE_MIME_TYPES from MIME_TYPE_MAPPING to reduce duplication
- Add missing webp to contentTypeMap, SAFE_INLINE_TYPES, binaryExtensions
- Consolidate PREVIEWABLE_EXTENSIONS into preview-panel exports
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: replace image/* wildcard with explicit supported types in file picker
The image/* accept attribute allowed users to select BMP, TIFF, HEIC,
and other image types that are rejected server-side. Replace with the
exact set of supported image MIME types and extensions to match the
copilot upload validation.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* Context tags
* Fix lint
* improvement: chat and terminal
---------
Co-authored-by: Emir Karabeg <emirkarabeg@berkeley.edu>
Co-authored-by: Waleed <walif6@gmail.com>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: Theodore Li <teddy@zenobiapay.com>
Co-authored-by: Vikhyath Mondreti <vikhyathvikku@gmail.com>
Co-authored-by: Vikhyath Mondreti <vikhyath@simstudio.ai>
Co-authored-by: Theodore Li <theodoreqili@gmail.com>
Co-authored-by: Theodore Li <theo@sim.ai>
* fix(execution): finalize runs before wrapper recovery
* fix(async): preserve execution correlation across queued runs
* fix(webhooks): pass correlation into preprocessing
* style(webhooks): normalize webhook executor formatting
* fix(async): avoid pre-starting queued execution logs
Let executeWorkflowCore own normal-path logging start so queued workflow and schedule executions persist the richer deployment and environment metadata instead of an earlier placeholder start record.
* fix(async): harden execution finalization guards
Prevent leaked core finalization markers from accumulating while keeping outer recovery paths idempotent. Preserve best-effort logging completion by reusing settled completion promises instead of reopening duplicate terminal writes.
* fix(async): preserve outcomes during cleanup
Keep execution finalization cleanup best-effort so cancellation cleanup failures do not overwrite successful or failed outcomes. Restore webhook processor formatting to the repository Biome style to avoid noisy formatter churn.
* fix(async): keep execution finalization state consistent
Retry minimal logging for early failures, only mark core finalization after a log row actually completes, and let paused completions fall back cleanly.
* fix(async): clean stale finalization guards
Scan all finalized execution ids during TTL cleanup so refreshed keys cannot keep expired guards alive, and cover the reused-id ordering regression.
* fix(async): retry failed error finalization
Allow error finalization to retry after a non-error completion and fallback both fail, and always persist failed/error semantics for completeWithError.
* fix(webhooks): reuse preprocessing execution ids
Thread preprocessing execution identity into queued webhook execution so both phases share the same correlation and logs.
---------
Co-authored-by: test <test@example.com>
* fix(grain): update to stable version of API
* fix prewebhook lookup
* update pending webhook verification infra
* add generic webhook test event verification subblock
* feat(google-ads): add google ads integration for campaign and ad performance queries
* fix(google-ads): add input validation for GAQL query parameters
* fix(google-ads): remove deprecated pageSize param, fix searchSettings nesting, add missing date ranges
* fix(google-ads): validate managerCustomerId before use in login-customer-id header
* chore(docs): regenerate docs after google ads integration
* fix(google-ads): use centralized scope utilities and add type re-export
- Replace hardcoded scopes in auth.ts with getCanonicalScopesForProvider('google-ads')
- Replace hardcoded requiredScopes in block with getScopesForService('google-ads')
- Add type re-export from index.ts barrel
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix(google-ads): add userinfo scopes to oauth provider config
Align google-ads with all other Google services by including
userinfo.email and userinfo.profile scopes in the centralized
OAUTH_PROVIDERS config.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* lint
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* fix(executor): skip Response block formatting for internal JWT callers
The workflow executor tool received `{error: true}` despite successful child
workflow execution when the child had a Response block. This happened because
`createHttpResponseFromBlock()` hijacked the response with raw user-defined
data, and the executor's `transformResponse` expected the standard
`{success, executionId, output, metadata}` wrapper.
Fix: skip Response block formatting when `authType === INTERNAL_JWT` since
Response blocks are designed for external API consumers, not internal
workflow-to-workflow calls. Also extract `AuthType` constants from magic
strings across all auth type comparisons in the codebase.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* test(executor): add route-level tests for Response block auth gating
Verify that internal JWT callers receive standard format while external
callers (API key, session) get Response block formatting. Tests the
server-side condition directly using workflowHasResponseBlock and
createHttpResponseFromBlock with AuthType constants.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix(testing): add AuthType to all hybrid auth test mocks
Route code now imports AuthType from @/lib/auth/hybrid, so test mocks
must export it too. Added AuthTypeMock to @sim/testing and included it
in all 15 test files that mock the hybrid auth module.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Issue keys are self-sufficient identifiers in Jira (e.g., PROJ-123).
The manualIssueKey field is a text input where users type the key directly,
so it should not depend on projectId/manualProjectId. This dependency
caused the field to clear unnecessarily when the project selection changed.
* feat(slack): add email field to get user and list users tools
* fix(slack): use empty string fallback for email and make type non-optional
* fix(slack): comment out users:read.email scope pending app review
Use explicit hyphen separator instead of relying on slice offset to
implicitly include the hyphen in the suffix, making the intent clearer.
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
The GET /rest/api/3/search/jql endpoint requires an explicit `fields`
parameter to return issue data. Without it, only the issue `id` is
returned with all other fields empty. This adds `fields=*all` as the
default when the user doesn't specify custom fields.
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* feat(fathom): add Fathom AI Notetaker integration
* fix(fathom): address PR review feedback
- Add response.ok checks to all 5 tool transformResponse functions
- Fix include_summary default to respect explicit false (check undefined)
- Add externalId validation before URL interpolation in webhook deletion
* fix(fathom): address second round PR review feedback
- Remove redundant 204 status check in deleteFathomWebhook (204 is ok)
- Use consistent undefined-guard pattern for all include flags
- Add .catch() fallback on webhook creation JSON parse
- Change recording_id default from 0 to null to avoid misleading sentinel
* fix(fathom): add missing crm_matches to list_meetings transform and fix action_items type
- Add crm_matches pass-through in list_meetings transform (was silently dropped)
- Fix action_items type to match API schema (description, user_generated, completed, etc.)
- Add crm_matches type with contacts, companies, deals, error fields
* fix(fathom): guard against undefined webhook id on creation success
* fix(fathom): add type to nested trigger outputs and fix boolean coercion
- Add type: 'object' to recorded_by and default_summary trigger outputs
- Use val === true || val === 'true' pattern for include flag coercion
to safely handle both boolean and string values from providerConfig
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: Lakee Sivaraya <71339072+lakeesiv@users.noreply.github.com>
Co-authored-by: Vikhyath Mondreti <vikhyath@simstudio.ai>
Co-authored-by: Vikhyath Mondreti <vikhyathvikku@gmail.com>
* fix(traces): prevent condition blocks from rendering source agent's timeSegments
Condition blocks spread their source block's entire output into their own
output. When the source is an agent, this leaked providerTiming/timeSegments
into the condition's output, causing buildTraceSpans to create "Initial
response" as a child of the condition span instead of the agent span.
Two fixes:
- Skip timeSegment child creation for condition block types in buildTraceSpans
- Filter execution metadata (providerTiming, tokens, toolCalls, model, cost)
from condition handler's filterSourceOutput
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix(traces): guard condition blocks from leaked metadata on old persisted logs
Extend isConditionBlockType guards to also skip setting span.providerTiming,
span.cost, span.tokens, and span.model for condition blocks. This ensures
old persisted logs (recorded before the filterSourceOutput fix) don't display
misleading execution metadata on condition spans.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix(traces): guard toolCalls fallback path for condition blocks on old logs
The else branch that extracts toolCalls from log.output also needs a
condition block guard, otherwise old persisted logs with leaked toolCalls
from the source agent would render on the condition span.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* refactor(traces): extract isCondition to local variable for readability
Cache isConditionBlockType(log.blockType) in a local const at the top
of the forEach loop instead of calling it 6 times per iteration.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* fix(blocks): remap condition/router IDs when duplicating blocks
Condition and router blocks embed IDs in the format `{blockId}-{suffix}`
inside their subBlock values and edge sourceHandles. When blocks were
duplicated, these IDs were not updated to reference the new block ID,
causing duplicate handle IDs and broken edge routing.
Fixes all four duplication paths: single block duplicate, copy/paste,
workflow duplication (server-side), and workflow import.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix(blocks): deep-clone subBlocks before mutating condition IDs
Shallow copy of subBlocks meant remapConditionIds could mutate the
source data (clipboard on repeated paste, or input workflowState on
import). Deep-clone subBlocks in both regenerateBlockIds and
regenerateWorkflowIds to prevent this.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix(blocks): remap condition IDs in regenerateWorkflowStateIds (template use)
The template use code path was missing condition/router ID remapping,
causing broken condition blocks when creating workflows from templates.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* fix(gmail): RFC 2047 encode subject headers for non-ASCII characters
* Fix RFC 2047 encoded word length limit
Split long email subjects into multiple RFC 2047 encoded words to comply with the 75-character limit per RFC 2047 Section 2. Each encoded word now contains at most 45 bytes of UTF-8 content (producing max 60 chars of base64 + 12 chars overhead = 72 total). Multiple encoded words are separated by CRLF + space (folding whitespace).
Applied via @cursor push command
* fix(gmail): split RFC 2047 encoded words on character boundaries
* fix(gmail): simplify RFC 2047 encoding to match Google's own sample
---------
Co-authored-by: Cursor Agent <cursoragent@cursor.com>
* fix(webhooks): eliminate redundant DB queries from webhook execution path
* chore(webhooks): remove implementation-detail comments
* fix(webhooks): restore auth-first ordering and add credential resolution warning
- Revert parallel auth+preprocessing to sequential auth→preprocessing
to prevent rate-limit exhaustion via unauthenticated requests
- Add warning log when credential account resolution fails in background job
* fix(webhooks): restore auth-before-reachability ordering and remove dead credentialAccountUserId field
- Move reachability test back after auth to prevent path enumeration
- Remove dead credentialAccountUserId from WebhookExecutionPayload
- Simplify credential resolution condition in background job
* fix(security): add SSRF protection to database tools and webhook delivery
* fix(security): address review comments on SSRF PR
- Remove Promise.race timeout pattern to avoid unhandled rejections
(http.request timeout is sufficient for webhook delivery)
- Use safeCompare in verifyCronAuth instead of inline HMAC logic
- Strip IPv6 brackets before validateDatabaseHost in Redis route
* fix(security): allow HTTP webhooks and fix misleading MCP error docs
- Add allowHttp option to validateExternalUrl, validateUrlWithDNS,
and secureFetchWithValidation to support HTTP webhook URLs
- Pass allowHttp: true for webhook delivery and test endpoints
- Fix misleading JSDoc on createMcpErrorResponse (doesn't log errors)
- Mark unused error param with underscore prefix
* fix(security): forward allowHttp option through redirect validation
Pass allowHttp to validateUrlWithDNS in the redirect handler of
secureFetchWithPinnedIP so HTTP-to-HTTP redirects work when allowHttp
is enabled for webhook delivery.
* fix(security): block localhost when allowHttp is enabled
When allowHttp is true (user-supplied webhook URLs), explicitly block
localhost/loopback in both validateExternalUrl and validateUrlWithDNS
to prevent SSRF against internal services.
* fix(security): always strip multi-line content in sanitizeConnectionError
Take the first line of the error message regardless of length to
prevent leaking sensitive data from multi-line error messages.
* fix(parallel): align integration with Parallel AI API docs
* fix(parallel): keep processor subBlock ID for backwards compatibility
* fix(parallel): move error field to top level per ToolResponse interface
* fix(parallel): guard research_input and prevent domain leakage across operations
* fix(parallel): make url/title nullable in types to match transformResponse
* fix(parallel): revert search_queries param type to string for backwards compatibility
* feat(hosted keys): Implement serper hosted key
* Handle required fields correctly for hosted keys
* Add rate limiting (3 tries, exponential backoff)
* Add custom pricing, switch to exa as first hosted key
* Add telemetry
* Consolidate byok type definitions
* Add warning comment if default calculation is used
* Record usage to user stats table
* Fix unit tests, use cost property
* Include more metadata in cost output
* Fix disabled tests
* Fix spacing
* Fix lint
* Move knowledge cost restructuring away from generic block handler
* Migrate knowledge unit tests
* Lint
* Fix broken tests
* Add user based hosted key throttling
* Refactor hosted key handling. Add optimistic handling of throttling for custom throttle rules.
* Remove research as hosted key. Recommend BYOK if throtttling occurs
* Make adding api keys adjustable via env vars
* Remove vestigial fields from research
* Make billing actor id required for throttling
* Switch to round robin for api key distribution
* Add helper method for adding hosted key cost
* Strip leading double underscores to avoid breaking change
* Lint fix
* Remove falsy check in favor for explicit null check
* Add more detailed metrics for different throttling types
* Fix _costDollars field
* Handle hosted agent tool calls
* Fail loudly if cost field isn't found
* Remove any type
* Fix type error
* Fix lint
* Fix usage log double logging data
* Fix test
---------
Co-authored-by: Theodore Li <teddy@zenobiapay.com>
* feat(evernote): add Evernote integration with 11 tools
* fix(evernote): fix signed integer mismatch in Thrift version check
* fix(evernote): fix exception field mapping and add sandbox support
* fix(evernote): address PR review feedback
* fix(evernote): clamp maxNotes to Evernote's 250 limit
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* improvement(oauth): centralize scopes and remove dead scope evaluation code
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix(oauth): fix stale scope-descriptions.ts references and add test coverage
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* fix(selectors): resolve env var references at design time for selector context
Selectors now resolve {{ENV_VAR}} references before building context and
returning dependency values to consumers, enabling env-var-based credentials
(e.g. {{SLACK_BOT_TOKEN}}) to work with selector dropdowns.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix(selectors): prevent unresolved env var templates from leaking into context
- Fall back to undefined instead of raw template string when env var is
missing from store, so the null-check in the context loop discards it
- Use resolvedDetailId in query cache key so React Query refetches when
the underlying env var value changes
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix(selectors): use || for consistent empty-string env var handling
Align use-selector-setup.ts with use-selector-query.ts by using || instead
of ?? so empty-string env var values are treated as unset.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* feat(selectors): add dropdown selectors for 14 integrations
* fix(selectors): secure OAuth tokens in JSM and Confluence selector routes
Convert JSM selector-servicedesks, selector-requesttypes, and Confluence
selector-spaces routes from GET (with access token in URL query params) to
POST with authorizeCredentialUse + refreshAccessTokenIfNeeded pattern. Also
adds missing ensureCredential guard to microsoft.planner.plans registry entry.
* fix(selectors): use sanitized serviceDeskId and encode SharePoint siteId
Use serviceDeskIdValidation.sanitized instead of raw serviceDeskId in JSM
request types URL. Add encodeURIComponent to SharePoint siteId to prevent
URL path injection.
* lint
* fix(selectors): revert encodeURIComponent on SharePoint siteId
SharePoint site IDs use the format "hostname,guid,guid" with commas that
must remain unencoded for the Microsoft Graph API. The encodeURIComponent
call would convert commas to %2C and break the API call.
* fix(selectors): use sanitized cloudId in Confluence and JSM route URLs
Use cloudIdValidation.sanitized instead of raw cloudId in URL construction
for consistency with the validation pattern, even though the current
validator returns the input unchanged.
* fix(selectors): add missing context fields to resolution, ensureCredential to sharepoint.lists, and siteId validation
- Add baseId, datasetId, serviceDeskId to SelectorResolutionArgs,
ExtendedSelectorContext, extractExtendedContext, useSelectorDisplayName,
and resolveSelectorForSubBlock so cascading selectors resolve correctly
through the resolution path.
- Add ensureCredential guard to sharepoint.lists registry entry.
- Add regex validation for SharePoint siteId format (hostname,GUID,GUID).
* fix(selectors): rename advanced subBlock IDs to avoid canonicalParamId clashes
Rename all advanced-mode subBlock IDs that matched their canonicalParamId
to use a `manual*` prefix, following the established convention
(e.g., manualSiteId, manualCredential). This prevents ambiguity between
subBlock IDs and canonical parameter names in the serialization layer.
25 renames across 14 blocks: baseId→manualBaseId, tableId→manualTableId,
workspace→manualWorkspace, objectType→manualObjectType, etc.
* Revert "fix(selectors): rename advanced subBlock IDs to avoid canonicalParamId clashes"
This reverts commit 4e30161c68.
* fix(selectors): rename canonicalParamIds to avoid subBlock ID clashes
Prefix all clashing canonicalParamId values with `selected_` so they
don't match any subBlock ID. Update each block's `inputs` section and
`tools.config.params` function to destructure the new canonical names
and remap them to the original tool param names. SubBlock IDs and tool
definitions remain unchanged for backwards compatibility.
Affected: 25 canonical params across 14 blocks (airtable, asana, attio,
calcom, confluence, google_bigquery, google_tasks, jsm, microsoft_planner,
notion, pipedrive, sharepoint, trello, zoom).
* fix(selectors): rename pre-existing driveId and files canonicalParamIds in SharePoint
Apply the same selected_ prefix convention to the pre-existing SharePoint
driveId and files canonical params that clashed with their subBlock IDs.
* style: format long lines in calcom, pipedrive, and sharepoint blocks
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix(selectors): resolve cascading context for selected_ canonical params and normalize Asana response
Strip `selected_` prefix from canonical param IDs when mapping to
SelectorContext fields so cascading selectors (Airtable base→table,
BigQuery dataset→table, JSM serviceDesk→requestType) correctly
propagate parent values.
Normalize Asana workspaces route to return `{ id, name }` instead of
`{ gid, name }` for consistency with all other selector routes.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix(selectors): replace hacky prefix stripping with explicit CANONICAL_TO_CONTEXT mapping
Replace CONTEXT_FIELD_SET (Record<string, true>) with CANONICAL_TO_CONTEXT
(Record<string, keyof SelectorContext>) that explicitly maps canonical
param IDs to their SelectorContext field names.
This properly handles the selected_ prefix aliases (e.g. selected_baseId
→ baseId) without string manipulation, and removes the unsafe
Record<string, unknown> cast.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* refactor(selectors): remove unnecessary selected_ prefix from canonicalParamIds
The selected_ prefix was added to avoid a perceived clash between
canonicalParamId and subBlock id values, but this clash does not
actually cause any issues — pre-existing blocks on main (Google Sheets,
Webflow, SharePoint) already use matching values successfully.
Remove the prefix from all 14 blocks, revert use-selector-setup.ts to
the simple CONTEXT_FIELD_SET pattern, and simplify tools.config.params
functions that were only remapping the prefix back.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix(selectors): add spaceId selector pair to Confluence V2 block
The V2 block was missing the spaceSelector basic-mode selector that the
V1 (Legacy) block already had.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* refactor(selectors): revert V1 block changes, add selectors to Notion V1 for V2 inheritance
Confluence V1: reverted to main state (V2 has its own subBlocks).
Notion V1: added selector pairs per-operation since V2 inherits
subBlocks, inputs, and params from V1.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix(selectors): audit fixes for auth patterns, registry gaps, and display name resolution
- Convert Microsoft Planner plans/tasks routes from GET+getSession to POST+authorizeCredentialUse
- Add fetchById to microsoft.planner (tasks) and sharepoint.sites registry entries
- Add ensureCredential to sharepoint.sites and microsoft.planner registry fetchList
- Update microsoft.planner.plans registry to use POST method
- Add siteId, collectionId, spreadsheetId, fileId to SelectorDisplayNameArgs and caller
- Add fileId to SelectorResolutionArgs and resolution context
- Fix Zoom topicUpdate visibility in basic mode (remove mode:'advanced')
- Change Zoom meetings selector to fetch upcoming_meetings instead of only scheduled
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* style: lint formatting fixes
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix(selectors): consolidate Notion canonical param pairs into array conditions
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix(selectors): add missing selectorKey to Confluence V1 page selector
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix(selectors): use sanitized IDs in URLs, convert SharePoint routes to POST+authorizeCredentialUse
- Use planIdValidation.sanitized in MS Planner tasks fetch URL
- Convert sharepoint/lists and sharepoint/sites from GET+getSession to POST+authorizeCredentialUse
- Update registry entries to match POST pattern
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix(selectors): revert Zoom meetings type to scheduled for broader compatibility
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix(selectors): add SharePoint site ID validator, fix cascading selector display name fallbacks
- Add validateSharePointSiteId to input-validation.ts
- Use validation util in SharePoint lists route instead of inline regex
- Add || fallback to selector IDs in workflow-block.tsx so cascading
display names resolve in basic mode (baseSelector, planSelector, etc.)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix(selectors): hoist requestId before try block in all selector routes
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix(selectors): hoist requestId before try block in Trello boards route
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix(selectors): guard selector queries against unresolved variable references
Skip fetchById and context population when values are design-time
placeholders (<Block.output> or {{ENV_VAR}}) rather than real IDs.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* refactor(selectors): replace hardcoded display name fallbacks with canonical-aware resolution
Use resolveDependencyValue to resolve context values for
useSelectorDisplayName, eliminating manual || getStringValue('*Selector')
fallbacks that required updating for each new selector pair.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix(selectors): tighten SharePoint site ID validation to exclude underscores
SharePoint composite site IDs use hostname,guid,guid format where only
alphanumerics, periods, hyphens, and commas are valid characters.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix(selectors): ensure string IDs in Pipedrive/Cal.com routes, fix Trello closed board filter
Pipedrive pipelines and Cal.com event-types/schedules routes now
consistently return string IDs via String() conversion.
Trello boards route no longer filters out closed boards, preserving
them for fetchById lookups. The closed filter is applied only in the
registry's fetchList so archived boards don't appear in dropdowns
but can still be resolved by ID for display names.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix(selectors): convert Zoom meeting IDs to strings for consistency
Zoom API returns numeric meeting IDs. Convert with String() to match
the string ID convention used by all other selector routes.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix(selectors): align registry types with route string ID returns
Routes already convert numeric IDs to strings via String(), so update
the registry types (CalcomEventType, CalcomSchedule, PipedrivePipeline,
ZoomMeeting) from id: number to id: string and remove the now-redundant
String() coercions in fetchList/fetchById.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* feat(reddit): add 5 new tools, fix bugs, and audit all endpoints against API docs
* fix(reddit): add optional chaining, pagination wiring, and trim safety
- Add optional chaining on children?.[0] in get_posts, get_controversial,
search, and get_comments to prevent TypeError on unexpected API responses
- Wire after/before pagination params to get_messages block operation
- Use ?? instead of || for get_comments limit to handle 0 correctly
- Add .trim() on postId in get_comments URL path
* chore(reddit): remove unused output property constants from types.ts
* fix(reddit): add HTTP error handling to GET tools
Add !response.ok guards to get_me, get_user, get_subreddit_info,
and get_messages to return success: false on non-2xx responses
instead of silently returning empty data with success: true.
* fix(reddit): add input validation and HTTP error guards
- Add validateEnum/validatePathSegment to prevent URL path traversal
- Add !response.ok guards to send_message and reply tools
- Centralize subreddit validation in normalizeSubreddit
* feat(slack): add new tools and user selectors
* fix(slack): fix download fileName param and canvas error handling
* fix(slack): use markdown format for canvas rename title_content
* fix(slack): rename channel output to channelInfo and document presence API limitation
* lint
* fix(chat): use explicit trigger type check instead of heuristic for chat guard (#3419)
* fix(chat): use explicit trigger type check instead of heuristic for chat guard
* fix(chat): remove heuristic fallback from isExecutingFromChat
Use only overrideTriggerType === 'chat' instead of also checking
for 'input' in workflowInput, which can false-positive on manual
executions with workflow input.
* fix(chat): use isExecutingFromChat variable consistently in callbacks
Replace inline overrideTriggerType !== 'chat' checks with
!isExecutingFromChat to stay consistent with the rest of the function.
* fix(slack): add missing fields to SlackChannel interface
* fix(slack): fix canvas transformResponse type mismatch
Provide required output fields on error path to match SlackCanvasResponse type.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix(slack): move error field to top level in canvas transformResponse
The error field belongs on ToolResponse, not inside the output object.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* fix(chat): use explicit trigger type check instead of heuristic for chat guard
* fix(chat): remove heuristic fallback from isExecutingFromChat
Use only overrideTriggerType === 'chat' instead of also checking
for 'input' in workflowInput, which can false-positive on manual
executions with workflow input.
* fix(chat): use isExecutingFromChat variable consistently in callbacks
Replace inline overrideTriggerType !== 'chat' checks with
!isExecutingFromChat to stay consistent with the rest of the function.
* fix(memory): add Bun.gc, stream cancellation, and unconsumed fetch drains
* fix(memory): await reader.cancel() and use non-blocking Bun.gc
* fix(memory): update Bun.gc comment to match non-blocking call
* fix(memory): use response.body.cancel() instead of response.text() for drains
* fix(executor): flush TextDecoder after streaming loop for multi-byte chars
* fix(memory): use text() drain for SecureFetchResponse which lacks body property
* fix(chat): prevent premature isExecuting=false from killing chat stream
The onExecutionCompleted/Error/Cancelled callbacks were setting
isExecuting=false as soon as the server-side SSE stream completed.
For chat executions, this triggered a useEffect in chat.tsx that
cancelled the client-side stream reader before it finished consuming
buffered data — causing empty or partial chat responses.
Skip the isExecuting=false in these callbacks for chat executions
since the chat's own finally block handles cleanup after the stream
is fully consumed.
* fix(chat): remove useEffect anti-pattern that killed chat stream on state change
The effect reacted to isExecuting becoming false to clean up streams,
but this is an anti-pattern per React guidelines — using state changes
as a proxy for events. All cleanup cases are already handled by proper
event paths: stream done (processStreamingResponse), user cancel
(handleStopStreaming), component unmount (cleanup effect), and
abort/error (catch block).
* fix(servicenow): remove invalid string comparison on numeric offset param
* upgrade turborepo
* feat(servicenow): add offset and display value params to read records
* fix(servicenow): address greptile review feedback for offset and displayValue
* fix(servicenow): handle offset=0 correctly in pagination
* fix(servicenow): guard offset against empty string in URL builder
* fix(subflows): recurse into all descendants for lock, enable, and protection checks
* fix(subflows): prevent container resize on initial render and clean up code
- Add canvasReadyRef to skip container dimension recalculation during
ReactFlow init — position changes from extent clamping fired before
block heights are measured, causing containers to resize on page load
- Resolve globals.css merge conflict, remove global z-index overrides
(handled via ReactFlow zIndex prop instead)
- Clean up subflow-node: hoist static helpers to module scope, remove
unused ref, fix nested ternary readability, rename outlineColor→ringColor
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix(subflows): use full ancestor-chain protection for descendant enable-toggle
The enable-toggle for descendants was checking only direct `locked` status
instead of walking the full ancestor chain via `isBlockProtected`. This meant
a block nested 2+ levels inside a locked subflow could still be toggled.
Also added TSDoc clarifying why boxShadow works for subflow ring indicators.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* revert(subflows): remove canvasReadyRef height-gating approach
The canvasReadyRef gating in onNodesChange didn't fully fix the
container resize-on-load issue. Reverting to address properly later.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: remove unintentional edge-interaction CSS from globals
Leftover from merge conflict resolution — not part of this PR's changes.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix(editor): correct isAncestorLocked when block and ancestor both locked, restore fade-in transition
isAncestorLocked was derived from isBlockProtected which short-circuits
on block.locked, so a self-locked block inside a locked ancestor showed
"Unlock block" instead of "Ancestor container is locked". Now walks the
ancestor chain independently.
Also restores the accidentally removed transition-opacity duration-150
class on the ReactFlow container.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix(subflows): use full ancestor-chain protection for top-level enable-toggle, restore edge-label z-index
The top-level block check in batchToggleEnabled used block.locked (self
only) while descendants used isBlockProtected (full ancestor chain). A
block inside a locked ancestor but not itself locked would bypass the
check. Now all three layers (store, collaborative hook, DB operations)
consistently use isBlockProtected/isDbBlockProtected at both levels.
Also restores the accidentally removed edge-labels z-index rule, bumped
from 60 to 1001 so labels render above child nodes (zIndex: 1000).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix(subflows): extract isAncestorProtected utility, add cycle detection to all traversals
- Extract isAncestorProtected from utils.ts so editor.tsx doesn't
duplicate the ancestor-chain walk. isBlockProtected now delegates to it.
- Add visited-set cycle detection to all ancestor walks
(isBlockProtected, isAncestorProtected, isDbBlockProtected) and
descendant searches (findAllDescendantNodes, findDbDescendants) to
guard against corrupt parentId references.
- Document why click-catching div has no event bubbling concern
(ReactFlow renders children as viewport siblings, not DOM children).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* fix(editor): restore cursor position after tag/env-var completion in code editors
* lint
* refactor(editor): extract restoreCursorAfterInsertion helper, fix weak fallbacks
* updated
* fix(editor): replace useEffect with direct ref assignment for editorValueRef
* fix(editor): guard cursor restoration behind preview/readOnly check
Move restoreCursorAfterInsertion inside the !isPreview && !readOnly guard
so cursor position isn't computed against newValue when the textarea still
holds liveValue. Add comment documenting the cross-string index invariant
in the shared helper.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix(editor): escape blockId in CSS selector with CSS.escape()
Prevents potential SyntaxError if blockId ever contains CSS special
characters when querying the textarea for cursor restoration.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* perf(editor): use ref for cursor fallback to stabilize useCallback
Replace cursorPosition state in handleSubflowTagSelect's dependency
array with a cursorPositionRef. This avoids recreating the callback
on every keystroke since cursorPosition is only used as a fallback
when textareaRef.current is null.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* refactor(editor): pass cursor position explicitly from dropdowns
Instead of inferring cursor position by searching for delimiters in the
output string (which could match unrelated < or {{ in code), compute
the exact cursor position in TagDropdown and EnvVarDropdown where the
insertion range is definitively known, and pass it through onSelect.
This follows the same pattern used by CodeMirror, Monaco, and
ProseMirror: the insertion source always knows the range, so cursor
position is computed at the source rather than inferred by the consumer.
- TagDropdown/EnvVarDropdown: compute newCursorPosition, pass as 2nd arg
- restoreCursorAfterInsertion: simplified to just (textarea, position)
- code.tsx, condition-input.tsx, use-subflow-editor.ts: accept position
- Removed editorValueRef and cursorPositionRef from use-subflow-editor
(no longer needed since dropdown computes position)
- Other consumers (native inputs) unaffected due to TS callback compat
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* docs(editor): fix JSDoc terminology — macrotask not microtask
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* feat(executor): support nested loop DAG construction and edge wiring
Wire inner loop sentinel nodes into outer loop sentinel chains so that
nested loops execute correctly. Resolves boundary-node detection to use
effective sentinel IDs for nested loops, handles loop-exit edges from
inner sentinel-end to outer sentinel-end, and recursively clears
execution state for all nested loop scopes between iterations.
NOTE: loop-in-loop nesting only; parallel nesting is not yet supported.
Made-with: Cursor
* feat(executor): add nested loop iteration context and named loop variable resolution
Introduce ParentIteration to track ancestor loop state, build a
loopParentMap during DAG construction, and propagate parent iterations
through block execution and child workflow contexts.
Extend LoopResolver to support named loop references (e.g. <loop1.index>)
and add output property resolution (<loop1.result>). Named references
use the block's display name normalized to a tag-safe identifier,
enabling blocks inside nested loops to reference any ancestor loop's
iteration state.
NOTE: loop-in-loop nesting only; parallel nesting is not yet supported.
Made-with: Cursor
* feat(terminal): propagate parent iteration context through SSE events and terminal display
Thread parentIterations through SSE block-started, block-completed, and
block-error events so the terminal can reconstruct nested loop
hierarchies. Update the entry tree builder to recursively nest inner
loop subflow nodes inside their parent iteration rows, using
parentIterations depth-stripping to support arbitrary nesting depth.
Display the block's store name for subflow container rows instead of
the generic "Loop" / "Parallel" label.
Made-with: Cursor
* feat(canvas): allow nesting subflow containers and prevent cycles
Remove the restriction that prevented subflow nodes from being dragged
into other subflow containers, enabling loop-in-loop nesting on the
canvas. Add cycle detection (isDescendantOf) to prevent a container
from being placed inside one of its own descendants.
Resize all ancestor containers when a nested child moves, collect
descendant blocks when removing from a subflow so boundary edges are
attributed correctly, and surface all ancestor loop tags in the tag
dropdown for blocks inside nested loops.
Made-with: Cursor
* feat(agent): add MCP server discovery mode for agent tool input (#3353)
* feat(agent): add MCP server discovery mode for agent tool input
* fix(tool-input): use type variant for MCP server tool count badge
* fix(mcp-dynamic-args): align label styling with standard subblock labels
* standardized inp format UI
* feat(tool-input): replace MCP server inline expand with drill-down navigation
* feat(tool-input): add chevron affordance and keyboard nav for MCP server drill-down
* fix(tool-input): handle mcp-server type in refresh, validation, badges, and usage control
* refactor(tool-validation): extract getMcpServerIssue, remove fake tool hack
* lint
* reorder dropdown
* perf(agent): parallelize MCP server tool creation with Promise.all
* fix(combobox): preserve cursor movement in search input, reset query on drilldown
* fix(combobox): route ArrowRight through handleSelect, remove redundant type guards
* fix(agent): rename mcpServers to mcpServerSelections to avoid shadowing DB import, route ArrowRight through handleSelect
* docs: update google integration docs
* fix(tool-input): reset drilldown state on tool selection to prevent stale view
* perf(agent): parallelize MCP server discovery across multiple servers
* improvement(tests): speed up unit tests by eliminating vi.resetModules anti-pattern (#3357)
* improvement(tests): speed up unit tests by eliminating vi.resetModules anti-pattern
- convert 51 test files from vi.resetModules/vi.doMock/dynamic import to vi.hoisted/vi.mock/static import
- add global @sim/db mock to vitest.setup.ts
- switch 4 test files from jsdom to node environment
- remove all vi.importActual calls that loaded heavy modules (200+ block files)
- remove slow mockConsoleLogger/mockAuth/setupCommonApiMocks helpers
- reduce real setTimeout delays in engine tests
- mock heavy transitive deps in diff-engine test
test execution time: 34s -> 9s (3.9x faster)
environment time: 2.5s -> 0.6s (4x faster)
* docs(testing): update testing best practices with performance rules
- document vi.hoisted + vi.mock + static import as the standard pattern
- explicitly ban vi.resetModules, vi.doMock, vi.importActual, mockAuth, setupCommonApiMocks
- document global mocks from vitest.setup.ts
- add mock pattern reference for auth, hybrid auth, and database chains
- add performance rules section covering heavy deps, jsdom vs node, real timers
* fix(tests): fix 4 failing test files with missing mocks
- socket/middleware/permissions: add vi.mock for @/lib/auth to prevent transitive getBaseUrl() call
- workflow-handler: add vi.mock for @/executor/utils/http matching executor mock pattern
- evaluator-handler: add db.query.account mock structure before vi.spyOn
- router-handler: same db.query.account fix as evaluator
* fix(tests): replace banned Function type with explicit callback signature
* feat(databricks): add Databricks integration with 8 tools (#3361)
* feat(databricks): add Databricks integration with 8 tools
Add complete Databricks integration supporting SQL execution, job management,
run monitoring, and cluster listing via Personal Access Token authentication.
Tools: execute_sql, list_jobs, run_job, get_run, list_runs, cancel_run,
get_run_output, list_clusters
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix(databricks): throw on invalid JSON params, fix boolean coercion, add expandTasks field
- Throw errors on invalid JSON in jobParameters/notebookParams instead of silently defaulting to {}
- Always set boolean params explicitly to prevent string 'false' being truthy
- Add missing expandTasks dropdown UI field for list_jobs operation
* fix(databricks): align tool inputs/outputs with official API spec
- execute_sql: fix wait_timeout default description (50s, not 10s)
- get_run: add queueDuration field, update lifecycle/result state enums
- get_run_output: fix notebook output size (5 MB not 1 MB), add logsTruncated field
- list_runs: add userCancelledOrTimedout to state, fix limit range (1-24), update state enums
- list_jobs: fix name filter description to "exact case-insensitive"
- list_clusters: add PIPELINE_MAINTENANCE to ClusterSource enum
* fix(databricks): regenerate docs to reflect API spec fixes
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* feat(luma): add Luma integration for event and guest management (#3364)
* feat(luma): add Luma integration for event and guest management
Add complete Luma (lu.ma) integration with 6 tools: get event, create event,
update event, list calendar events, get guests, and add guests. Includes block
configuration with wandConfig for timestamps/timezones/durations, advanced mode
for optional fields, and generated documentation.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix(luma): address PR review feedback
- Remove hosts field from list_events transformResponse (not in LumaEventEntry type)
- Fix truncated add_guests description by removing quotes that broke docs generator
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix(luma): fix update_event field name and add_guests response parsing
- Use 'id' instead of 'event_id' in update_event request body per API spec
- Fix add_guests to parse entries[].guest response structure instead of flat guests array
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* feat(gamma): add gamma integration for AI-powered content generation (#3358)
* feat(gamma): add gamma integration for AI-powered content generation
* fix(gamma): address PR review comments
- Make credits/error conditionally included in check_status response to avoid always-truthy objects
- Replace full wordmark SVG with square "G" letterform for proper rendering in icon slots
* fix(gamma): remove imageSource from generate_from_template endpoint
The from-template API only accepts imageOptions.model and imageOptions.style,
not imageOptions.source (image source is inherited from the template).
* fix(gamma): use typed output in check_status transformResponse
* regen docs
* feat(greenhouse): add greenhouse integration for managing candidates, jobs, and applications (#3363)
* feat(ashby): add ashby integration for candidate, job, and application management (#3362)
* feat(ashby): add ashby integration for candidate, job, and application management
* fix(ashby): auto-fix lint formatting in docs files
* improvement(oauth): reordered oauth modal (#3368)
* feat(loops): add Loops email platform integration (#3359)
* feat(loops): add Loops email platform integration
Add complete Loops integration with 10 tools covering all API endpoints:
- Contact management: create, update, find, delete
- Email: send transactional emails with attachments
- Events: trigger automated email sequences
- Lists: list mailing lists and transactional email templates
- Properties: create and list contact properties
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* ran litn
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* feat(resend): expand integration with contacts, domains, and enhanced email ops (#3366)
* improvement(blocks): update luma styling and linkup field modes (#3370)
* improvement(blocks): update luma styling and linkup field modes
* improvement(fireflies): move optional fields to advanced mode
* improvement(blocks): move optional fields to advanced mode for 10 integrations
* improvement(blocks): move optional fields to advanced mode for 6 more integrations
* feat(x): add 28 new X API v2 tool integrations and expand OAuth scopes (#3365)
* feat(x): add 28 new X API v2 tool integrations and expand OAuth scopes
* fix(x): add missing nextToken param to search tweets and fix XCreateTweetParams type
* fix(x): correct API spec issues in retweeted_by, quote_tweets, personalized_trends, and usage tools
* fix(x): add missing newestId and oldestId to error meta in get_liked_tweets and get_quote_tweets
* fix(x): add missing newestId/oldestId to get_liked_tweets success branch and includes to XTweetListResponse
* fix(x): add error handling to create_tweet and delete_tweet transformResponse
* fix(x): add error handling and logger to all X tools
* fix(x): revert block requiredScopes to match current operations
* feat(x): update block to support all 28 new X API v2 tools
* fix(x): add missing text output and fix hiddenResult output key mismatch
* docs(x): regenerate docs for all 28 new X API v2 tools
* improvement(docs): audit and standardize tool description sections, update developer count to 70k (#3371)
* improvement(x): align OAuth scopes, add scope descriptions, and set optional fields to advanced mode (#3372)
* improvement(x): align OAuth scopes, add scope descriptions, and set optional fields to advanced mode
* improvement(skills): add typed JSON outputs guidance to add-tools, add-block, and add-integration skills
* improvement(skills): add final validation steps to add-tools, add-block, and add-integration skills
* fix(skills): correct misleading JSON array comment in wandConfig example
* feat(skills): add validate-integration skill for auditing tools, blocks, and registry against API docs
* improvement(skills): expand validate-integration with full block-tool alignment, OAuth scopes, pagination, and error handling checks
* improvement(ci): add sticky disk caches and bump runner for faster builds (#3373)
* improvement(selectors): make selectorKeys declarative (#3374)
* fix(webflow): resolution for selectors
* remove unecessary fallback'
* fix teams selector resolution
* make selector keys declarative
* selectors fixes
* improvement(selectors): consolidate selector input logic (#3375)
* feat(google-contacts): add google contacts integration (#3340)
* feat(google-contacts): add google contacts integration
* fix(google-contacts): throw error when no update fields provided
* lint
* update icon
* improvement(google-contacts): add advanced mode, error handling, and input trimming
- Set mode: 'advanced' on optional fields (emailType, phoneType, notes, pageSize, pageToken, sortOrder)
- Add createLogger and response.ok error handling to all 6 tools
- Add .trim() on resourceName in get, update, delete URL builders
* improvement(mcp): add all MCP server tools individually instead of as single server entry (#3376)
* improvement(mcp): add all MCP server tools individually instead of as single server entry
* fix(mcp): prevent remove popover from opening inadvertently
* fix(sse): fix memory leaks in SSE stream cleanup and add memory telemetry (#3378)
* fix(sse): fix memory leaks in SSE stream cleanup and add memory telemetry
* improvement(monitoring): add SSE metering to wand, execution-stream, and a2a-message endpoints
* fix(workflow-execute): remove abort from cancel() to preserve run-on-leave behavior
* improvement(monitoring): use stable process.getActiveResourcesInfo() API
* refactor(a2a): hoist resubscribe cleanup to eliminate duplication between start() and cancel()
* style(a2a): format import line
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix(wand): set guard flag on early-return decrement for consistency
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* improvement(ashby): validate ashby integration and update skill files (#3381)
* improvement(luma): expand host response fields and harden event ID inputs (#3383)
* improvement(resend): add error handling, authMode, and naming consistency (#3382)
* fix(chat-deploy): fix launch chat popup and auth persistence, clean up React anti-patterns (#3380)
* fix(chat-deploy): fix launch chat popup and auth persistence, clean up React anti-patterns
* lint
* fix(greenhouse): fix email_address query param, add .trim() to ID paths, revert onValidationChange to useEffect
* fix(chat-deploy): fix stale AuthSelector state, stabilize refetch ref, clean up copy timeout
* fix(chat-deploy): reset chatSuccess on modal open to prevent stuck state
* improvement(loops): validate loops integration and update skill files (#3384)
* improvement(loops): validate loops integration and update skill files
* loops icon color
* update databricks icon
* fix(monitoring): set MemoryTelemetry logger to INFO level for production visibility (#3386)
Production defaults to ERROR-only logging. Without this override,
memory snapshots would be silently suppressed.
* feat(integrations): add amplitude, google pagespeed insights, and pagerduty integrations (#3385)
* feat(integrations): add amplitude and google pagespeed insights integrations
* verified and regen docs
* fix icons
* fix(integrations): add pagerduty to tool and block registries
Re-add registry entries that were reverted after initial commit.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* more updates
* ack comemnts
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* feat(docs): add API reference with OpenAPI spec and auto-generated endpoint pages (#3388)
* feat(docs): add API reference with OpenAPI spec and auto-generated endpoint pages
* multiline curl
* random improvements
* cleanup
* update docs copy
* fix build
* cast
* fix builg
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: Lakee Sivaraya <71339072+lakeesiv@users.noreply.github.com>
Co-authored-by: Vikhyath Mondreti <vikhyath@simstudio.ai>
Co-authored-by: Vikhyath Mondreti <vikhyathvikku@gmail.com>
* fix(icons): fix pagerduty icon (#3392)
* improvement(executor): audit and harden nested loop/parallel implementation
* improvement(executor): audit and harden nested loop/parallel implementation
- Replace unsafe _childWorkflowInstanceId cast with typeof type guard
- Reuse WorkflowNodeMetadata interface instead of inline type duplication
- Rename _executeCore to executeCore (private, no underscore needed)
- Add log warning when SSE callbacks are dropped beyond MAX_SSE_CHILD_DEPTH
- Remove unnecessary onStream type assertion, use StreamingExecution type
- Convert OUTPUT_PROPERTIES/KNOWN_PROPERTIES from arrays to Sets for O(1) lookup
- Add type guard in loop resolver resolveOutput before casting
- Add TSDoc to edgeCrossesLoopBoundary explaining original-ID usage
- Add TSDoc to MAX_SSE_CHILD_DEPTH constant
- Update ParentIteration TSDoc to reflect parallel nesting support
- Type usageControl as union 'auto'|'force'|'none' in buildMcpTool
- Replace (t: any) casts with typed objects in agent-handler tests
- Add type guard in builder-data convertArrayItem
- Make ctx required in clearLoopExecutionState (only caller always passes it)
- Replace Math.random() with deterministic counter in terminal tests
- Fix isWorkflowBlockType mock to actually check block types
- Add loop-in-loop and workflow block tree tests
* improvement(executor): audit fixes for nested subflow implementation
- Fix findInnermostLoopForBlock/ParallelForBlock to return deepest nested
container instead of first Object.keys() match
- Fix isBlockInLoopOrDescendant returning false when directLoopId equals
target (should return true)
- Add isBlockInParallelOrDescendant with recursive nested parallel checking
to match loop resolver behavior
- Extract duplicated ~20-line iteration context building from loop/parallel
orchestrators into shared buildContainerIterationContext utility
- Remove inline import() type references in orchestrators
- Remove dead executionOrder field from WorkflowNodeMetadata
- Remove redundant double-normalization in findParallelBoundaryNodes
- Consolidate 3 identical tree-walk helpers into generic hasMatchInTree
- Add empty-array guards for Math.min/Math.max in terminal utils
- Make KNOWN_PROPERTIES a Set in parallel resolver for consistency
- Remove no-op handleDragEnd callback from toolbar
- Remove dead result/results entries from KNOWN_PROPERTIES in loop resolver
- Add tests for buildContainerIterationContext
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* finished
* improvement(airtable): added more tools (#3396)
* fix(layout): polyfill crypto.randomUUID for non-secure HTTP contexts (#3397)
* feat(integrations): add dub.co integration (#3400)
* feat(integrations): add dub.co integration
* improvement(dub): add manual docs description and lint formatting fixes
* lint
* fix(dub): remove unsupported optional property from block outputs
* fix(memory): fix O(n²) string concatenation and unconsumed fetch response leaks (#3399)
* fix(monitoring): set MemoryTelemetry logger to INFO level for production visibility
Production defaults to ERROR-only logging. Without this override,
memory snapshots would be silently suppressed.
* fix(memory): fix O(n²) string concatenation and unconsumed fetch response leaks
* fix(tests): add text() mock to workflow-handler test fetch responses
* fix(memory): remove unused O(n²) join in onStreamChunk callback
* chore(careers): remove careers page, redirect to Ashby jobs portal (#3401)
* chore(careers): remove careers page, redirect to Ashby jobs portal
* lint
* feat(integrations): add google meet integration (#3403)
* feat(integrations): add google meet integration
* lint
* ack comments
* ack comments
* fix(terminal): deduplicate nested container entries in buildEntryTree
Filter out container-typed block rows when matching nested subflow
nodes exist, preventing nested loops/parallels from appearing twice
(once as a flat block and once as an expandable subflow).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* improvement(executor): clean up nested subflow implementation
- Fix wireSentinelEdges to use LOOP_EXIT handle for nested loop terminals
- Extract buildExecutionPipeline to deduplicate orchestrator wiring
- Replace two-phase init with constructor injection for Loop/ParallelOrchestrator
- Remove dead code: shouldExecuteLoopNode, resolveForEachItems, isLoopNode, isParallelNode, isSubflowBlockType
- Deduplicate currentItem resolution in ParallelResolver via resolveCurrentItem
- Type getDistributionItems param as SerializedParallel instead of any
- Demote verbose per-reference logger.info to logger.debug in evaluateWhileCondition
- Add loop-in-parallel wiring test in edges.test.ts
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix(test): update parallel resolver test to use distribution instead of distributionItems
The distributionItems fallback was never part of SerializedParallel — it
only worked through any typing. Updated the test to use the real
distribution property.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix(executor): skip loop back-edges in parallel boundary detection and update test
findParallelBoundaryNodes now skips LOOP_CONTINUE back-edges when
detecting terminal nodes, matching findLoopBoundaryNodes behavior.
Without this, a nested loop's back-edge was incorrectly counted as a
forward edge within the parallel, preventing terminal detection.
Also updated parallel resolver test to use the real distribution
property instead of the non-existent distributionItems fallback.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix(executor): clean up cloned loop scopes in deleteParallelScopeAndClones
When a parallel contains a nested loop, cloned loop scopes (__obranch-N)
created by expandParallel were not being deleted, causing stale scopes to
persist across outer loop iterations.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix(executor): remove dead fallbacks, fix nested loop boundary detection, restore executionOrder
- Remove unreachable `?? candidateIds[0]` fallbacks in loop/parallel resolvers
- Remove arbitrary first-match fallback scan in findEffectiveContainerId
- Fix edgeCrossesLoopBoundary to use innermost loop detection for nested loops
- Add warning log for missing branch outputs in parallel aggregation
- Restore executionOrder on WorkflowNodeMetadata and pipe through child workflow notification
- Remove dead sim-drag-subflow classList.remove call
- Clean up cloned loop subflowParentMap entries in deleteParallelScopeAndClones
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* leftover
* upgrade turborepo
* update stagehand icon
* fix(tag-dropdown): show contextual loop/parallel tags for deeply nested blocks
findAncestorLoops only checked direct loop membership, missing blocks nested
inside parallels within loops (and vice versa). Refactored to walk through
both loop and parallel containers recursively, so a block inside a parallel
inside a loop correctly sees the loop's contextual tags (index, currentItem)
instead of the loop's output tags (results).
Also fixed parallel ancestor detection to handle nested parallel-in-loop and
loop-in-parallel scenarios, collecting all ancestor parallels instead of just
the immediate containing one.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* testing
* fixed dedicated logs
* fix
* fix(subflows): enable nested subflow interaction and execution highlighting
Remove !important z-index overrides that prevented nested subflows from
being grabbed/dragged independently. Z-index is now managed by ReactFlow's
elevateNodesOnSelect and per-node zIndex: depth props. Also adds execution
status highlighting for nested subflows in both canvas and snapshot preview.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix(preview): add cycle guard to recursive subflow status derivation
Prevents infinite recursion if subflowChildrenMap contains circular
references by tracking visited nodes during traversal.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: Lakee Sivaraya <71339072+lakeesiv@users.noreply.github.com>
Co-authored-by: Vikhyath Mondreti <vikhyath@simstudio.ai>
Co-authored-by: Vikhyath Mondreti <vikhyathvikku@gmail.com>
Co-authored-by: Vasyl Abramovych <vasyl.abramovych@gmail.com>
* fix(monitoring): set MemoryTelemetry logger to INFO level for production visibility
Production defaults to ERROR-only logging. Without this override,
memory snapshots would be silently suppressed.
* fix(memory): fix O(n²) string concatenation and unconsumed fetch response leaks
* fix(tests): add text() mock to workflow-handler test fetch responses
* fix(memory): remove unused O(n²) join in onStreamChunk callback
* feat(integrations): add amplitude and google pagespeed insights integrations
* verified and regen docs
* fix icons
* fix(integrations): add pagerduty to tool and block registries
Re-add registry entries that were reverted after initial commit.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* more updates
* ack comemnts
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* fix(chat-deploy): fix launch chat popup and auth persistence, clean up React anti-patterns
* lint
* fix(greenhouse): fix email_address query param, add .trim() to ID paths, revert onValidationChange to useEffect
* fix(chat-deploy): fix stale AuthSelector state, stabilize refetch ref, clean up copy timeout
* fix(chat-deploy): reset chatSuccess on modal open to prevent stuck state
* fix(sse): fix memory leaks in SSE stream cleanup and add memory telemetry
* improvement(monitoring): add SSE metering to wand, execution-stream, and a2a-message endpoints
* fix(workflow-execute): remove abort from cancel() to preserve run-on-leave behavior
* improvement(monitoring): use stable process.getActiveResourcesInfo() API
* refactor(a2a): hoist resubscribe cleanup to eliminate duplication between start() and cancel()
* style(a2a): format import line
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix(wand): set guard flag on early-return decrement for consistency
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* improvement(mcp): add all MCP server tools individually instead of as single server entry
* fix(mcp): prevent remove popover from opening inadvertently
* improvement(x): align OAuth scopes, add scope descriptions, and set optional fields to advanced mode
* improvement(skills): add typed JSON outputs guidance to add-tools, add-block, and add-integration skills
* improvement(skills): add final validation steps to add-tools, add-block, and add-integration skills
* fix(skills): correct misleading JSON array comment in wandConfig example
* feat(skills): add validate-integration skill for auditing tools, blocks, and registry against API docs
* improvement(skills): expand validate-integration with full block-tool alignment, OAuth scopes, pagination, and error handling checks
* feat(x): add 28 new X API v2 tool integrations and expand OAuth scopes
* fix(x): add missing nextToken param to search tweets and fix XCreateTweetParams type
* fix(x): correct API spec issues in retweeted_by, quote_tweets, personalized_trends, and usage tools
* fix(x): add missing newestId and oldestId to error meta in get_liked_tweets and get_quote_tweets
* fix(x): add missing newestId/oldestId to get_liked_tweets success branch and includes to XTweetListResponse
* fix(x): add error handling to create_tweet and delete_tweet transformResponse
* fix(x): add error handling and logger to all X tools
* fix(x): revert block requiredScopes to match current operations
* feat(x): update block to support all 28 new X API v2 tools
* fix(x): add missing text output and fix hiddenResult output key mismatch
* docs(x): regenerate docs for all 28 new X API v2 tools
* improvement(blocks): update luma styling and linkup field modes
* improvement(fireflies): move optional fields to advanced mode
* improvement(blocks): move optional fields to advanced mode for 10 integrations
* improvement(blocks): move optional fields to advanced mode for 6 more integrations
* feat(gamma): add gamma integration for AI-powered content generation
* fix(gamma): address PR review comments
- Make credits/error conditionally included in check_status response to avoid always-truthy objects
- Replace full wordmark SVG with square "G" letterform for proper rendering in icon slots
* fix(gamma): remove imageSource from generate_from_template endpoint
The from-template API only accepts imageOptions.model and imageOptions.style,
not imageOptions.source (image source is inherited from the template).
* fix(gamma): use typed output in check_status transformResponse
* regen docs
* feat(luma): add Luma integration for event and guest management
Add complete Luma (lu.ma) integration with 6 tools: get event, create event,
update event, list calendar events, get guests, and add guests. Includes block
configuration with wandConfig for timestamps/timezones/durations, advanced mode
for optional fields, and generated documentation.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix(luma): address PR review feedback
- Remove hosts field from list_events transformResponse (not in LumaEventEntry type)
- Fix truncated add_guests description by removing quotes that broke docs generator
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix(luma): fix update_event field name and add_guests response parsing
- Use 'id' instead of 'event_id' in update_event request body per API spec
- Fix add_guests to parse entries[].guest response structure instead of flat guests array
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* feat(databricks): add Databricks integration with 8 tools
Add complete Databricks integration supporting SQL execution, job management,
run monitoring, and cluster listing via Personal Access Token authentication.
Tools: execute_sql, list_jobs, run_job, get_run, list_runs, cancel_run,
get_run_output, list_clusters
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix(databricks): throw on invalid JSON params, fix boolean coercion, add expandTasks field
- Throw errors on invalid JSON in jobParameters/notebookParams instead of silently defaulting to {}
- Always set boolean params explicitly to prevent string 'false' being truthy
- Add missing expandTasks dropdown UI field for list_jobs operation
* fix(databricks): align tool inputs/outputs with official API spec
- execute_sql: fix wait_timeout default description (50s, not 10s)
- get_run: add queueDuration field, update lifecycle/result state enums
- get_run_output: fix notebook output size (5 MB not 1 MB), add logsTruncated field
- list_runs: add userCancelledOrTimedout to state, fix limit range (1-24), update state enums
- list_jobs: fix name filter description to "exact case-insensitive"
- list_clusters: add PIPELINE_MAINTENANCE to ClusterSource enum
* fix(databricks): regenerate docs to reflect API spec fixes
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* improvement(tests): speed up unit tests by eliminating vi.resetModules anti-pattern
- convert 51 test files from vi.resetModules/vi.doMock/dynamic import to vi.hoisted/vi.mock/static import
- add global @sim/db mock to vitest.setup.ts
- switch 4 test files from jsdom to node environment
- remove all vi.importActual calls that loaded heavy modules (200+ block files)
- remove slow mockConsoleLogger/mockAuth/setupCommonApiMocks helpers
- reduce real setTimeout delays in engine tests
- mock heavy transitive deps in diff-engine test
test execution time: 34s -> 9s (3.9x faster)
environment time: 2.5s -> 0.6s (4x faster)
* docs(testing): update testing best practices with performance rules
- document vi.hoisted + vi.mock + static import as the standard pattern
- explicitly ban vi.resetModules, vi.doMock, vi.importActual, mockAuth, setupCommonApiMocks
- document global mocks from vitest.setup.ts
- add mock pattern reference for auth, hybrid auth, and database chains
- add performance rules section covering heavy deps, jsdom vs node, real timers
* fix(tests): fix 4 failing test files with missing mocks
- socket/middleware/permissions: add vi.mock for @/lib/auth to prevent transitive getBaseUrl() call
- workflow-handler: add vi.mock for @/executor/utils/http matching executor mock pattern
- evaluator-handler: add db.query.account mock structure before vi.spyOn
- router-handler: same db.query.account fix as evaluator
* fix(tests): replace banned Function type with explicit callback signature
* feat(agent): add MCP server discovery mode for agent tool input
* fix(tool-input): use type variant for MCP server tool count badge
* fix(mcp-dynamic-args): align label styling with standard subblock labels
* standardized inp format UI
* feat(tool-input): replace MCP server inline expand with drill-down navigation
* feat(tool-input): add chevron affordance and keyboard nav for MCP server drill-down
* fix(tool-input): handle mcp-server type in refresh, validation, badges, and usage control
* refactor(tool-validation): extract getMcpServerIssue, remove fake tool hack
* lint
* reorder dropdown
* perf(agent): parallelize MCP server tool creation with Promise.all
* fix(combobox): preserve cursor movement in search input, reset query on drilldown
* fix(combobox): route ArrowRight through handleSelect, remove redundant type guards
* fix(agent): rename mcpServers to mcpServerSelections to avoid shadowing DB import, route ArrowRight through handleSelect
* docs: update google integration docs
* fix(tool-input): reset drilldown state on tool selection to prevent stale view
* perf(agent): parallelize MCP server discovery across multiple servers
- Add body-format=storage to GET-before-PUT for page and blogpost updates
(without this, Confluence v2 API does not return body content, causing
the fallback to erase content when only updating the title)
- Fetch current space name when updating only description (Confluence API
requires name on PUT, so we preserve the existing name automatically)
buildUnifiedStartOutput and buildIntegrationTriggerOutput first populate
output with schema-coerced structuredInput values (via coerceValue), then
iterate workflowInput and unconditionally overwrite those keys with raw
strings. This causes typed values (arrays, objects, numbers, booleans)
passed to child workflows to arrive as stringified versions.
Add a structuredKeys guard so the workflowInput loop skips keys already
set by the coerced structuredInput, letting coerceValue's type-aware
parsing (JSON.parse for objects/arrays, Number() for numbers, etc.)
take effect.
Fixes#3105
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* feat(sidebar): add lock/unlock to workflow registry context menu
* docs(tools): add manual descriptions to google_books and table
* docs(tools): add manual descriptions to google_bigquery and google_tasks
* fix(sidebar): avoid unnecessary store subscriptions and fix mixed lock state toggle
* fix(sidebar): use getWorkflowLockToggleIds utility for lock toggle
Replaces manual pivot-sorting logic with the existing utility function,
which handles block ordering and no-op guards consistently.
* lint
* feat(google-tasks): add Google Tasks integration
* fix(google-tasks): return actual taskId in delete response
* fix(google-tasks): use absolute imports and fix registry order
* fix(google-tasks): rename list-task-lists to list_task_lists for doc generator
* improvement(google-tasks): destructure task and taskList outputs with typed schemas
* ran lint
* improvement(google-tasks): add wandConfig for due date timestamp generation
* fix(terminal): thread executionOrder through child workflow SSE events for loop support
* ran lint
* fix(terminal): render iteration children through EntryNodeRow for workflow block expansion
IterationNodeRow was rendering all children as flat BlockRow components,
ignoring nodeType. Workflow blocks inside loop iterations were never
rendered as WorkflowNodeRow, so they had no expand chevron or child tree.
* fix(terminal): add childWorkflowBlockId to matchesEntryForUpdate
Sub-executors reset executionOrderCounter, so child blocks across loop
iterations share the same blockId + executionOrder. Without checking
childWorkflowBlockId, updateConsole for iteration N overwrites entries
from iterations 0..N-1, causing all child blocks to be grouped under
the last iteration's workflow instance.
* feat(confluence): add get user by account ID tool
* feat(confluence): add missing tools for tasks, blog posts, spaces, descendants, permissions, and properties
Add 16 new Confluence operations: list/get/update tasks, update/delete blog posts,
create/update/delete spaces, get page descendants, list space permissions,
list/create/delete space properties. Includes API routes, tool definitions,
block config wiring, OAuth scopes, and generated docs.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix(confluence): add missing OAuth scopes to auth.ts provider config
The OAuth authorization flow uses scopes from auth.ts, not oauth.ts.
The 9 new scopes were only added to oauth.ts and the block config but
not to the actual provider config in auth.ts, causing re-auth to still
return tokens without the new scopes.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* lint
* fix(confluence): fix truncated get_user tool description in docs
Remove apostrophe from description that caused MDX generation to
truncate at the escape character.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix(confluence): address PR review feedback
- Move get_user from GET to POST to avoid exposing access token in URL
- Add 400 validation for missing params in space-properties create/delete
- Add null check for blog post version before update to prevent TypeError
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* feat(confluence): add missing response fields for descendants and tasks
- Add type and depth fields to page descendants (from Confluence API)
- Add body field (storage format) to task list/get/update responses
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* lint
* fix(confluence): use validatePathSegment for Atlassian account IDs
validateAlphanumericId rejects valid Atlassian account IDs that contain
colons (e.g. 557058:6b9c9931-4693-49c1-8b3a-931f1af98134). Use
validatePathSegment with a custom pattern allowing colons instead.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* ran lint
* update mock
* upgrade turborepo
* fix(confluence): reject empty update body for space PUT
Return 400 when neither name nor description is provided for space
update, instead of sending an empty body to the Confluence API.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix(confluence): remove spaceId requirement for create_space and fix list_tasks pagination
- Remove create_space from spaceId condition array since creating a space
doesn't require a space ID input
- Remove list_tasks from generic supportsCursor array so it uses its
dedicated handler that correctly passes assignedTo and status filters
during pagination
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* ran lint
* fixed type errors
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* fix(api): add configurable request retries
The API block docs described automatic retries, but the block didn't expose any retry controls and requests were executed only once.
This adds tool-level retry support with exponential backoff (including Retry-After support) for timeouts, 429s, and 5xx responses, exposes retry settings in the API block and http_request tool, and updates the docs to match.
Fixes#3225
* remove unnecessary helpers, cleanup
* update desc
* ack comments
* ack comment
* ack
* handle timeouts
---------
Co-authored-by: Jay Prajapati <79649559+jayy-77@users.noreply.github.com>
* improvement(creds): bulk paste functionality, save notification, error notif
* use effect anti patterns
* fix add to cursor button
* fix(attio): wrap webhook body in data object and include required filter field
* fixed and tested attio webhook lifecycle
* fix(attio): use code subblock type for JSON input fields
* fix(attio): correct people name attribute format in wand prompt example
* fix(attio): improve wand prompt with correct attribute formats for all field types
* fix(attio): use array format with full_name for personal-name attribute in wand prompt
* fix(attio): use loose null checks to prevent sending null params to API
* fix(attio): add offset param and make pagination fields advanced mode
* fix(attio): remove redundant (optional) from placeholders
* fix(attio): always send required workspace_access and workspace_member_access in create list
* fix(attio): always send api_slug in create list, auto-generate from name if not provided
* fix(attio): update api slug placeholder text
* fix(tools): manage lifecycle for attio tools
* updated docs
* fix(attio): remove incorrect save button reference from setup instructions
* fix(attio): log debug message when signature verification is skipped
* fix(providers): propagate abort signal to all LLM SDK calls
* fix(providers): propagate abort signal to deep research interactions API
* fix(providers): clean up abort listener when sleep timer resolves
* feat(attio): add Attio CRM integration with 40 tools and 18 webhook triggers
* update docs
* fix(attio): use timestamp generationType for date wandConfig fields
* improvement(processing): reduce redundant DB queries in execution preprocessing
* improvement(processing): add defensive ID check for prefetched workflow record
* improvement(processing): fix type safety in execution error logging
Replace `as any` cast in non-SSE error path with proper `buildTraceSpans()`
transformation, matching the SSE error path. Remove redundant `as any` cast
in preprocessing.ts where the types already align.
* improvement(processing): replace `as any` casts with proper types in logging
- logger.ts: cast JSONB cost column to `WorkflowExecutionLog['cost']` instead
of `any` in both `completeWorkflowExecution` and `getWorkflowExecution`
- logger.ts: replace `(orgUsageBefore as any)?.toString?.()` with `String()`
since COALESCE guarantees a non-null SQL aggregate value
- logging-session.ts: cast JSONB cost to `AccumulatedCost` (the local
interface) instead of `any` in `loadExistingCost`
* improvement(processing): use exported HighestPrioritySubscription type in usage.ts
Replace inline `Awaited<ReturnType<typeof getHighestPrioritySubscription>>`
with the already-exported `HighestPrioritySubscription` type alias.
* improvement(processing): replace remaining `as any` casts with proper types
- preprocessing.ts: use exported `HighestPrioritySubscription` type instead
of redeclaring via `Awaited<ReturnType<...>>`
- deploy/route.ts, status/route.ts: cast `hasWorkflowChanged` args to
`WorkflowState` instead of `any` (JSONB + object literal narrowing)
- state/route.ts: type block sanitization and save with `BlockState` and
`WorkflowState` instead of `any`
- search-suggestions.ts: remove 8 unnecessary `as any` casts on `'date'`
literal that already satisfies the `Suggestion['category']` union
* fix(processing): prevent double-billing race in LoggingSession completion
When executeWorkflowCore throws, its catch block fire-and-forgets
safeCompleteWithError, then re-throws. The caller's catch block also
fire-and-forgets safeCompleteWithError on the same LoggingSession. Both
check this.completed (still false) before either's async DB write resolves,
so both proceed to completeWorkflowExecution which uses additive SQL for
billing — doubling the charged cost on every failed execution.
Fix: add a synchronous `completing` flag set immediately before the async
work begins. This blocks concurrent callers at the guard check. On failure,
the flag is reset so the safe* fallback path (completeWithCostOnlyLog) can
still attempt recovery.
* fix(processing): unblock error responses and isolate run-count failures
Remove unnecessary `await waitForCompletion()` from non-SSE and SSE error
paths where no `markAsFailed()` follows — these were blocking error responses
on log persistence for no reason. Wrap `updateWorkflowRunCounts` in its own
try/catch so a run-count DB failure cannot prevent session completion, billing,
and trace span persistence.
* improvement(processing): remove dead setupExecutor method
The method body was just a debug log with an `any` parameter — logging
now works entirely through trace spans with no executor integration.
* remove logger.debug
* fix(processing): guard completionPromise as write-once (singleton promise)
Prevent concurrent safeComplete* calls from overwriting completionPromise
with a no-op. The guard now lives at the assignment site — if a completion
is already in-flight, return its promise instead of starting a new one.
This ensures waitForCompletion() always awaits the real work.
* improvement(processing): remove empty else/catch blocks left by debug log cleanup
* fix(processing): enforce waitForCompletion inside markAsFailed to prevent completion races
Move waitForCompletion() into markAsFailed() so every call site is
automatically safe against in-flight fire-and-forget completions.
Remove the now-redundant external waitForCompletion() calls in route.ts.
* fix(processing): reset completing flag on fallback failure, clean up empty catch
- completeWithCostOnlyLog now resets this.completing = false when
the fallback itself fails, preventing a permanently stuck session
- Use _disconnectError in MCP test-connection to signal intentional ignore
* fix(processing): restore disconnect error logging in MCP test-connection
Revert unrelated debug log removal — this file isn't part of the
processing improvements and the log aids connection leak detection.
* fix(processing): address audit findings across branch
- preprocessing.ts: use undefined (not null) for failed subscription
fetch so getUserUsageLimit does a fresh lookup instead of silently
falling back to free-tier limits
- deployed/route.ts: log warning on loadDeployedWorkflowState failure
instead of silently swallowing the error
- schedule-execution.ts: remove dead successLog parameter and all
call-site arguments left over from logger.debug cleanup
- mcp/middleware.ts: drop unused error binding in empty catch
- audit/log.ts, wand.ts: promote logger.debug to logger.warn in catch
blocks where these are the only failure signal
* revert: undo unnecessary subscription null→undefined change
getHighestPrioritySubscription never throws (it catches internally
and returns null), so the catch block in preprocessExecution is dead
code. The null vs undefined distinction doesn't matter and the
coercions added unnecessary complexity.
* improvement(processing): remove dead try/catch around getHighestPrioritySubscription
getHighestPrioritySubscription catches internally and returns null
on error, so the wrapping try/catch was unreachable dead code.
* improvement(processing): remove dead getSnapshotByHash method
No longer called after createSnapshotWithDeduplication was refactored
to use a single upsert instead of select-then-insert.
---------
Return an anonymous session using the same response envelope as Better Auth's get-session endpoint, and make the session provider tolerant to both wrapped and raw session payloads.
Fixes#2524
* feat(confluence): add webhook triggers for Confluence events
Adds 16 Confluence triggers: page CRUD, comments, blogs, attachments,
spaces, and labels — plus a generic webhook trigger.
* feat(confluence): wire triggers into block and webhook processor
Add trigger subBlocks and triggers config to ConfluenceV2Block so
triggers appear in the UI. Add Confluence signature verification and
event filtering to the webhook processor.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix(confluence): align trigger outputs with actual webhook payloads
- Rewrite output builders to match real Confluence webhook payload
structure (flat spaceKey, numeric version, actual API fields)
- Remove fabricated fields (nested space/version objects, comment.body)
- Add missing fields (creatorAccountId, lastModifierAccountId, self,
creationDate, modificationDate, accountType)
- Add extractor functions (extractPageData, extractCommentData, etc.)
following the same pattern as Jira
- Add formatWebhookInput handler for Confluence in utils.server.ts
so payloads are properly destructured before reaching workflows
- Make event field matching resilient (check both event and webhookEvent)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix(confluence): handle generic webhook in formatWebhookInput
The generic webhook (confluence_webhook) was falling through to
extractPageData, which only returns the page field. For a catch-all
trigger that accepts all event types, preserve all entity fields
(page, comment, blog, attachment, space, label, content).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix(confluence): use payload-based filtering instead of nonexistent event field
Confluence Cloud webhooks don't include an event/webhookEvent field in the
body (unlike Jira). Replaced broken event string matching with structural
payload filtering that checks which entity key is present.
* lint
* fix(confluence): read webhookSecret instead of secret in signature verification
* fix(webhooks): read webhookSecret for jira, linear, and github signature verification
These providers define their secret subBlock with id: 'webhookSecret' but the
processor was reading providerConfig.secret which is always undefined, silently
skipping signature verification even when a secret is configured.
* fix(confluence): use event field for exact matching with entity-category fallback
Admin REST API webhooks (Settings > Webhooks) include an event field for
action-level filtering (page_created vs page_updated). Connect app webhooks
omit it, so we fall back to entity-category matching.
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Add DISABLE_PUBLIC_API / NEXT_PUBLIC_DISABLE_PUBLIC_API environment variables
and disablePublicApi permission group config option to allow self-hosted
deployments and enterprise admins to globally disable the public API toggle.
When disabled: the Access toggle is hidden in the Edit API Info modal,
the execute route blocks unauthenticated public access (401), and the
public-api PATCH route rejects enabling public API (403).
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* feat(gong): add Gong integration with 18 API tools
* fix(gong): make toDateTime optional for list_calls, add list_trackers to workspaceId condition
* chore(gong): regenerate docs
* fix(hex): update icon color and block bgColor
* feat(execution): workflow cycle detection via X-Sim-Via header
* fix(execution): scope X-Sim-Via header to internal routes and add child workflow depth validation
- Move call chain header injection from HTTP tool layer (request.ts/utils.ts)
to tool execution layer (tools/index.ts) gated on isInternalRoute, preventing
internal workflow IDs from leaking to external third-party APIs
- Remove cycle detection from validateCallChain — depth limit alone prevents
infinite loops while allowing legitimate self-recursion (pagination, tree
processing, batch splitting)
- Add validateCallChain check in workflow-handler.ts before spawning child
executor, closing the gap where in-process child workflows skipped validation
- Remove unsafe `(params as any)._context` type bypass in request.ts
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix(execution): validate child call chain instead of parent chain
Validate childCallChain (after appending current workflow ID) rather
than ctx.callChain (parent). Prevents an off-by-one where a chain at
depth 10 could still spawn an 11th workflow.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* fix(executor): resolve block ID for parallel subflow active state
* fix timing for parallel block
* refactor(parallel): extract shared updateActiveBlockRefCount helper
* fix(parallel): error-sticky block run status to prevent branch success masking failure
* Revert "fix(parallel): error-sticky block run status to prevent branch success masking failure"
This reverts commit 9c087cd466.
* fix(security): allow localhost HTTP without weakening SSRF protections
* fix(security): remove extraneous comments and fix failing SSRF test
* fix(security): derive isLocalhost from hostname not resolved IP in validateUrlWithDNS
* fix(security): verify resolved IP is loopback when hostname is localhost in validateUrlWithDNS
---------
Co-authored-by: aayush598 <aayushgid598@gmail.com>
* fix(trigger): handle Slack reaction_added/reaction_removed event payloads
* fix(trigger): use oldest param for conversations.history consistency
* fix oldest param
* fix(trigger): use reactions.get API to fetch message text for thread replies
* fix(tables): hide tables from sidebar and block registry
* fix(trigger): add isolated-vm support to trigger.dev container builds (#3269)
Scheduled workflow executions running in trigger.dev containers were
failing to spawn isolated-vm workers because the native module wasn't
available in the container. This caused loop condition evaluation to
silently fail and exit after one iteration.
- Add isolated-vm to build.external and additionalPackages in trigger config
- Include isolated-vm-worker.cjs via additionalFiles for child process spawning
- Add fallback path resolution for worker file in trigger.dev environment
* lint
Scheduled workflow executions running in trigger.dev containers were
failing to spawn isolated-vm workers because the native module wasn't
available in the container. This caused loop condition evaluation to
silently fail and exit after one iteration.
- Add isolated-vm to build.external and additionalPackages in trigger config
- Include isolated-vm-worker.cjs via additionalFiles for child process spawning
- Add fallback path resolution for worker file in trigger.dev environment
* fix(blocks): add required constraint for serviceDeskId in JSM block
* fix(blocks): rename custom field values to request field values in JSM create request
* fix(blocks): move type coercions from tools.config.tool to tools.config.params
Number() coercions in tools.config.tool ran at serialization time before
variable resolution, destroying dynamic references like <block.result.count>
by converting them to NaN/null. Moved all coercions to tools.config.params
which runs at execution time after variables are resolved.
Fixed in 15 blocks: exa, arxiv, sentry, incidentio, wikipedia, ahrefs,
posthog, elasticsearch, dropbox, hunter, lemlist, spotify, youtube, grafana,
parallel. Also added mode: 'advanced' to optional exa fields.
Closes#3258
* fix(blocks): address PR review — move remaining param mutations from tool() to params()
- Moved field mappings from tool() to params() in grafana, posthog,
lemlist, spotify, dropbox (same dynamic reference bug)
- Fixed parallel.ts excerpts/full_content boolean logic
- Fixed parallel.ts search_queries empty case (must set undefined)
- Fixed elasticsearch.ts timeout not included when already ends with 's'
- Restored dropbox.ts tool() switch for proper default fallback
* fix(blocks): restore field renames to tool() for serialization-time validation
Field renames (e.g. personalApiKey→apiKey) must be in tool() because
validateRequiredFieldsBeforeExecution calls selectToolId()→tool() then
checks renamed field names on params. Only type coercions (Number(),
boolean) stay in params() to avoid destroying dynamic variable references.
* refactor(vercel): mark optional fields as advanced mode
Move optional/power-user fields behind the advanced toggle:
- List Deployments: project filter, target, state
- Create Deployment: project ID override, redeploy from, target
- List Projects: search
- Create/Update Project: framework, build/output/install commands
- Env Vars: variable type
- Webhooks: project IDs filter
- Checks: path, details URL
- Team Members: role filter
- All operations: team ID scope
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* style(youtube): mark optional params as advanced mode
Hide pagination, sort order, and filter fields behind the advanced
toggle for a cleaner default UX across all YouTube operations.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* added advanced fields for vercel and youtube, added cloudflare and dataverse block
* addded desc for dataverse
* add more tools
* ack comment
* more
* ops
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* feat(vercel): add complete Vercel integration with 42 API tools
Add Vercel platform management integration covering deployments, projects,
environment variables, domains, DNS records, aliases, edge configs, and
team/user management. All tools use API key authentication with Bearer tokens.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* feat(vercel): add webhook and deployment check tools
Add 8 new Vercel API tools:
- Webhooks: list, create, delete
- Deployment Checks: create, get, list, update, rerequest
Brings total Vercel tools to 50.
* fix(vercel): expand all object and array output definitions
Expand unexpanded output types:
- get_deployment: meta and gitSource objects now have properties
- list_deployment_files: children array now has items definition
- get_team: teamRoles and teamPermissions arrays now have items
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* update icon size, update docs
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* fix(shortlink): remove isHosted guard from redirects, not available at build time on ECS
* fix(shortlink): use rewrite instead of redirect for Beluga tracking
- Add isEnterpriseMember and canViewUsageInfo flags to subscription permissions
- Hide UsageHeader, CreditBalance, billing date, and usage notifications from enterprise members
- Show only plan name in subscription tab for enterprise members (non-admin)
- Hide usage indicator details (amount, progress pills) from enterprise members
- Team tab already hidden via requiresTeam check in settings modal
Closes#6882
Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: Emir Karabeg <emir-karabeg@users.noreply.github.com>
* feat(audit-log): add persistent audit log system with comprehensive route instrumentation
* fix(audit-log): address PR review — nullable workspaceId, enum usage, remove redundant queries
- Make audit_log.workspace_id nullable with ON DELETE SET NULL (logs survive workspace/user deletion)
- Make audit_log.actor_id nullable with ON DELETE SET NULL
- Replace all 53 routes' string literal action/resourceType with AuditAction.X and AuditResourceType.X enums
- Fix empty workspaceId ('') → null for OAuth, form, and org routes to avoid FK violations
- Remove redundant DB queries in chat manage route (use checkChatAccess return data)
- Fix organization routes to pass workspaceId: null instead of organizationId
* fix(audit-log): replace remaining workspaceId '' fallbacks with null
* fix(audit-log): credential-set org IDs, workspace deletion FK, actorId fallback, string literal action
* reran migrations
* fix(mcp,audit): tighten env var domain bypass, add post-resolution check, form workspaceId
- Only bypass MCP domain check when env var is in hostname/authority, not path/query
- Add post-resolution validateMcpDomain call in test-connection endpoint
- Match client-side isDomainAllowed to same hostname-only bypass logic
- Return workspaceId from checkFormAccess, use in form audit logs
- Add 49 comprehensive domain-check tests covering all edge cases
* fix(mcp): stateful regex lastIndex bug, RFC 3986 authority parsing
- Remove /g flag from module-level ENV_VAR_PATTERN to avoid lastIndex state
- Create fresh regex instances per call in server-side hasEnvVarInHostname
- Fix authority extraction to terminate at /, ?, or # per RFC 3986
- Prevents bypass via https://evil.com?token={{SECRET}} (no path)
- Add test cases for query-only and fragment-only env var URLs (53 total)
* fix(audit-log): try/catch for never-throw contract, accept null actorName/Email, fix misleading action
- Wrap recordAudit body in try/catch so nanoid() or header extraction can't throw
- Accept string | null for actorName and actorEmail (session.user.name can be null)
- Normalize null -> undefined before insert to match DB column types
- Fix org members route: ORG_MEMBER_ADDED -> ORG_INVITATION_CREATED (sends invite, not adds member)
* improvement(audit-log): add resource names and specific invitation actions
* fix(audit-log): use validated chat record, add mock sync tests
* fix: prevent copilot keyboard shortcuts from triggering when panel is inactive
The OptionsSelector component was capturing keyboard events (1-9 number keys and Enter)
globally on the document, causing accidental option selections when users were
interacting with other parts of the application.
This fix adds a check to only handle keyboard shortcuts when the copilot panel
is the active tab, preventing the shortcuts from interfering with other workflows.
Co-authored-by: Emir Karabeg <emir-karabeg@users.noreply.github.com>
* lint
---------
Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: Emir Karabeg <emir-karabeg@users.noreply.github.com>
Co-authored-by: Waleed Latif <walif6@gmail.com>
* feat(access-control): add ALLOWED_INTEGRATIONS env var for self-hosted block restrictions
* fix(tests): add getAllowedIntegrationsFromEnv mock to agent-handler tests
* fix(access-control): add auth to allowlist endpoint, fix loading state race, use accurate error message
* fix(access-control): remove auth from allowed-integrations endpoint to match models endpoint pattern
* fix(access-control): normalize blockType to lowercase before env allowlist check
* fix(access-control): expose merged allowedIntegrations on config to prevent bypass via direct access
* consolidate merging of allowed blocks so all callers have it by default
* normalize to lower case
* added tests
* added tests, normalize to lower case
* added safety incase userId is missing
* fix failing tests
- Changed default stickinessThreshold from 100 to 30 in use-scroll-management.ts
- Removed explicit stickinessThreshold override (40) from copilot.tsx
- Both copilot and chat now use the same default value of 30
- This makes scrolling less sticky across all copilot message interactions
Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: Emir Karabeg <emir-karabeg@users.noreply.github.com>
* fix: update i18n.lock
* feat(docs): enhance documentation with new sections on file handling, form deployment, quick reference, agent skills, and A2A integration
* fix: update i18n.lock
* feat(docs): enhance documentation with new sections on file handling, form deployment, quick reference, agent skills, and A2A integration
* refactor(tool-input): eliminate SyncWrappers, add canonical toggle and dependsOn gating
Replace 17+ individual SyncWrapper components with a single centralized
ToolSubBlockRenderer that bridges the subblock store with StoredTool.params
via synthetic store keys. This reduces ~1000 lines of duplicated wrapper
code and ensures tool-input renders subblock components identically to
the standalone SubBlock path.
- Add ToolSubBlockRenderer with bidirectional store sync
- Add basic/advanced mode toggle (ArrowLeftRight) using collaborative functions
- Add dependsOn gating via useDependsOnGate (fields disable instead of hiding)
- Add paramVisibility field to SubBlockConfig for tool-input visibility control
- Pass canonicalModeOverrides through getSubBlocksForToolInput
- Show (optional) label for non-user-only fields (LLM can inject at runtime)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix(tool-input): restore optional indicator, fix folder selector and canonical toggle, extract components
- Attach resolved paramVisibility to subblocks from getSubBlocksForToolInput
- Add labelSuffix prop to SubBlock for "(optional)" badge on user-or-llm params
- Fix folder selector missing for tools with canonicalParamId (e.g. Google Drive)
- Fix canonical toggle not clickable by letting SubBlock handle dependsOn internally
- Extract ParameterWithLabel, ToolSubBlockRenderer, ToolCredentialSelector to components/tools/
- Extract StoredTool interface to types.ts, selection helpers to utils.ts
- Remove dead code (mcpError, refreshTools, oldParamIds, initialParams)
- Strengthen typing: replace any with proper types on icon components and evaluateParameterCondition
* add sibling values to subblock context since subblock store isn't relevant in tool input, and removed unused param
* cleanup
* fix(tool-input): render uncovered tool params alongside subblocks
The SubBlock-first rendering path was hard-returning after rendering
subblocks, so tool params without matching subblocks (like inputMapping
for workflow tools) were never rendered. Now renders subblocks first,
then any remaining displayParams not covered by subblocks via the legacy
ParameterWithLabel fallback.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix(tool-input): auto-refresh workflow inputs after redeploy
After redeploying a child workflow via the stale badge, the workflow
state cache was not invalidated, so WorkflowInputMapperInput kept
showing stale input fields until page refresh. Now invalidates
workflowKeys.state on deploy success.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix(tool-input): correct workflow selector visibility and tighten (optional) spacing
- Set workflowId param to user-only in workflow_executor tool config
so "Select Workflow" no longer shows "(optional)" indicator
- Tighten (optional) label spacing with -ml-[3px] to counteract
parent Label's gap-[6px], making it feel inline with the label text
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix(tool-input): align (optional) text to baseline instead of center
Use items-baseline instead of items-center on Label flex containers
so the smaller (optional) text aligns with the label text baseline
rather than sitting slightly below it.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix(tool-input): increase top padding of expanded tool body
Bump the expanded tool body container's top padding from 8px to 12px
for more breathing room between the header bar and the first parameter.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix(tool-input): apply extra top padding only to SubBlock-first path
Revert container padding to py-[8px] (MCP tools were correct).
Wrap SubBlock-first output in a div with pt-[4px] so only registry
tools get extra breathing room from the container top.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix(tool-input): increase gap between SubBlock params for visual clarity
SubBlock's internal gap (10px between label and input) matched the
between-parameter gap (10px), making them indistinguishable. Increase
the between-parameter gap to 14px so consecutive parameters are
visually distinct, matching the separation seen in ParameterWithLabel.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix spacing and optional tag
* update styling + move predeploy checks earlier for first time deploys
* update change detection to account for synthetic tool ids
* fix remaining blocks who had files visibility set to hidden
* cleanup
* add catch
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* fix(agent): always fetch latest custom tool from DB when customToolId is present
* test(agent): use generic test data for customToolId resolution tests
* fix(agent): mock buildAuthHeaders in tests for CI compatibility
* remove inline mocks in favor of sim/testing ones
* fix(terminal): reconnect to running executions after page refresh
* fix(terminal): use ExecutionEvent type instead of any in reconnection stream
* fix(execution): type event buffer with ExecutionEvent instead of Record<string, unknown>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix(execution): validate fromEventId query param in reconnection endpoint
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* Fix some bugs
* fix(variables): fix tag dropdown and cursor alignment in variables block (#3199)
* feat(confluence): added list space labels, delete label, delete page prop (#3201)
* updated route
* ack comments
* fix(execution): reset execution state in reconnection cleanup to unblock re-entry
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix(execution): restore running entries when reconnection is interrupted by navigation
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* done
* remove cast in ioredis types
* ack PR comments
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: Siddharth Ganesan <siddharthganesan@gmail.com>
* feat(providers): add Gemini Deep Research via Interactions API
* fix(providers): hide memory UI for deep research models
* feat(providers): add multi-turn support and token logging for deep research
* fix(providers): only collect user messages as deep research input
* fix(providers): forward previousInteractionId to provider request
* fix(blocks): hide memory child fields for deep research models
* remove memory params from models that don't support it in provider requests
* update blog
* fix(execution): scope execution state per workflow to prevent cross-workflow bleed
* fix(execution): use validated workflowId param instead of non-null assertion in handleRunUntilBlock
* improvement(execution): use individual selectors to avoid unnecessary re-renders from unselectored store hook
* improvement(execution): use useShallow selector in workflow.tsx to avoid re-renders from lastRunPath/lastRunEdges changes
Adds the AgentSkillsIcon to trace spans in logs when displaying the
load_skill tool. Previously, skills appeared with a default gray color.
Now they display with the proper skill icon and a purple (#8B5CF6)
background color, consistent with the skills icon used in the settings
modal and skill input components.
Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: Emir Karabeg <emir-karabeg@users.noreply.github.com>
* improvement(preview): added trigger mode context for deploy preview
* use existing helper
* enhance disabled mode for subblocks
* update
* update all subblocks to allow scrolling in read only mode
* updated short and long input to match others, reverted triggerutils change
* fix(mcp): harden notification system against race conditions
- Guard concurrent connect() calls in connection manager with connectingServers Set
- Suppress post-disconnect notification handler firing in MCP client
- Clean up Redis event listeners in pub/sub dispose()
- Add tests for all three hardening fixes (11 new tests)
* updated tests
* plugged in new mcp event based system and create sse route to publish notifs
* ack commetns
* fix reconnect timer
* cleanup when running onClose
* fixed spacing on mcp settings tab
* keep error listeners before quiet in redis
* feat(models): updated model configs, updated anthropic provider to propagate errors back to user if any
* moved max tokens to advanced
* updated model configs and testesd
* removed default in max config for output tokens
* moved more stuff to advanced mode in the agent block
* stronger typing
* move api key under model, update mistral and groq
* update openrouter, fixed serializer to allow ollama/vllm models without api key
* removed ollama handling
* improvement(preview): nested workflow snapshots/preview when not executed
* improvements to resolve nested subblock values
* few more things
* add try catch
* fix fallback case
* deps
* fix(logs): execution files should always use our internal route
* correct degree of access control
* fix tests
* fix tag defs flag
* fix type check
* fix mcp tools
* make webhooks consistent
* fix ollama and vllm visibility
* remove dup test
* feat(icons): add Airweave icon and update registry with Airweave block and tool
* feat(icons): add Airweave icon and update icon mapping and metadata
* fix(search): update API key header from Authorization to X-API-Key for Airweave search tool
* refactor(icon-mapping): reorder icon imports for consistency and formatting improvements; update airweave block retrieval strategy description formatting; add newline at end of meta.json
* refactor(search): update visibility settings for retrieval strategy and query options to allow access for both users and LLMs
* fix(resolver): response format in deactivated branch
* add evaluator metrics too
* add child workflow id to the workflow block outputs
* cleanup typing
* fix(linear): align tool outputs, queries, and pagination with API
* fix(linear): coerce first param to number, remove duplicate conditions, add null guard
* fix(providers): correct tool calling message format across all providers
* fix(bedrock): correct timestamp char count in comment
* chore(gemini): remove dead executeToolCall function
* remove unused var
* feat(note-block): add single newline support in preview
Add remark-breaks plugin to the note block markdown renderer to convert
single newlines into line breaks. This fixes the issue where users had
to use double newlines (\n\n) to create visible line breaks in the
note block preview.
Co-authored-by: Emir Karabeg <emir-karabeg@users.noreply.github.com>
* Revert "feat(note-block): add single newline support in preview"
This reverts commit 049b42502a.
* feat(note-block): add single newline support in preview
Add a preprocessor function that converts single newlines to markdown
hard breaks (two trailing spaces + newline) before rendering. This
ensures that when users press Enter in the note block editor, the
line break shows up in the preview.
The function preserves:
- Double newlines (paragraph breaks)
- Code block formatting (fenced and inline)
Co-authored-by: Emir Karabeg <emir-karabeg@users.noreply.github.com>
* refactor(note-block): simplify comments
Co-authored-by: Emir Karabeg <emir-karabeg@users.noreply.github.com>
* added remark-breaks to allow single new line
---------
Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: Emir Karabeg <emir-karabeg@users.noreply.github.com>
Co-authored-by: waleed <walif6@gmail.com>
* feat(canvas): added the ability to lock blocks
* unlock duplicates of locked blocks
* fix(duplicate): place duplicate outside locked container
When duplicating a block that's inside a locked loop/parallel,
the duplicate is now placed outside the container since nothing
should be added to a locked container.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* fix(duplicate): unlock all blocks when duplicating workflow
- Server-side workflow duplication now sets locked: false for all blocks
- regenerateWorkflowStateIds also unlocks blocks for templates
- Client-side regenerateBlockIds already handled this (for paste/import)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* fix code block disabled state, allow unlock from editor
* fix(lock): address code review feedback
- Fix toggle enabled using first toggleable block, not first block
- Delete button now checks isParentLocked
- Lock button now has disabled state
- Editor lock icon distinguishes block vs parent lock state
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* fix(lock): prevent unlocking blocks inside locked containers
- Editor: can't unlock block if parent container is locked
- Action bar: can't unlock block if parent container is locked
- Shows "Parent container is locked" tooltip in both cases
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* fix(lock): ensure consistent behavior across all UIs
Block Menu, Editor, Action Bar now all have identical behavior:
- Enable/Disable: disabled when locked OR parent locked
- Flip Handles: disabled when locked OR parent locked
- Delete: disabled when locked OR parent locked
- Remove from Subflow: disabled when locked OR parent locked
- Lock: always available for admins
- Unlock: disabled when parent is locked (unlock parent first)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* fix(enable): consistent behavior - can't enable if parent disabled
Same pattern as lock: must enable parent container first before
enabling children inside it.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* docs(quick-reference): add lock block action
Added documentation for the lock/unlock block feature (admin only).
Note: Image placeholder added, pending actual screenshot.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* remove prefix square brackets in error notif
* add lock block image
* fix(block-menu): paste should not be disabled for locked selection
Paste creates new blocks, doesn't modify selected ones. Changed from
disableEdit (includes lock state) to !userCanEdit (permission only),
matching the Duplicate action behavior.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* refactor(workflow): extract block deletion protection into shared utility
Extract duplicated block protection logic from workflow.tsx into
a reusable filterProtectedBlocks helper in utils/block-protection-utils.ts.
This ensures consistent behavior between context menu delete and
keyboard delete operations.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* refactor(workflow): extend block protection utilities for edge protection
Add isEdgeProtected, filterUnprotectedEdges, and hasProtectedBlocks
utilities. Refactor workflow.tsx to use these helpers for:
- onEdgesChange edge removal filtering
- onConnect connection prevention
- onNodeDragStart drag prevention
- Keyboard edge deletion
- Block menu disableEdit calculation
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* fix(lock): address review comments for lock feature
1. Store batchToggleEnabled now uses continue to skip locked blocks
entirely, matching database operation behavior
2. Copilot add operation now checks if parent container is locked
before adding nested nodes (defensive check for consistency)
3. Remove unused filterUnprotectedEdges function
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* fix(copilot): add lock checks for insert and extract operations
- insert_into_subflow: Check if existing block being moved is locked
- extract_from_subflow: Check if block or parent subflow is locked
These operations now match the UI behavior where locked blocks
cannot be moved into/out of containers.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* fix(lock): prevent duplicates inside locked containers via regenerateBlockIds
1. regenerateBlockIds now checks if existing parent is locked before
keeping the block inside it. If parent is locked, the duplicate
is placed outside (parentId cleared) instead of creating an
inconsistent state.
2. Remove unnecessary effectivePermissions.canAdmin and potentialParentId
from onNodeDragStart dependency array.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* fix(lock): fix toggle locked target state and draggable check
1. BATCH_TOGGLE_LOCKED now uses first block from blocksToToggle set
instead of blockIds[0], matching BATCH_TOGGLE_ENABLED pattern.
Also added early exit if blocksToToggle is empty.
2. Blocks inside locked containers are now properly non-draggable.
Changed draggable check from !block.locked to use isBlockProtected()
which checks both block lock and parent container lock.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* fix(copilot): check parent lock in edit and delete operations
Both edit and delete operations now check if the block's parent
container is locked, not just if the block itself is locked. This
ensures consistent behavior with the UI which uses isBlockProtected
utility that checks both direct lock and parent lock.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* fix(socket): add server-side lock validation and admin-only permissions
1. BATCH_TOGGLE_LOCKED now requires admin role - non-admin users with
write role can no longer bypass UI restriction via direct socket
messages
2. BATCH_REMOVE_BLOCKS now validates lock status server-side - filters
out protected blocks (locked or inside locked parent) before deletion
3. Remove duplicate/outdated comment in regenerateBlockIds
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* test(socket): update permission test for admin-only lock toggle
batch-toggle-locked is now admin-only, so write role should be denied.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* fix(undo-redo): use consistent target state for toggle redo
The redo logic for BATCH_TOGGLE_ENABLED and BATCH_TOGGLE_LOCKED was
incorrectly computing each block's new state as !previousStates[blockId].
However, the store's batchToggleEnabled/batchToggleLocked set ALL blocks
to the SAME target state based on the first block's previous state.
Now redo computes targetState = !previousStates[firstBlockId] and applies
it to all blocks, matching the store's behavior.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* fix(socket): add comprehensive lock validation across operations
Based on audit findings, adds lock validation to multiple operations:
1. BATCH_TOGGLE_HANDLES - now skips locked/protected blocks at:
- Store layer (batchToggleHandles)
- Collaborative hook (collaborativeBatchToggleBlockHandles)
- Server socket handler
2. BATCH_ADD_BLOCKS - server now filters blocks being added to
locked parent containers
3. BATCH_UPDATE_PARENT - server now:
- Skips protected blocks (locked or inside locked container)
- Prevents moving blocks into locked containers
All validations use consistent isProtected() helper that checks both
direct lock and parent container lock.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* refactor(workflow): use pre-computed lock state from contextMenuBlocks
contextMenuBlocks already has locked and isParentLocked properties
computed in use-canvas-context-menu.ts, so there's no need to look
up blocks again via hasProtectedBlocks.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* fix(lock): add lock validation to block rename operations
Defense-in-depth: although the UI disables rename for locked blocks,
the collaborative layer and server now also validate locks.
- collaborativeUpdateBlockName: checks if block is locked or inside
locked container before attempting rename
- UPDATE_NAME server handler: checks lock status and parent lock
before performing database update
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* added defense in depth for renaming locked blocks
* fix(socket): add server-side lock validation for edges and subblocks
Defense-in-depth: adds lock checks to server-side handlers that were
previously relying only on client-side validation.
Edge operations (ADD, REMOVE, BATCH_ADD, BATCH_REMOVE):
- Check if source or target blocks are protected before modifying edges
Subblock updates:
- Check if parent block is protected before updating subblock values
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* fix(lock): fetch parent blocks for edge protection checks and consistent tooltip
- Fixed edge operations to fetch parent blocks before checking lock status
- Previously, isBlockProtected checked if parent was locked, but the parent
wasn't in blocksById because only source/target blocks were fetched
- Now fetches parent blocks for all four edge operations: ADD, REMOVE,
BATCH_ADD_EDGES, BATCH_REMOVE_EDGES
- Fixed tooltip inconsistency: changed "Run previous blocks first" to
"Run upstream blocks first" in action-bar to match workflow.tsx
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* updated tooltip text for run from block
* fix(lock): add lock check to duplicate button and clean up drag handler
- Added lock check to duplicate button in action bar to prevent
duplicating locked blocks (consistent with other edit operations)
- Removed ineffective early return in onNodeDragStart since the
`draggable` property on nodes already prevents dragging protected
blocks - the early return was misleading as it couldn't actually
stop a drag operation
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* fix(lock): use disableEdit for duplicate in block menu
Changed duplicate menu item to use disableEdit (which includes lock
check) instead of !userCanEdit for consistency with action bar and
other edit operations.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
* improvement(tag-dropdown): removeed custom styling on tag dropdown popover, fixed execution ordering in terminal and loops entries
* ack pr comments
* handle old records
* improvement(billing): improve against direct subscription creation bypasses
* more usage of block/unblock helpers
* address bugbot comments
* fail closed
* only run dup check for orgs
* fix(workflow): optimize loop/parallel regeneration and prevent duplicate agent tools
* refactor(workflow): remove addBlock in favor of batchAddBlocks
- Migrated undo-redo to use batchAddBlocks instead of addBlock loop
- Removed addBlock method from workflow store (now unused)
- Updated tests to use helper function wrapping batchAddBlocks
- This fixes the cursor bot comments about inconsistent parent checking
* fix(executor): use performance.now() for precise block timing
Replace Date.now() with performance.now() for timing measurements in
the executor to provide sub-millisecond precision. This fixes timing
discrepancies with fast-executing blocks like the start block where
millisecond precision was insufficient.
Changes:
- block-executor.ts: Use performance.now() for block execution timing
- engine.ts: Use performance.now() for overall execution timing
Co-authored-by: emir <emir@simstudio.ai>
* format ms as whole nums,round secs to 2 decimal places and compute all started/ended times on server and passback to clinet
---------
Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: waleed <walif6@gmail.com>
* improvement(docker): add internal api secret to docker compose
* remove dead code
* remove more dead code
* add api encryption key to this too
* update
* feat(tools): added calcom
* added more triggers, tested
* updated regex in script for release to be more lenient
* fix(tag-dropdown): performance improvements and scroll bug fixes
- Add flatTagIndexMap for O(1) tag lookups (replaces O(n²) findIndex calls)
- Memoize caret position calculation to avoid DOM manipulation on every render
- Use refs for inputValue/cursorPosition to keep handleTagSelect callback stable
- Change itemRefs from index-based to tag-based keys to prevent stale refs
- Fix scroll jump in nested folders by removing scroll reset from registerFolder
- Add onFolderEnter callback for scroll reset when entering folder via keyboard
- Disable keyboard navigation wrap-around at boundaries
- Simplify selection reset to single effect on flatTagList.length change
Also:
- Add safeCompare utility for timing-safe string comparison
- Refactor webhook signature validation to use safeCompare
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* updated types
* fix(calcom): simplify required field constraints for booking attendee
The condition field already restricts these to calcom_create_booking,
so simplified to required: true. Per Cal.com API docs, email is optional
while name and timeZone are required.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* added tests
* updated folder multi select, updated calcom and github tools and docs generator script
* updated drag, updated outputs for tools, regen docs with nested docs script
* updated setup instructions links, destructure trigger outputs, fix text subblock styling
* updated docs gen script
* updated docs script
* updated docs script
* updated script
* remove destructuring of stripe webhook
* expanded wand textarea, updated calcom tools
---------
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
Next.js rewrites can strip request bodies for large payloads (1MB+),
causing 400 errors from CloudFront. PostHog session recordings require
up to 64MB per message. Moving the proxy to middleware ensures proper
body passthrough.
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
* feat(preview): add workflow context badge for nested navigation
Adds a badge next to the Back button when viewing nested workflows
to help users identify which workflow they are currently viewing.
This is especially helpful when navigating deeply into nested
workflow blocks.
Changes:
- Added workflowName field to WorkflowStackEntry interface
- Capture workflow name from metadata when drilling down
- Display workflow name badge next to Back button
Co-authored-by: emir <emir@simstudio.ai>
* added workflow name and desc to metadata for workflow preview
* added copy and search icon in code in preview editor
---------
Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: waleed <walif6@gmail.com>
* feat(timeout): add timeout subblock to the api block
* fix(timeout): honor timeout config for internal routes and fix type coercion
- Add AbortController support for internal routes (/api/*) to honor timeout
- Fix type coercion: convert string timeout from short-input to number
- Handle NaN gracefully by falling back to undefined (default timeout)
Fixes#2786Fixes#2242
* fix: remove redundant clearTimeout in catch block
* fix: validate timeout is positive number
Negative timeout values would cause immediate request abort since
JavaScript treats negative setTimeout delays as 0.
* update docs image, update search modal performance
* removed unused keywords type
* ack comments
* cleanup
* fix: add default timeout for internal routes and validate finite timeout
- Internal routes now use same 5-minute default as external routes
- Added Number.isFinite() check to reject Infinity values
* fix: enforce max timeout and improve error message consistency
- Clamp timeout to max 600000ms (10 minutes) as documented
- External routes now report timeout value in error message
* remove unused code
* fix(child-workflow): must bypass hiddenFromDisplay config
* fix passing of spans to be in block log
* keep fallback for backwards compat
* fix error message formatting
* clean up
* fix(workflow): update container dimensions on keyboard movement
* fix(workflow): avoid duplicate container updates during drag
Add !change.dragging check to only handle keyboard movements in
onNodesChange, since mouse drags are already handled by onNodeDrag.
* fix(workflow): persist keyboard movements to backend
Keyboard arrow key movements now call collaborativeBatchUpdatePositions
to sync position changes to the backend for persistence and real-time
collaboration.
* improvement(cmdk): refactor search modal to use cmdk + fix icon SVG IDs (#3044)
* improvement(cmdk): refactor search modal to use cmdk + fix icon SVG IDs
* chore: remove unrelated workflow.tsx changes
* chore: remove comments
* chore: add devtools middleware to search modal store
* fix: allow search data re-initialization when permissions change
* fix: include keywords in search filter + show service name in tool operations
* fix: correct filterBlocks type signature
* fix: move generic to function parameter position
* fix(mcp): correct event handler type for onInput
* perf: always render command palette for instant opening
* fix: clear search input when modal reopens
* fix(helm): move rotationPolicy under privateKey for cert-manager compatibility (#3046)
* fix(helm): move rotationPolicy under privateKey for cert-manager compatibility
* docs(helm): add reclaimPolicy Retain guidance for production database storage
* fix(helm): prevent empty branding ConfigMap creation
* fix(workflow): avoid duplicate position updates on drag end
Check isInDragOperation before persisting in onNodesChange to prevent
duplicate calls. Drag-end events have dragStartPosition still set,
while keyboard movements don't, allowing proper distinction.
* Fix
* Cleanup
* order of ops for validations
* only reachable subflow nodes should hit validation
---------
Co-authored-by: Vikhyath Mondreti <vikhyath@simstudio.ai>
* improvement(cmdk): refactor search modal to use cmdk + fix icon SVG IDs
* chore: remove unrelated workflow.tsx changes
* chore: remove comments
* chore: add devtools middleware to search modal store
* fix: allow search data re-initialization when permissions change
* fix: include keywords in search filter + show service name in tool operations
* fix: correct filterBlocks type signature
* fix: move generic to function parameter position
* fix(mcp): correct event handler type for onInput
* perf: always render command palette for instant opening
* fix: clear search input when modal reopens
* fix(security): add authentication to tool API routes
* fix(drive): use checkSessionOrInternalAuth to allow browser access
* fix(selectors): use checkSessionOrInternalAuth for UI-accessible routes
* feat(note-block): expand media embed support with tuned aspect ratios
* fix(note-block): add artist parameter to Bandcamp embed URLs
Include the artist subdomain in Bandcamp track and album embed URLs
to ensure proper embed resolution.
* fix(note-block): add required src attribute to track elements
HTML spec requires track elements to have a src attribute.
* fix(note-block): address embed URL matching issues
- Fix YouTube regex to handle v= anywhere in query params
- Fix Twitch channel match to exclude /clip/ URLs
- Remove Mux support (HLS not supported in most browsers)
- Remove Bandcamp support (requires numeric IDs, not slugs)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
* fix(docs): separate local and blob asset resolution for quick-reference
ActionImage now uses local paths directly for PNGs while ActionVideo
uses blob storage with proper path normalization (strips static/ prefix).
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* refactor(docs): simplify asset resolution by using correct paths directly
Remove path normalization logic from action-media component. Instead,
use the appropriate paths in MDX:
- PNGs: /static/quick-reference/... (local)
- MP4s: quick-reference/... (blob via getAssetUrl)
---------
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
* fix(docs): update requirements to be more accurate for deploying the app
* updated kb to support 1536 dimension vectors for models other than text embedding 3 small
* fix(storage): support Azure connection string for presigned URLs
* fix(kb): update test for embedding dimensions parameter
* fix(storage): align credential source ordering for consistency
* docs(sdk): update README to reflect new interface
* improvement(docs): add quick reference page and update SDK documentation
* docs(copilot): update copilot documentation with all features
* fix(anthropic): use anthropic sdk to transform malformed response schemas to anthropic format
* copy internal transformJSONSchema from anthropic
* remove dep update
* use built-in func from anthropic
* fix(security): restrict API key access on internal-only routes
* test(security): update function execute tests for checkInternalAuth
* updated agent handler
* move session check higher in checkSessionOrInternalAuth
* extracted duplicate code into helper for resolving user from jwt
* improvement(helm): add internal ingress support and same-host path consolidation
* improvement(helm): clean up ingress template comments
Simplify verbose inline Helm comments and section dividers to match the
minimal style used in services.yaml.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* fix(helm): add missing copilot path consolidation for realtime host
When copilot.host equals realtime.host but differs from app.host,
copilot paths were not being routed. Added logic to consolidate
copilot paths into the realtime rule for this scenario.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* improvement(helm): follow ingress best practices
- Remove orphan comments that appeared when services were disabled
- Add documentation about path ordering requirements
- Paths rendered in order: realtime, copilot, app (specific before catch-all)
- Clean template output matching industry Helm chart standards
---------
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
* feat(admin): add credits endpoint to issue credits to users
* fix(admin): use existing credit functions and handle enterprise seats
* fix(admin): reject NaN and Infinity in amount validation
* styling
* fix(admin): validate userId and email are strings
* feat(blog): v0.5 post
* improvement(blog): simplify title and remove code block header
- Simplified blog title from "Introducing Sim Studio v0.5" to "Introducing Sim v0.5"
- Removed language label header and copy button from code blocks for cleaner appearance
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* ack PR comments
* small styling improvements
* created system to create post-specific components
* updated componnet
* cache invalidation
---------
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
* fix(custom-tools): remove unsafe title fallback in getCustomTool
* fix(custom-tools): restore title fallback in getCustomTool lookup
Custom tools are referenced by title (custom_${title}), not database ID.
The title fallback is required for client-side tool resolution to work.
- Refactor auth forms to use BrandedButton component
- Add BrandedLink component for changelog page
- Reduce code duplication in login, signup, reset-password forms
- Update star count default value
* fix(auth): improve reset password flow and consolidate brand detection
* fix(auth): set errorHandled for EMAIL_NOT_VERIFIED to prevent duplicate error
* fix(auth): clear success message on login errors
* chore(auth): fix import order per lint
* feat(tools): added textract
* cleanup
* ack pr comments
* reorder
* removed upload for textract async version
* fix additional fields dropdown in editor, update parser to leave validation to be done on the server
* added mistral v2, files v2, and finalized textract
* updated the rest of the old file patterns, updated mistral outputs for v2
* updated tag dropdown to parse non-operation fields as well
* updated extension finder
* cleanup
* added description for inputs to workflow
* use helper for internal route check
* fix tag dropdown merge conflict change
* remove duplicate code
---------
Co-authored-by: Vikhyath Mondreti <vikhyath@simstudio.ai>
* fix(kb): align bulk chunk operation with API response
* fix(kb): skip local state update for failed chunks
* fix(kb): correct errors type and refresh on partial failure
* improvement(modal): fixed popover issue in custom tools modal, removed the ability to update if no changes made
* improvement(modal): fixed popover issue in custom tools modal, removed the ability to update if no changes made
* popover fixes, color picker keyboard nav, code simplification
* color standardization
* fix color picker
* set discard alert state when closing modal
* improvement(kb): migrate manual fetches in kb module to use reactquery
* converted remaining manual kb fetches
* unwrap kb tags before API call, added more query invalidation for chunks
* added resetMutation calls after modal closes
* fix(verbiage): more explicit verbiage on some dialog menus, google drive updates, advanved to additional fields, remove general settings store sync in favor of tanstack
* updated docs
* nested tag dropdown, more well-defined nested outputs, keyboard nav for context menus, etc
* cleanup
* allow cannonical toggle even if depends on not satisfied
* remove smooth scroll in tag drop
* fix selection
* fix
---------
Co-authored-by: Vikhyath Mondreti <vikhyath@simstudio.ai>
* improvement(tools): added visibility for tools that were missing it, added new google tools
* fixed the name for google forms
* revert schema enrichers change
* fixed block ordering
* improvement(deployed-mcp): added the ability to make the visibility for deployed mcp tools public, updated UX
* use reactquery
* migrated chats to use reactquery, upgraded entire deploymodal to use reactquery instead of manual state management
* added hooks for chat chats and updated callers to all use reactquery
* fix
* updated comments
* consolidated utils
* fix(webflow): fix collection & site dropdown in webflow triggers
* added form submission trigger to webflow
* fix(webflow): added form submission trigger and scope
* fixed function signatures
* improvement(presence): show presence for the same user in another tab, fix z-index of multiplayer cursor to fall behind panel,terminal,sidebar but above blocks, improved connection detection
* upsert users into presence list
* improvement(permissions): added ability to auto-add new org members to existing permission group, disallow disabling of start block
* ran migrations
* add deploy modal tabs config to perm groups
* fix ordering of access control listings
* prep staging merge
* regen migrations
---------
Co-authored-by: Vikhyath Mondreti <vikhyath@simstudio.ai>
* feat(workflow-controls): added action bar for picker/hand/undo/redo/zoom workflow controls, added general setting to disable
* added util for fit to zoom that accounts for sidebar, terminal, and panel
* ack PR comments
* remove dead state variable, add logs
* improvement(ui/ux): action bar, panel, tooltip, dragging, invite modal
* added fit to view in canvas context menu
* fix(theme): dark mode flash
* fix: duplicate fit to view
* refactor: popovers; improvement: notifications, diff controls, action bar
* improvement(action-bar): ui/ux
* refactor(action-bar): renamed to workflow controls
* ran migrations
* fix: deleted migration
---------
Co-authored-by: Emir Karabeg <emirkarabeg@berkeley.edu>
* added back trace spans to notifications
* fixed double verification code
* fix dashboard
* updated welcome email
* added link to cal for team
* update dashboard stats route
* added react grab URL to CSP if FF is enabled, removed dead db hook
* fix failing test
* ensure MCP add server tool is centered
* updated A2A copy button and MCP location, and default description matching
* updated button on chat page
* added vite version override
* fix
* fix(agent-tools): added special handling for workflow tool in agent tool input, added react grab
* FF react grab
* ack comments
* updated to account for workflow input tool on top of just workflow as well
* fix(triggers): package lemlist data, cleanup trigger outputs formatting, fix display name issues
* cleanup trigger outputs
* fix tests
* more test fixes
* remove branch field for ones where it's not relevant
* remove branch from unrelated ops
* fix)comparison): add condition to prevent duplicate identical edges, ignore from workflow change detection
* fix failing test
* added back store check
* feat(tool): added introspection tools for all db integrations
* added sanitization for sql schema
* ack pr comments, with clarifying comments
* moved util
* feat(tools): added workflow tools to agent tools dropdown for discoverability, enforce perms on client for redeploying via the agent
* added perms enforcement to workflow block header as well
* improvement(response): only allow singleton
* respect singleton triggers and blocks in copilot
* don't show dup button for response
* fix error message
* feat(permission-groups): integration/model access controls for enterprise
* feat: enterprise gating for BYOK, SSO, credential sets with org admin/owner checks
* execution time enforcement of mcp and custom tools
* add admin routes to cleanup permission group data
* fix not being on enterprise checks
* separate out orgs from billing system
* update the docs
* add custom tool blockers based on perm configs
* add migrations
* fix
* address greptile comments
* regen migrations
* fix default model picking based on user config
* cleaned up UI
* feat(sidebar): context menu for nav items in sidebar
* added toolbar context menu, fixed incorrect access pattern in old context menus and added docs for missing blocks
* fixed links
* fix(tools): fixed wrokflow tool for agent to respect user provided params, inject at runtime like all other tools
* ack comments
* remove redunant if-else
* added tests
* improvement(billng): team upgrade + session management
* remove comments
* session updates should be atomic
* make consistent for onSubscritionUpdate
* plan upgrade to refresh session
* fix var name
* remove dead code
* preserve params
* progress on cred sets
* fix credential set system
* return data to render credential set in block preview
* progress
* invite flow
* simplify code
* fix ui
* fix tests
* fix types
* fix
* fix icon for outlook
* fix cred set name not showing up for owner
* fix rendering of credential set name
* fix outlook well known folder id resolution
* fix perms for creating cred set
* add to docs and simplify ui
* consolidate webhook code better
* fix tests
* fix credential collab logic issue
* fix ui
* fix lint
* feat(fireflies): added fireflies tools and trigger
* finished fireflies
* added wandConfig to all timestamp subblocks on the platform
* added current time to timestamp wand generation
* fix file upload subblock styling, tested all fireflies ops
* removed dropdown for trigger for fireflies
* updated docs
* added fireflies to formatWebhookInput
* added more wandConfigs
* feat(time-picker): added timepicker emcn component, added to playground, added searchable prop for dropdown, added more timezones for schedule, updated license and notice date
* removed unused params, cleaned up redundant utils
* fix(parallel): add parallel sentinel to make parallel-parallel and parallel-loop work correctly
* fix regular -> parallel + copilot nested subflows
* add tests
* consolidate to always explode parallel dag at runtime
* improvement(schedules): use tanstack query to fetch schedule data, cleanup ui on schedule info component
* update trigger-save UI, increase auto disable to 100 consecutive from 10
* updated docs
* consolidate consts
* improvement(variables): update workflows to use deployed variables, not local ones to align with the rest of the canvas components
* update change detection to ignore trigger id since it is runtime metadata and not actually required to be redeployed
* improvement(logs): state machine of workflow execution
* cleanup more code
* fallback consistency
* fix labels
* backfill in migration correctly
* make streaming stop in chat window correctly
* improvement(usage-limit): update usage in real time, fix token output object
* updated tokenBreakdown to tokens, standardized input/output/total token object type across providers
* update remaining references
* ack PR comment
* remove singleton query client instance from hooks, leave only in zustand
* fixed logs for parallel and loop execution flow
* Fix array check for collection
* fixed for empty loop and paralle blocks and showing input on dashboard
* extracted utility functions
* fixed the refrencing errors and making sure it propogates to the console
* fix parallel
* fix tests'
---------
Co-authored-by: priyanshu.solanki <priyanshu.solanki@saviynt.com>
Co-authored-by: Siddharth Ganesan <siddharthganesan@gmail.com>
Co-authored-by: Vikhyath Mondreti <vikhyath@simstudio.ai>
* fix(search): removed full text param from built-in search, anthropic provider streaming fix
* rewrite gemini provider with official sdk + add thinking capability
* vertex gemini consolidation
* never silently use different model
* pass oauth client through the googleAuthOptions param directly
* make server side provider registry
* remove comments
* take oauth selector below model selector
---------
Co-authored-by: Vikhyath Mondreti <vikhyath@simstudio.ai>
Reddit API requires User-Agent header for all requests including OAuth
token refresh. Without it, requests fail with 403 error after the
initial token expires.
Fixes#1822
* improvement(pricing): increase free user limit to 20 usd
* make gemini pricing accurate
* generate migration for db constant
* update docs
* test notif data
* fix(vars): add socket persistence when variable names are changed, update variable name normalization to match block name normalization, added space constraint on envvar names
* removed redundant queueing, removed unused immediate flag from sockets ops
* ack PR comments
* creating boolean, number and date tags with different equality matchings
* feat: add UI for tag field types with filter operators
- Update base-tags-modal with field type selector dropdown
- Update document-tags-modal with different input types per fieldType
- Update knowledge-tag-filters with operator dropdown and type-specific inputs
- Update search routes to support all tag slot types
- Update hook to use AllTagSlot type
* feat: add field type support to document-tag-entry component
- Add dropdown with all field types (Text, Number, Date, Boolean)
- Render different value inputs based on field type
- Update slot counting to include all field types (28 total)
* fix: resolve MAX_TAG_SLOTS error and z-index dropdown issue
- Replace MAX_TAG_SLOTS with totalSlots in document-tag-entry
- Add z-index to SelectContent in base-tags-modal for proper layering
* fix: handle non-text columns in getTagUsage query
- Only apply empty string check for text columns (tag1-tag7)
- Numeric/date/boolean columns only check IS NOT NULL
- Cast values to text for consistent output
* refactor: use EMCN components for KB UI
- Replace @/components/ui imports with @/components/emcn
- Use Combobox instead of Select for dropdowns
- Use EMCN Switch, Button, Input, Label components
- Remove unsupported 'size' prop from EMCN Button
* fix: layout for delete button next to date picker
- Change delete button from absolute to inline positioning
- Add proper column width (w-10) for delete button
- Add empty header cell for delete column
- Apply fix to both document-tag-entry and knowledge-tag-filters
* fix: clear value when switching tag field type
- Reset value to empty when changing type (e.g., boolean to text)
- Reset value when tag name changes and type differs
- Prevents 'true'/'false' from sticking in text inputs
* feat: add full support for number/date/boolean tag filtering in KB search
- Copy all tag types (number, date, boolean) from document to embedding records
- Update processDocumentTags to handle all field types with proper type conversion
- Add number/date/boolean columns to document queries in checkDocumentWriteAccess
- Update chunk creation to inherit all tag types from parent document
- Add getSearchResultFields helper for consistent query result selection
- Support structured filters with operators (eq, gt, lt, between, etc.)
- Fix search queries to include all 28 tag fields in results
* fixing tags import issue
* fix rm file
* reduced number to 3 and date to 2
* fixing lint
* fixed the prop size issue
* increased number from 3 to 5 and boolean from 7 to 2
* fixed number the sql stuff
* progress
* fix document tag and kb tag modals
* update datepicker emcn component
* fix ui
* progress on KB block tags UI
* fix issues with date filters
* fix execution parsing of types for KB tags
* remove migration before merge
* regen migrations
* fix tests and types
* address greptile comments
* fix more greptile comments
* fix filtering logic for multiple of same row
* fix tests
---------
Co-authored-by: priyanshu.solanki <priyanshu.solanki@saviynt.com>
Co-authored-by: Vikhyath Mondreti <vikhyath@simstudio.ai>
The realtime service network policy was missing the custom egress rules section
that allows configuration of additional egress rules via values.yaml. This caused
the realtime pods to be unable to connect to external databases (e.g., PostgreSQL
on port 5432) when using external database configurations.
The app network policy already had this section, but the realtime network policy
was missing it, creating an inconsistency and preventing the realtime service
from accessing external databases configured via networkPolicy.egress values.
This fix adds the same custom egress rules template section to the realtime
network policy, matching the app network policy behavior and allowing users to
configure database connectivity via values.yaml.
* fix(subflow): prevent auto-connect across subflow edges with keyboard shortcut block additions, make positioning for auto-drop smarter
* stronger typing
* fix(autofill): add dummy inputs to prevent browser autofill for various fields, prevent having 0 workflows in workspace
* cleanup
* ack PR comments
* fix failing test
* feat(og): add opengraph images for templates, blogs, and updated existing opengraph image for all other pages
* added to workspace templates page as well
* ack PR comments
* fix(oauth): updated oauth providers that had unstable reference IDs leading to duplicate oauth records (#2441)
* fix(oauth): updated oauth providers that had unstable reference IDs leading to duplicate oauth records
* ack PR comments
* ack PR comments
* cleanup salesforce refresh logic
* ack more PR comments
* feat(compare-schema): ci check to make sure schema.ts never goes out of sync with migrations
* test out of sync [do not merge]
* Revert "test out of sync [do not merge]"
This reverts commit 9771f66b84.
* fix(condition): used isolated vms for condition block RCE
* ack PR comment
* one more
* remove inputForm from sched, update loop condition to also use isolated vm
* hide servicenow
* feat(vertex): added vertex to list of supported providers
* added utils files for each provider, consolidated gemini utils, added dynamic verbosity and reasoning fetcher
* feat(service-now): added service now block
* fix: bun lock
* improvement: fixed @trigger.dev/sdk imports and removal of sentry blocks
* improvement: fixed @trigger.dev/sdk import
* improvement: fixed @trigger.dev/sdk import
* fix(servicenow): save accessTokenExpiresAt on initial OAuth account creation
* docs(servicenow): add ServiceNow tool documentation and icon mapping
* fixing bun lint issues
* fixing username/password fields
* fixing test file for refreshaccesstoken to support instance uri
* removing basic auth and fixing undo-redo/store.ts
* removed import set api code, changed CRUD operations to CRUD_record and added wand configuration to help users to generate JSON Arrays
---------
Co-authored-by: priyanshu.solanki <priyanshu.solanki@saviynt.com>
* make creator profile required
* fix grafana tag dropdown / outputs mismatch
* fix grafana annotations to make dashboard id required
* fix fal ai
* fix fal ai
* fix zep
* fix(tools): fix perplexity & parallel ai tag dropdown inaccuracies
* fixed stt, tts and added output conditions to conditionally display tag dropdown values based on other subblock values
* updated exa to match latest API
* feat(folders): add the ability to create a folder within a folder in popover (#2287)
* fix(agent): filter out empty params to ensure LLM can set tool params at runtime (#2288)
* fix(mcp): added backfill effect to add missing descriptions for mcp tools (#2290)
* fix(redis): cleanup access pattern across callsites (#2289)
* fix(redis): cleanup access pattern across callsites
* swap redis command to be non blocking
* improvement(log-details): polling, trace spans (#2292)
---------
Co-authored-by: Vikhyath Mondreti <vikhyathvikku@gmail.com>
Co-authored-by: Emir Karabeg <78010029+emir-karabeg@users.noreply.github.com>
* fix(custom-bot-slack): dependsOn incorrectly set for bot_token"
* fix other references to be compatible
* fix dependsOn for things depending on authMethod"
* feat(tools): added rds tools/block
* feat(tools): added rds, dynamodb, background color gradient
* changed conditions for WHERE condition to be json conditions instead of raw string
* fix(team-plans): track departed member usage so value not lost
* reset usage to 0 when they leave team
* prep merge with stagig
* regen migrations
* fix org invite + ws selection'
---------
Co-authored-by: Waleed <walif6@gmail.com>
* feat(agent): added workflow, kb, and function as a tool for agent block
* fix keyboard nav and keyboard selection in tool-inp
* ack PR comments
* remove custom tool changes
* fixed kb tools for agent
* cleanup
* feat(tools): added speech to text with openai whisper, elevenlabs, and deepgram
* added new file icons, implemented ffmpeg
* updated docs
* revert environment
* added blacksmith optimizations to workflows and dockerfiles to enhance performance. please review before pushing to production
* remove cache from and cache to directives from docker based actions, per blacksmith docs
---------
Co-authored-by: Connor Mulholland <connormul@Connors-MacBook-Pro.local>
* fix(subflows): add loops/parallels to accessible list of blocks in the tag dropdown when contained withitn a subflow
* remove currentIteration in loop
* improvement(docs): remove copy page from mobile view on docs
* bring title and pagenav lower on mobile
* added cursor pointer to clickable components in docs
* fix(triggers): dedup + not surfacing deployment status log
* fix ms teams
* change to microsoftteams
* Revert "change to microsoftteams"
This reverts commit 217f808641.
* fix
* fix
* fix provider name
* fix oauth for msteams
* feat(billing): add notif for first failed payment, added upgrade email from free, updated providers that supported granular tool control to support them, fixed envvar popover, fixed redirect to wrong workspace after oauth connect
* fix build
* ack PR comments
* fix(custom-tools): updates to existing tools
* don't reorder custom tools in modal based on edit time
* restructure custom tools to persist copilot generated tools
* fix tests
* fix(templates): view current ui
* update UI to be less cluttered
* make state management for creating user profile smoother
* fix autoselect logic
* fix lint
* improvement(docs): added new platform ss
* rename approval to human in the loop
* cleanup
* remove yml
* removed other languages large sections
* fix icons
* Add helm for copilot
* Remove otel and log level
* Change repo name
* improvement(helm): enhance copilot chart with HA support and validation
* refactor(helm): consolidate copilot secrets and fix postgres volume mount
* feat(tools): added 10 new github triggers
* feat(tools): added 48 new github tools, 12 triggers
* fix(logging): make logging safe start an upsert to prevent insertions of duplicate execution id records, remove layout from github block
* feat(schedules): move schedule configuration out of modals into subblocks
* added more timezones
* added simple in-memory rate limiting to update schedule, validation on numeric values for date and time, fix update schedule behavior
* fix failing tests, ack PR comments
* surface better errors
* improvement(variables): add error context for duplicate variable names, only check for collision when focus is lost
* disallow empty variable names, performance optimizations
* safety guard against empty variables names
* feat(triggers): make triggers use existing subblock system, need to still fix webhook URL on multiselect and add script in text subblock for google form
* minimize added subblocks, cleanup code, make triggers first-class subblock users
* remove multi select dropdown and add props to existing dropdown instead
* cleanup dropdown
* add socket op to delete external webhook connections on block delete
* establish external webhook before creating webhook DB record, surface better errors for ones that require external connections
* fix copy button in short-input
* revert environment.ts, cleanup
* add triggers registry, update copilot tool to reflect new trigger setup
* update trigger-save subblock
* clean
* cleanup
* remove unused subblock store op, update search modal to reflect list of triggers
* add init from workflow to subblock store to populate new subblock format from old triggers
* fix mapping of old names to new ones
* added debug logging
* remove all extraneous debug logging and added mapping for triggerConfig field names that were changed
* fix trigger config for triggers w/ multiple triggers
* edge cases for effectiveTriggerId
* cleaned up
* fix dropdown multiselect
* fix multiselect
* updated short-input copy button
* duplicate blocks in trigger mode
* ack PR comments
* feat(cost): added hidden cost breakdown component to settings > subscription, start collecting current period copilot cost and last period copilot cost
* don't rerender envvars when switching between workflows in the same workspace
* feat(envvars): use cache for envvar dropdown key names, prevent autofill & suggestions in the settings
* add the same prevention for autocomplete and suggestions to sso and webhook
* fix(kb): fix mistral parse and kb uploads, include userId in internal auth
* update updated_at for kb when adding a new doc via knowledge block
* update tests
* Add variables block
* Add wait block
* While loop v1
* While loop v1
* Do while loops
* Copilot user input rerender fix
* Fix while and dowhile
* Vars block dropdown
* While loop docs
* Remove vars block coloring
* Fix lint
* Link docs to wait
* Fix build fail
* remove extraneous text from careers app
* feat(kb): added sort order to kb
* updated styles of workspace selector and delete button to match theme of rest of knowledgebase
* added google forms scope and google drive scope
* added back file scope
---------
Co-authored-by: Adam Gough <adamgough@Mac.attlocal.net>
Co-authored-by: Adam Gough <adamgough@Mac-530.lan>
* fix(dashboard): add additional context for paginated logs in dashboard, add empty state when selected cell has no data
* apps/sim
* renaming
* remove relative import
* feat(supabase): added vector search tool and updated docs
* exclude generic webhook from docs gen
* change items to pages in meta.json for tools directory in the docs
* feat(webhooks): added optioanl input format to webhooks, added support for file uploads
* feat(webhooks): added input format component to generic webhook trigger, added file support
* consolidated execution files utils, extended presigned URL duration for async tasks
* fix(input-format): allow value field to be cleared
* don't let value field be detected as deployment change
* fix zep icon in docs
* exclude collapsed state
* improvement(response-copilot): make it use builder mode over editor mode to prevent json formatting issues
* change placeholder text
* fix conversion between builder and editor mode
* fix(chat-subs): always use next public app url env
* use getBaseUrl everywhere
* move remaining uses
* fix test
* change auth.ts and make getBaseUrl() call not top level for emails
* change remaining uses
* revert csp
* cleanup
* fix
* feat(mistal): added mistral as a provider, updated model prices
* remove the ability for a block to reference its own outluts
* fixed order of responses for guardrails block
* fix(webhooks): use next public app url instead of request origin for webhook registration
* ack PR comments
* ci: pin Bun to v1.2.22 to avoid Bun 1.3 breaking changes
* feat(deployed-chat): updated chat panel UI, deployed chat and API can now accept files
* added nested tag dropdown for files
* added duplicate file validation to chat panel
* update docs & SDKs
* fixed build
* rm extraneous comments
* ack PR comments, cut multiple DB roundtrips for permissions & api key checks in api/workflows
* allow read-only users to access deployment info, but not take actions
* add downloadable file to logs for files passed in via API
* protect files/serve route that is only used client-side
---------
Co-authored-by: waleed <waleed>
* feat(billing): bill by threshold to prevent cancellation edge case
* fix org billing
* fix idempotency key issue
* small optimization for team checks
* remove console log
* remove unused type
* fix error handling
description: Create a block configuration for a Sim integration with proper subBlocks, conditions, and tool wiring
argument-hint: <service-name>
---
# Add Block Skill
You are an expert at creating block configurations for Sim. You understand the serializer, subBlock types, conditions, dependsOn, modes, and all UI patterns.
## Your Task
When the user asks you to create a block:
1. Create the block file in `apps/sim/blocks/blocks/{service}.ts`
2. Configure all subBlocks with proper types, conditions, and dependencies
serviceId:'{service}',// Must match OAuth provider service key
requiredScopes: getScopesForService('{service}'),// Import from @/lib/oauth/utils
placeholder:'Select account',
required: true,
}
```
**Scopes:** Always use `getScopesForService(serviceId)` from `@/lib/oauth/utils` for `requiredScopes`. Never hardcode scope arrays — the single source of truth is `OAUTH_PROVIDERS` in `lib/oauth/oauth.ts`.
**Scope descriptions:** When adding a new OAuth provider, also add human-readable descriptions for all scopes in `SCOPE_DESCRIPTIONS` within `lib/oauth/utils.ts`.
-`'json-object'` - Raw JSON (adds "no markdown" instruction)
-`'json-schema'` - JSON Schema definitions
-`'sql-query'` - SQL statements
-`'timestamp'` - Adds current date/time context
## Tools Configuration
**Important:**`tools.config.tool` runs during serialization before variable resolution. Put `Number()` and other type coercions in `tools.config.params` instead, which runs at execution time after variables are resolved.
**Preferred:** Use tool names directly as dropdown option IDs to avoid switch cases:
When using `type: 'json'` and you know the object shape in advance, **describe the inner fields in the description** so downstream blocks know what properties are available. For well-known, stable objects, use nested output definitions instead:
```typescript
outputs:{
// BAD: Opaque json with no info about what's inside
plan:{type:'json',description:'Zone plan information'},
// GOOD: Describe the known fields in the description
plan:{
type:'json',
description:'Zone plan information (id, name, price, currency, frequency, is_subscribed)',
},
// BEST: Use nested output definition when the shape is stable and well-known
See the `/add-trigger` skill for creating triggers.
## Icon Requirement
If the icon doesn't already exist in `@/components/icons.tsx`, **do NOT search for it yourself**. After completing the block, ask the user to provide the SVG:
```
The block is complete, but I need an icon for {Service}.
Please provide the SVG and I'll convert it to a React component.
You can usually find this in the service's brand/press kit page, or copy it from their website.
```
## Advanced Mode for Optional Fields
Optional fields that are rarely used should be set to `mode: 'advanced'` so they don't clutter the basic UI. This includes:
mode:'advanced',// Rarely used, hide from basic view
}
```
## WandConfig for Complex Inputs
Use `wandConfig` for fields that are hard to fill out manually, such as timestamps, comma-separated lists, and complex query strings. This gives users an AI-assisted input experience.
```typescript
// Timestamps - use generationType: 'timestamp' to inject current date context
{
id:'startTime',
title:'Start Time',
type:'short-input',
mode:'advanced',
wandConfig:{
enabled: true,
prompt:'Generate an ISO 8601 timestamp based on the user description. Return ONLY the timestamp string.',
generationType:'timestamp',
},
}
// Comma-separated lists - simple prompt without generationType
{
id:'mediaIds',
title:'Media IDs',
type:'short-input',
mode:'advanced',
wandConfig:{
enabled: true,
prompt:'Generate a comma-separated list of media IDs. Return ONLY the comma-separated values.',
},
}
```
## Naming Convention
All tool IDs referenced in `tools.access` and returned by `tools.config.tool` MUST use `snake_case` (e.g., `x_create_tweet`, `slack_send_message`). Never use camelCase or PascalCase.
## Checklist Before Finishing
- [ ] All subBlocks have `id`, `title` (except switch), and `type`
description: Add a knowledge base connector for syncing documents from an external source
argument-hint: <service-name> [api-docs-url]
---
# Add Connector Skill
You are an expert at adding knowledge base connectors to Sim. A connector syncs documents from an external source (Confluence, Google Drive, Notion, etc.) into a knowledge base.
## Your Task
When the user asks you to create a connector:
1. Use Context7 or WebFetch to read the service's API documentation
2. Determine the auth mode: **OAuth** (if Sim already has an OAuth provider for the service) or **API key** (if the service uses API key / Bearer token auth)
3. Create the connector directory and config
4. Register it in the connector registry
## Directory Structure
Create files in `apps/sim/connectors/{service}/`:
```
connectors/{service}/
├── index.ts # Barrel export
└── {service}.ts # ConnectorConfig definition
```
## Authentication
Connectors use a discriminated union for auth config (`ConnectorAuthConfig` in `connectors/types.ts`):
For services with existing OAuth providers in `apps/sim/lib/oauth/types.ts`. The `provider` must match an `OAuthService`. The modal shows a credential picker and handles token refresh automatically.
### API key mode
For services that use API key / Bearer token auth. The modal shows a password input with the configured `label` and `placeholder`. The API key is encrypted at rest using AES-256-GCM and stored in a dedicated `encryptedApiKey` column on the connector record. The sync engine decrypts it automatically — connectors receive the raw access token in `listDocuments`, `getDocument`, and `validateConfig`.
The add-connector modal renders these automatically — no custom UI needed.
Three field types are supported: `short-input`, `dropdown`, and `selector`.
```typescript
// Text input
{
id:'domain',
title:'Domain',
type:'short-input',
placeholder:'yoursite.example.com',
required: true,
}
// Dropdown (static options)
{
id:'contentType',
title:'Content Type',
type:'dropdown',
required: false,
options:[
{label:'Pages only',id:'page'},
{label:'Blog posts only',id:'blogpost'},
{label:'All content',id:'all'},
],
}
```
## Dynamic Selectors (Canonical Pairs)
Use `type: 'selector'` to fetch options dynamically from the existing selector registry (`hooks/selectors/registry.ts`). Selectors are always paired with a manual fallback input using the **canonical pair** pattern — a `selector` field (basic mode) and a `short-input` field (advanced mode) linked by `canonicalParamId`.
The user sees a toggle button (ArrowLeftRight) to switch between the selector dropdown and manual text input. On submit, the modal resolves each canonical pair to the active mode's value, keyed by `canonicalParamId`.
### Rules
1.**Every selector field MUST have a canonical pair** — a corresponding `short-input` (or `dropdown`) field with the same `canonicalParamId` and `mode: 'advanced'`.
2.**`required` must be set identically on both fields** in a pair. If the selector is required, the manual input must also be required.
3.**`canonicalParamId` must match the key the connector expects in `sourceConfig`** (e.g. `baseId`, `channel`, `teamId`). The advanced field's `id` should typically match `canonicalParamId`.
4.**`dependsOn` references the selector field's `id`**, not the `canonicalParamId`. The modal propagates dependency clearing across canonical siblings automatically — changing either field in a parent pair clears dependent children.
### Selector canonical pair example (Airtable base → table cascade)
```typescript
configFields:[
// Base: selector (basic) + manual (advanced)
{
id:'baseSelector',
title:'Base',
type:'selector',
selectorKey:'airtable.bases',// Must exist in hooks/selectors/registry.ts
canonicalParamId:'baseId',
mode:'basic',
placeholder:'Select a base',
required: true,
},
{
id:'baseId',
title:'Base ID',
type:'short-input',
canonicalParamId:'baseId',
mode:'advanced',
placeholder:'e.g. appXXXXXXXXXXXXXX',
required: true,
},
// Table: selector depends on base (basic) + manual (advanced)
{
id:'tableSelector',
title:'Table',
type:'selector',
selectorKey:'airtable.tables',
canonicalParamId:'tableIdOrName',
mode:'basic',
dependsOn:['baseSelector'],// References the selector field ID
### Selector with domain dependency (Jira/Confluence pattern)
When a selector depends on a plain `short-input` field (no canonical pair), `dependsOn` references that field's `id` directly. The `domain` field's value maps to `SelectorContext.domain` automatically via `SELECTOR_CONTEXT_FIELDS`.
```typescript
configFields:[
{
id:'domain',
title:'Jira Domain',
type:'short-input',
placeholder:'yoursite.atlassian.net',
required: true,
},
{
id:'projectSelector',
title:'Project',
type:'selector',
selectorKey:'jira.projects',
canonicalParamId:'projectKey',
mode:'basic',
dependsOn:['domain'],
placeholder:'Select a project',
required: true,
},
{
id:'projectKey',
title:'Project Key',
type:'short-input',
canonicalParamId:'projectKey',
mode:'advanced',
placeholder:'e.g. ENG, PROJ',
required: true,
},
]
```
### How `dependsOn` maps to `SelectorContext`
The connector selector field builds a `SelectorContext` from dependency values. For the mapping to work, each dependency's `canonicalParamId` (or field `id` for non-canonical fields) must exist in `SELECTOR_CONTEXT_FIELDS` (`lib/workflows/subblocks/context.ts`):
All external API calls must use `fetchWithRetry` from `@/lib/knowledge/documents/utils` instead of raw `fetch()`. This provides exponential backoff with retries on 429/502/503/504 errors. It returns a standard `Response` — all `.ok`, `.json()`, `.text()` checks work unchanged.
For `validateConfig` (user-facing, called on save), pass `VALIDATE_RETRY_OPTIONS` to cap wait time at ~7s. Background operations (`listDocuments`, `getDocument`) use the built-in defaults (5 retries, ~31s max).
If `ExternalDocument.sourceUrl` is set, the sync engine stores it on the document record. Always construct the full URL (not a relative path).
## Sync Engine Behavior (Do Not Modify)
The sync engine (`lib/knowledge/connectors/sync-engine.ts`) is connector-agnostic. It:
1. Calls `listDocuments` with pagination until `hasMore` is false
2. Compares `contentHash` to detect new/changed/unchanged documents
3. Stores `sourceUrl` and calls `mapTags` on insert/update automatically
4. Handles soft-delete of removed documents
5. Resolves access tokens automatically — OAuth tokens are refreshed, API keys are decrypted from the `encryptedApiKey` column
You never need to modify the sync engine when adding a connector.
## Icon
The `icon` field on `ConnectorConfig` is used throughout the UI — in the connector list, the add-connector modal, and as the document icon in the knowledge base table (replacing the generic file type icon for connector-sourced documents). The icon is read from `CONNECTOR_REGISTRY[connectorType].icon` at runtime — no separate icon map to maintain.
If the service already has an icon in `apps/sim/components/icons.tsx` (from a tool integration), reuse it. Otherwise, ask the user to provide the SVG.
## Registering
Add one line to `apps/sim/connectors/registry.ts`:
-`visibility: 'user-only'` for API keys and user credentials
-`visibility: 'user-or-llm'` for operation parameters
- Always use `?? null` for nullable API response fields
- Always use `?? []` for optional array fields
- Set `optional: true` for outputs that may not exist
- Never output raw JSON dumps - extract meaningful fields
- When using `type: 'json'` and you know the object shape, define `properties` with the inner fields so downstream consumers know the structure. Only use bare `type: 'json'` when the shape is truly dynamic
-`canonicalParamId` must NOT match any subblock's `id` in the block
-`canonicalParamId` must be unique per operation/condition context
- Only use `canonicalParamId` to link basic/advanced alternatives for the same logical parameter
-`mode` only controls UI visibility, NOT serialization. Without `canonicalParamId`, both basic and advanced field values would be sent
- Every subblock `id` must be unique within the block. Duplicate IDs cause conflicts even with different conditions
- **Required consistency:** If one subblock in a canonical group has `required: true`, ALL subblocks in that group must have `required: true` (prevents bypassing validation by switching modes)
- **Inputs section:** Must list canonical param IDs (e.g., `fileId`), NOT raw subblock IDs (e.g., `fileSelector`, `manualFileId`)
- **Params function:** Must use canonical param IDs, NOT raw subblock IDs (raw IDs are deleted after canonical transformation)
- [ ] Secondary triggers do NOT have `includeDropdown`
- [ ] All triggers use `buildTriggerSubBlocks` helper
- [ ] Created `index.ts` barrel export
- [ ] Registered all triggers in `triggers/registry.ts`
### Docs
- [ ] Ran `bun run scripts/generate-docs.ts`
- [ ] Verified docs file created
### Final Validation (Required)
- [ ] Read every tool file and cross-referenced inputs/outputs against the API docs
- [ ] Verified block subBlocks cover all required tool params with correct conditions
- [ ] Verified block outputs match what the tools actually return
- [ ] Verified `tools.config.params` correctly maps and coerces all param types
## Example Command
When the user asks to add an integration:
```
User: Add a Stripe integration
You: I'll add the Stripe integration. Let me:
1. First, research the Stripe API using Context7
2. Create the tools for key operations (payments, subscriptions, etc.)
3. Create the block with operation dropdown
4. Register everything
5. Generate docs
6. Ask you for the Stripe icon SVG
[Proceed with implementation...]
[After completing steps 1-5...]
I've completed the Stripe integration. Before I can add the icon, please provide the SVG for Stripe.
You can usually find this in the service's brand/press kit page, or copy it from their website.
Paste the SVG code here and I'll convert it to a React component.
```
## File Handling
When your integration handles file uploads or downloads, follow these patterns to work with `UserFile` objects consistently.
### What is a UserFile?
A `UserFile` is the standard file representation in Sim:
```typescript
interfaceUserFile{
id: string// Unique identifier
name: string// Original filename
url: string// Presigned URL for download
size: number// File size in bytes
type:string// MIME type (e.g., 'application/pdf')
base64?: string// Optional base64 content (if small file)
key?: string// Internal storage key
context?: object// Storage context metadata
}
```
### File Input Pattern (Uploads)
For tools that accept file uploads, **always route through an internal API endpoint** rather than calling external APIs directly. This ensures proper file content retrieval.
Optional fields that are rarely used should be set to `mode: 'advanced'` so they don't clutter the basic UI. Examples: pagination tokens, time range filters, sort order, max results, reply settings.
### WandConfig for Complex Inputs
Use `wandConfig` for fields that are hard to fill out manually:
- **Timestamps**: Use `generationType: 'timestamp'` to inject current date context into the AI prompt
- **JSON arrays**: Use `generationType: 'json-object'` for structured data
- **Complex queries**: Use a descriptive prompt explaining the expected format
```typescript
{
id:'startTime',
title:'Start Time',
type:'short-input',
mode:'advanced',
wandConfig:{
enabled: true,
prompt:'Generate an ISO 8601 timestamp. Return ONLY the timestamp string.',
generationType:'timestamp',
},
}
```
### OAuth Scopes (Centralized System)
Scopes are maintained in a single source of truth and reused everywhere:
1.**Define scopes** in `lib/oauth/oauth.ts` under `OAUTH_PROVIDERS[provider].services[service].scopes`
2.**Add descriptions** in `SCOPE_DESCRIPTIONS` within `lib/oauth/utils.ts` for the OAuth modal UI
3.**Reference in auth.ts** using `getCanonicalScopesForProvider(providerId)` from `@/lib/oauth/utils`
4.**Reference in blocks** using `getScopesForService(serviceId)` from `@/lib/oauth/utils`
**Never hardcode scope arrays** in `auth.ts` or block `requiredScopes`. Always import from the centralized source.
1.**OAuth serviceId must match** - The `serviceId` in oauth-input must match the OAuth provider configuration
2.**All tool IDs MUST be snake_case** - `stripe_create_payment`, not `stripeCreatePayment`. This applies to tool `id` fields, registry keys, `tools.access` arrays, and `tools.config.tool` return values
3.**Block type is snake_case** - `type: 'stripe'`, not `type: 'Stripe'`
4.**Alphabetical ordering** - Keep imports and registry entries alphabetically sorted
5.**Required can be conditional** - Use `required: { field: 'op', value: 'create' }` instead of always true
6.**DependsOn clears options** - When a dependency changes, selector options are refetched
7.**Never pass Buffer directly to fetch** - Convert to `new Uint8Array(buffer)` for TypeScript compatibility
description: Create tool configurations for a Sim integration by reading API docs
argument-hint: <service-name> [api-docs-url]
---
# Add Tools Skill
You are an expert at creating tool configurations for Sim integrations. Your job is to read API documentation and create properly structured tool files.
## Your Task
When the user asks you to create tools for a service:
1. Use Context7 or WebFetch to read the service's API documentation
2. Create the tools directory structure
3. Generate properly typed tool configurations
## Directory Structure
Create files in `apps/sim/tools/{service}/`:
```
tools/{service}/
├── index.ts # Barrel export
├── types.ts # Parameter & response types
└── {action}.ts # Individual tool files (one per operation)
// Trim ID fields to prevent copy-paste whitespace errors:
// userId: params.userId?.trim(),
}),
},
transformResponse: async(response: Response)=>{
constdata=awaitresponse.json()
return{
success: true,
output:{
// Map API response to output
// Use ?? null for nullable fields
// Use ?? [] for optional arrays
},
}
},
outputs:{
// Define each output field
},
}
```
## Critical Rules for Parameters
### Visibility Options
-`'hidden'` - System-injected (OAuth tokens, internal params). User never sees.
-`'user-only'` - User must provide (credentials, api keys, account-specific IDs)
-`'user-or-llm'` - User provides OR LLM can compute (search queries, content, filters, most fall into this category)
### Parameter Types
-`'string'` - Text values
-`'number'` - Numeric values
-`'boolean'` - True/false
-`'json'` - Complex objects (NOT 'object', use 'json')
-`'file'` - Single file
-`'file[]'` - Multiple files
### Required vs Optional
- Always explicitly set `required: true` or `required: false`
- Optional params should have `required: false`
## Critical Rules for Outputs
### Output Types
-`'string'`, `'number'`, `'boolean'` - Primitives
-`'json'` - Complex objects (use this, NOT 'object')
-`'array'` - Arrays with `items` property
-`'object'` - Objects with `properties` property
### Optional Outputs
Add `optional: true` for fields that may not exist in the response:
```typescript
closedAt:{
type:'string',
description:'When the issue was closed',
optional: true,
},
```
### Typed JSON Outputs
When using `type: 'json'` and you know the object shape in advance, **always define the inner structure** using `properties` so downstream consumers know what fields are available:
```typescript
// BAD: Opaque json with no info about what's inside
2. Add to the `tools` object with snake_case keys:
```typescript
import{serviceActionTool}from'@/tools/{service}'
exportconsttools={
// ... existing tools ...
{service}_{action}:serviceActionTool,
}
```
## V2 Tool Pattern
If creating V2 tools (API-aligned outputs), use `_v2` suffix:
- Tool ID: `{service}_{action}_v2`
- Variable name: `{action}V2Tool`
- Version: `'2.0.0'`
- Outputs: Flat, API-aligned (no content/metadata wrapper)
## Naming Convention
All tool IDs MUST use `snake_case`: `{service}_{action}` (e.g., `x_create_tweet`, `slack_send_message`). Never use camelCase or PascalCase for tool IDs.
## Checklist Before Finishing
- [ ] All tool IDs use snake_case
- [ ] All params have explicit `required: true` or `required: false`
- [ ] All params have appropriate `visibility`
- [ ] All nullable response fields use `?? null`
- [ ] All optional outputs have `optional: true`
- [ ] No raw JSON dumps in outputs
- [ ] Types file has all interfaces
- [ ] Index.ts exports all tools
## Final Validation (Required)
After creating all tools, you MUST validate every tool before finishing:
1.**Read every tool file** you created — do not skip any
2.**Cross-reference with the API docs** to verify:
- All required params are marked `required: true`
- All optional params are marked `required: false`
- Param types match the API (string, number, boolean, json)
- Request URL, method, headers, and body match the API spec
-`transformResponse` extracts the correct fields from the API response
- All output fields match what the API actually returns
- No fields are missing from outputs that the API provides
- No extra fields are defined in outputs that the API doesn't return
3.**Verify consistency** across tools:
- Shared types in `types.ts` match all tools that use them
- Tool IDs in the barrel export match the tool file definitions
- Error handling is consistent (error checks, meaningful messages)
description: Create webhook triggers for a Sim integration using the generic trigger builder
argument-hint: <service-name>
---
# Add Trigger Skill
You are an expert at creating webhook triggers for Sim. You understand the trigger system, the generic `buildTriggerSubBlocks` helper, and how triggers connect to blocks.
## Your Task
When the user asks you to create triggers for a service:
1. Research what webhook events the service supports
2. Create the trigger files using the generic builder
3. Register triggers and connect them to the block
In the block file (`apps/sim/blocks/blocks/{service}.ts`):
```typescript
import{{Service}Icon}from'@/components/icons'
import{getTrigger}from'@/triggers'
importtype{BlockConfig}from'@/blocks/types'
exportconst{Service}Block: BlockConfig={
type:'{service}',
name:'{Service}',
// ... other config ...
// Enable triggers and list available trigger IDs
triggers:{
enabled: true,
available:[
'{service}_event_a',
'{service}_event_b',
'{service}_event_c',
'{service}_webhook',
],
},
subBlocks:[
// Regular tool subBlocks first
{id:'operation',/* ... */},
{id:'credential',/* ... */},
// ... other tool fields ...
// Then spread ALL trigger subBlocks
...getTrigger('{service}_event_a').subBlocks,
...getTrigger('{service}_event_b').subBlocks,
...getTrigger('{service}_event_c').subBlocks,
...getTrigger('{service}_webhook').subBlocks,
],
// ... tools config ...
}
```
## Automatic Webhook Registration (Preferred)
If the service's API supports programmatic webhook creation, implement automatic webhook registration instead of requiring users to manually configure webhooks. This provides a much better user experience.
### When to Use Automatic Registration
Check the service's API documentation for endpoints like:
-`POST /webhooks` or `POST /hooks` - Create webhook
-`DELETE /webhooks/{id}` - Delete webhook
Services that support this pattern include: Grain, Lemlist, Calendly, Airtable, Webflow, Typeform, etc.
### Implementation Steps
#### 1. Add API Key to Extra Fields
Update your `build{Service}ExtraFields` function to include an API key field:
1.**Dropdown** (only if `includeDropdown: true`) - Trigger type selector
2.**Webhook URL** - Read-only field with copy button
3.**Extra Fields** - Your service-specific fields (filters, options, etc.)
4.**Save Button** - Activates the trigger
5.**Instructions** - Setup guide for users
All fields automatically have:
-`mode: 'trigger'` - Only shown in trigger mode
-`condition: { field: 'selectedTriggerId', value: triggerId }` - Only shown when this trigger is selected
## Trigger Outputs & Webhook Input Formatting
### Important: Two Sources of Truth
There are two related but separate concerns:
1.**Trigger `outputs`** - Schema/contract defining what fields SHOULD be available. Used by UI for tag dropdown.
2.**`formatWebhookInput`** - Implementation that transforms raw webhook payload into actual data. Located in `apps/sim/lib/webhooks/utils.server.ts`.
**These MUST be aligned.** The fields returned by `formatWebhookInput` should match what's defined in trigger `outputs`. If they differ:
- Tag dropdown shows fields that don't exist (broken variable resolution)
- Or actual data has fields not shown in dropdown (users can't discover them)
### When to Add a formatWebhookInput Handler
- **Simple providers**: If the raw webhook payload structure already matches your outputs, you don't need a handler. The generic fallback returns `body` directly.
- **Complex providers**: If you need to transform, flatten, extract nested data, compute fields, or handle conditional logic, add a handler.
### Adding a Handler
In `apps/sim/lib/webhooks/utils.server.ts`, add a handler block:
```typescript
if(foundWebhook.provider==='{service}'){
// Transform raw webhook body to match trigger outputs
return{
eventType: body.type,
resourceId: body.data?.id||'',
timestamp: body.created_at,
resource: body.data,
}
}
```
**Key rules:**
- Return fields that match your trigger `outputs` definition exactly
- No wrapper objects like `webhook: { data: ... }` or `{service}: { ... }`
- No duplication (don't spread body AND add individual fields)
- Use `null` for missing optional data, not empty objects with empty strings
### Verify Alignment
Run the alignment checker:
```bash
bunx scripts/check-trigger-alignment.ts {service}
```
## Trigger Outputs
Trigger outputs use the same schema as block outputs (NOT tool outputs).
description: Validate an existing Sim integration (tools, block, registry) against the service's API docs
argument-hint: <service-name> [api-docs-url]
---
# Validate Integration Skill
You are an expert auditor for Sim integrations. Your job is to thoroughly validate that an existing integration is correct, complete, and follows all conventions.
## Your Task
When the user asks you to validate an integration:
1. Read the service's API documentation (via WebFetch or Context7)
2. Read every tool, the block, and registry entries
3. Cross-reference everything against the API docs and Sim conventions
4. Report all issues found, grouped by severity (critical, warning, suggestion)
5. Fix all issues after reporting them
## Step 1: Gather All Files
Read **every** file for the integration — do not skip any:
```
apps/sim/tools/{service}/ # All tool files, types.ts, index.ts
- Credentials → `oauth-input` with correct `serviceId`
- [ ] Dropdown `value: () => 'default'` is set for dropdowns with a sensible default
### Advanced Mode
- [ ] Optional, rarely-used fields are set to `mode: 'advanced'`:
- Pagination tokens / next tokens
- Time range filters (start/end time)
- Sort order / direction options
- Max results / per page limits
- Reply settings / threading options
- Rarely used IDs (reply-to, quote-tweet, etc.)
- Exclude filters
- [ ]**Required** fields are NEVER set to `mode: 'advanced'`
- [ ] Fields that users fill in most of the time are NOT set to `mode: 'advanced'`
### WandConfig
- [ ] Timestamp fields have `wandConfig` with `generationType: 'timestamp'`
- [ ] Comma-separated list fields have `wandConfig` with a descriptive prompt
- [ ] Complex filter/query fields have `wandConfig` with format examples in the prompt
- [ ] All `wandConfig` prompts end with "Return ONLY the [format] - no explanations, no extra text."
- [ ]`wandConfig.placeholder` describes what to type in natural language
### Tools Config
- [ ]`tools.access` lists **every** tool ID the block can use — none missing
- [ ]`tools.config.tool` returns the correct tool ID for each operation
- [ ] Type coercions are in `tools.config.params` (runs at execution time), NOT in `tools.config.tool` (runs at serialization time before variable resolution)
- [ ]`tools.config.params` handles:
-`Number()` conversion for numeric params that come as strings from inputs
-`Boolean` / string-to-boolean conversion for toggle params
- Empty string → `undefined` conversion for optional dropdown values
- Any subBlock ID → tool param name remapping
- [ ] No `Number()`, `JSON.parse()`, or other coercions in `tools.config.tool` — these would destroy dynamic references like `<Block.output>`
### Block Outputs
- [ ] Outputs cover the key fields returned by ALL tools (not just one operation)
**Only exception:** Singleton modules that cache state at module scope (e.g., Redis clients, connection pools). These genuinely need `vi.resetModules()` + dynamic import to get a fresh instance per test.
### NEVER use `vi.importActual()`
This defeats the purpose of mocking by loading the real module and all its dependencies.
// GOOD — mock everything, only implement what tests need
vi.mock('@/lib/workspaces/utils',()=>({
myFn: vi.fn(),
otherFn: vi.fn(),
}))
```
### NEVER use `mockAuth()`, `mockConsoleLogger()`, or `setupCommonApiMocks()` from `@sim/testing`
These helpers internally use `vi.doMock()` which is slow. Use direct `vi.hoisted()` + `vi.mock()` instead.
### Mock heavy transitive dependencies
If a module under test imports `@/blocks` (200+ files), `@/tools/registry`, or other heavy modules, mock them:
```typescript
vi.mock('@/blocks',()=>({
getBlock:()=>null,
getAllBlocks:()=>({}),
getAllBlockTypes:()=>[],
registry:{},
}))
```
### Use `@vitest-environment node` unless DOM is needed
Only use `@vitest-environment jsdom` if the test uses `window`, `document`, `FormData`, or other browser APIs. Node environment is significantly faster.
1. Dig around the codebase in terms of that given area of interest, gather general information such as keywords and architecture overview.
2. Spawn off n=10 (unless specified otherwise) task agents to dig deeper into the codebase in terms of that given area of interest, some of them should be out of the box for variance.
3. Once the task agents are done, use the information to do what the user wants.
If user is in plan mode, use the information to create the plan.
description: React Query patterns for the Sim application
globs: ["apps/sim/hooks/queries/**/*.ts"]
---
# React Query Patterns
All React Query hooks live in `hooks/queries/`. All server state must go through React Query — never use `useState` + `fetch` in components for data fetching or mutations.
## Query Key Factory
Every query file defines a hierarchical keys factory with an `all` root key and intermediate plural keys for prefix-level invalidation:
```typescript
export const entityKeys = {
all: ['entity'] as const,
lists: () => [...entityKeys.all, 'list'] as const,
list: (workspaceId?: string) => [...entityKeys.lists(), workspaceId ?? ''] as const,
details: () => [...entityKeys.all, 'detail'] as const,
detail: (id?: string) => [...entityKeys.details(), id ?? ''] as const,
}
```
Never use inline query keys — always use the factory.
## File Structure
```typescript
// 1. Query keys factory
// 2. Types (if needed)
// 3. Private fetch functions (accept signal parameter)
// 4. Exported hooks
```
## Query Hook
- Every `queryFn` must destructure and forward `signal` for request cancellation
- Every query must have an explicit `staleTime`
- Use `keepPreviousData` only on variable-key queries (where params change), never on static keys
```typescript
async function fetchEntities(workspaceId: string, signal?: AbortSignal) {
const response = await fetch(`/api/entities?workspaceId=${workspaceId}`, { signal })
if (!response.ok) throw new Error('Failed to fetch entities')
return response.json()
}
export function useEntityList(workspaceId?: string, options?: { enabled?: boolean }) {
return useQuery({
queryKey: entityKeys.list(workspaceId),
queryFn: ({ signal }) => fetchEntities(workspaceId as string, signal),
For optimistic mutations, use `onSettled` (not `onSuccess`) for cache reconciliation — `onSettled` fires on both success and error, ensuring the cache is always reconciled with the server.
For optimistic mutations syncing with Zustand, use `createOptimisticMutationHandlers` from `@/hooks/queries/utils/optimistic-mutation`.
## useCallback Dependencies
Never include mutation objects (e.g., `createEntity`) in `useCallback` dependency arrays — the mutation object is not referentially stable and changes on every state update. The `.mutate()` and `.mutateAsync()` functions are stable in TanStack Query v5.
**Only exception:** Singleton modules that cache state at module scope (e.g., Redis clients, connection pools). These genuinely need `vi.resetModules()` + dynamic import to get a fresh instance per test.
### NEVER use `vi.importActual()`
This defeats the purpose of mocking by loading the real module and all its dependencies.
```typescript
// BAD — loads real module + all transitive deps
vi.mock('@/lib/workspaces/utils', async () => {
const actual = await vi.importActual('@/lib/workspaces/utils')
return { ...actual, myFn: vi.fn() }
})
// GOOD — mock everything, only implement what tests need
vi.mock('@/lib/workspaces/utils', () => ({
myFn: vi.fn(),
otherFn: vi.fn(),
}))
```
### NEVER use `mockAuth()`, `mockConsoleLogger()`, or `setupCommonApiMocks()` from `@sim/testing`
These helpers internally use `vi.doMock()` which is slow. Use direct `vi.hoisted()` + `vi.mock()` instead.
### Mock heavy transitive dependencies
If a module under test imports `@/blocks` (200+ files), `@/tools/registry`, or other heavy modules, mock them:
```typescript
vi.mock('@/blocks', () => ({
getBlock: () => null,
getAllBlocks: () => ({}),
getAllBlockTypes: () => [],
registry: {},
}))
```
### Use `@vitest-environment node` unless DOM is needed
Only use `@vitest-environment jsdom` if the test uses `window`, `document`, `FormData`, or other browser APIs. Node environment is significantly faster.
description: Add hosted API key support to a tool so Sim provides the key when users don't bring their own. Use when adding hosted keys, BYOK support, hideWhenHosted, or hosted key pricing to a tool or block.
---
# Adding Hosted Key Support to a Tool
When a tool has hosted key support, Sim provides its own API key if the user hasn't configured one (via BYOK or env var). Usage is metered and billed to the workspace.
## Step 2: Research the API's Pricing Model and Rate Limits
**Before writing any `getCost` or `rateLimit` code**, look up the service's official documentation for both pricing and rate limits. You need to understand:
### Pricing
1.**How the API charges** — per request, per credit, per token, per step, per minute, etc.
2.**Whether the API reports cost in its response** — look for fields like `creditsUsed`, `costDollars`, `tokensUsed`, or similar in the response body or headers
3.**Whether cost varies by endpoint/options** — some APIs charge more for certain features (e.g., Firecrawl charges 1 credit/page base but +4 for JSON format, +4 for enhanced mode)
4.**The dollar-per-unit rate** — what each credit/token/unit costs in dollars on our plan
### Rate Limits
1.**What rate limits the API enforces** — requests per minute/second, tokens per minute, concurrent requests, etc.
2.**Whether limits vary by plan tier** — free vs paid vs enterprise often have different ceilings
3.**Whether limits are per-key or per-account** — determines whether adding more hosted keys actually increases total throughput
4.**What the API returns when rate limited** — HTTP 429, `Retry-After` header, error body format, etc.
5.**Whether there are multiple dimensions** — some APIs limit both requests/min AND tokens/min independently
Search the API's docs/pricing page (use WebSearch/WebFetch). Capture the pricing model as a comment in `getCost` so future maintainers know the source of truth.
### Setting Our Rate Limits
Our rate limiter (`lib/core/rate-limiter/hosted-key/`) uses a token-bucket algorithm applied **per billing actor** (workspace). It supports two modes:
- **`per_request`** — simple; just `requestsPerMinute`. Good when the API charges flat per-request or cost doesn't vary much.
- **`custom`** — `requestsPerMinute` plus additional `dimensions` (e.g., `tokens`, `search_units`). Each dimension has its own `limitPerMinute` and an `extractUsage` function that reads actual usage from the response. Use when the API charges on a variable metric (tokens, credits) and you want to cap that metric too.
When choosing values for `requestsPerMinute` and any dimension limits:
- **Stay well below the API's per-key limit** — our keys are shared across all workspaces. If the API allows 60 RPM per key and we have 3 keys, the global ceiling is ~180 RPM. Set the per-workspace limit low enough (e.g., 20-60 RPM) that many workspaces can coexist without collectively hitting the API's ceiling.
- **Account for key pooling** — our round-robin distributes requests across `N` hosted keys, so the effective API-side rate per key is `(total requests) / N`. But per-workspace limits are enforced *before* key selection, so they apply regardless of key count.
- **Prefer conservative defaults** — it's easy to raise limits later but hard to claw back after users depend on high throughput.
## Step 3: Add `hosting` Config to the Tool
Add a `hosting` object to the tool's `ToolConfig`. This tells the execution layer how to acquire hosted keys, calculate cost, and rate-limit.
Keys use a numbered naming pattern driven by a count env var:
```
YOUR_SERVICE_API_KEY_COUNT=3
YOUR_SERVICE_API_KEY_1=sk-...
YOUR_SERVICE_API_KEY_2=sk-...
YOUR_SERVICE_API_KEY_3=sk-...
```
The `envKeyPrefix` value (`YOUR_SERVICE_API_KEY`) determines which env vars are read at runtime. Adding more keys only requires bumping the count and adding the new env var.
### Pricing: Prefer API-Reported Cost
Always prefer using cost data returned by the API (e.g., `creditsUsed`, `costDollars`). This is the most accurate because it accounts for variable pricing tiers, feature modifiers, and plan-level discounts.
**When the API reports cost** — use it directly and throw if missing:
// Serper: 1 credit for <=10 results, 2 credits for >10 — from https://serper.dev/pricing
constcredits=Number(params.num)>10?2 : 1
return{cost: credits*0.001,metadata:{credits}}
},
},
```
**`getCost` must always throw** if it cannot determine cost. Never silently fall back to a default — this would hide billing inaccuracies.
### Capturing Cost Data from the API
If the API returns cost info, capture it in `transformResponse` so `getCost` can read it from the output:
```typescript
transformResponse: async(response: Response)=>{
constdata=awaitresponse.json()
return{
success: true,
output:{
results: data.results,
creditsUsed: data.creditsUsed,// pass through for getCost
},
}
},
```
For async/polling tools, capture it in `postProcess` when the job completes:
```typescript
if(jobData.status==='completed'){
result.output={
data: jobData.data,
creditsUsed: jobData.creditsUsed,
}
}
```
## Step 4: Hide the API Key Field When Hosted
In the block config (`blocks/blocks/{service}.ts`), add `hideWhenHosted: true` to the API key subblock. This hides the field on hosted Sim since the platform provides the key:
```typescript
{
id:'apiKey',
title:'API Key',
type:'short-input',
placeholder:'Enter your API key',
password: true,
required: true,
hideWhenHosted: true,
},
```
The visibility is controlled by `isSubBlockHiddenByHostedKey()` in `lib/workflows/subblocks/visibility.ts`, which checks the `isHosted` feature flag.
### Excluding Specific Operations from Hosted Key Support
When a block has multiple operations but some operations should **not** use a hosted key (e.g., the underlying API is deprecated, unsupported, or too expensive), use the **duplicate apiKey subblock** pattern. This is the same pattern Exa uses for its `research` operation:
1.**Remove the `hosting` config** from the tool definition for that operation — it must not have a `hosting` object at all.
2.**Duplicate the `apiKey` subblock** in the block config with opposing conditions:
```typescript
// API Key — hidden when hosted for operations with hosted key support
Both subblocks share the same `id: 'apiKey'`, so the same value flows to the tool. The conditions ensure only one is visible at a time. The first has `hideWhenHosted: true` and shows for all hosted operations; the second has no `hideWhenHosted` and shows only for the excluded operation — meaning users must always provide their own key for that operation.
To exclude multiple operations, use an array: `{ field: 'operation', value: ['op_a', 'op_b'] }`.
Add an entry to the `PROVIDERS` array in the BYOK settings component so users can bring their own key. You need the service icon from `components/icons.tsx`:
```typescript
{
id:'your_service',
name:'Your Service',
icon: YourServiceIcon,
description:'What this service does',
placeholder:'Enter your API key',
},
```
## Step 6: Summarize Pricing and Throttling Comparison
After all code changes are complete, output a detailed summary to the user covering:
### What to include
1.**API's pricing model** — how the service charges (per token, per credit, per request, etc.), the specific rates found in docs, and whether the API reports cost in responses.
2.**Our `getCost` approach** — how we calculate cost, what fields we depend on, and any assumptions or estimates (especially when the API doesn't report exact dollar cost).
3.**API's rate limits** — the documented limits (RPM, TPM, concurrent, etc.), which plan tier they apply to, and whether they're per-key or per-account.
4.**Our `rateLimit` config** — what we set for `requestsPerMinute` (and dimensions if custom mode), why we chose those values, and how they compare to the API's limits.
5.**Key pooling impact** — how many hosted keys we expect, and how round-robin distribution affects the effective per-key rate at the API.
6.**Gaps or risks** — anything the API charges for that we don't meter, rate limit dimensions we chose not to enforce, or pricing that may be inaccurate due to variable model/tier costs.
### Format
Present this as a structured summary with clear headings. Example:
```
### Pricing
- **API charges**: $X per 1M tokens (input), $Y per 1M tokens (output) — varies by model
- **Response reports cost?**: No — only token counts in `usage` field
- **Our getCost**: Estimates cost at $Z per 1M total tokens based on median model pricing
- **Risk**: Actual cost varies by model; our estimate may over/undercharge for cheap/expensive models
This directory contains configuration files for Visual Studio Code Dev Containers / GitHub Codespaces. Dev containers provide a consistent, isolated development environment for this project.
Development container configuration for VS Code Dev Containers and GitHub Codespaces.
## Contents
-`devcontainer.json` - The main configuration file that defines the development container settings
-`Dockerfile` - Defines the container image and development environment
-`docker-compose.yml` - Sets up the application and database containers
-`post-create.sh` - Script that runs when the container is created
-`.bashrc` - Custom shell configuration with helpful aliases
## Usage
### Prerequisites
## Prerequisites
- Visual Studio Code
- Docker installation:
-Docker Desktop (Windows/macOS)
- Docker Engine (Linux)
- VS Code Remote - Containers extension
- Docker Desktop or Podman Desktop
-VS Code Dev Containers extension
### Getting Started
## Getting Started
1. Open this project in Visual Studio Code
2.When prompted, click "Reopen in Container"
- Alternatively, press `F1` and select "Remote-Containers: Reopen in Container"
1. Open this project in VS Code
2.Click "Reopen in Container" when prompted (or press `F1` → "Dev Containers: Reopen in Container")
3. Wait for the container to build and initialize
4.The post-creation script will automatically:
4.Start developing with `sim-start`
- Install dependencies
- Set up environment variables
- Run database migrations
- Configure helpful aliases
The setup script will automatically install dependencies and run migrations.
5. Start the application with `sim-start` (alias for `bun run dev`)
## Development Commands
### Development Commands
### Running Services
The development environment includes these helpful aliases:
You have two options for running the development environment:
**Option 1: Run everything together (recommended for most development)**
```bash
sim-start # Runs both app and socket server using concurrently
```
**Option 2: Run services separately (useful for debugging individual services)**
- In the **app** container terminal: `sim-app` (starts Next.js app on port 3000)
- In the **realtime** container terminal: `sim-sockets` (starts socket server on port 3002)
### Other Commands
-`sim-start` - Start the development server
-`sim-migrate` - Push schema changes to the database
-`sim-generate` - Generate new migrations
-`sim-rebuild` - Build and start the production version
-`pgc` - Connect to the PostgreSQL database
-`check-db` - List all databases
### Using GitHub Codespaces
This project is also configured for GitHub Codespaces. To use it:
1. Go to the GitHub repository
2. Click the "Code" button
3. Select the "Codespaces" tab
4. Click "Create codespace on main"
This will start a new Codespace with the development environment already set up.
## Customization
You can customize the development environment by:
- Modifying `devcontainer.json` to add VS Code extensions or settings
- Updating the `Dockerfile` to install additional packages
- Editing `docker-compose.yml` to add services or change configuration
- Modifying `.bashrc` to add custom aliases or configurations
-`build` - Build the application
-`pgc` - Connect to PostgreSQL database
## Troubleshooting
If you encounter issues:
**Build errors**: Rebuild the container with `F1` → "Dev Containers: Rebuild Container"
1. Rebuild the container: `F1` → "Remote-Containers: Rebuild Container"
2. Check Docker logs for build errors
3. Verify Docker Desktop is running
4. Ensure all prerequisites are installed
**Port conflicts**: Ensure ports 3000, 3002, and 5432 are available
For more information, see the [VS Code Remote Development documentation](https://code.visualstudio.com/docs/remote/containers).
**Container runtime issues**: Verify Docker Desktop or Podman Desktop is running
## Technical Details
Services:
- **App container** (8GB memory limit) - Main Next.js application
- **Realtime container** (4GB memory limit) - Socket.io server for real-time features
- **Database** - PostgreSQL with pgvector extension
- **Migrations** - Runs automatically on container creation
You can develop with services running together or independently.
### Personalization
**Project commands** (`sim-start`, `sim-app`, etc.) are automatically available via `/workspace/.devcontainer/sim-commands.sh`.
**Personal shell customization** (aliases, prompts, etc.) should use VS Code's dotfiles feature:
1. Create a dotfiles repository (e.g., `github.com/youruser/dotfiles`)
2. Add your `.bashrc`, `.zshrc`, or other configs
3. Configure in VS Code Settings:
```json
{
"dotfiles.repository": "youruser/dotfiles",
"dotfiles.installCommand": "install.sh"
}
```
This separates project-specific commands from personal preferences, following VS Code best practices.
Automated translation updates triggered by changes to documentation.
This PR was automatically created after content changes were made, updating translations for all supported languages using Lingo.dev AI translation engine.
Automated weekly translation updates for documentation.
This PR was automatically created by the scheduled weekly i18n workflow, updating translations for all supported languages using Lingo.dev AI translation engine.
ERRORS="${ERRORS}\n❌ Feature flags must not be hardcoded to boolean literals!\n\nFound hardcoded flags:\n${HARDCODED}\n\nFeature flags should derive their values from environment variables.\n"
fi
echo "Checking feature flag naming conventions..."
# Check that all export const (except functions) start with 'is'
# This finds exports like "export const someFlag" that don't start with "is" or "get"
ERRORS="${ERRORS}\n❌ Feature flags must use 'is' prefix for boolean flags!\n\nFound incorrectly named flags:\n${BAD_NAMES}\n\nExample: 'hostedMode' should be 'isHostedMode'\n"
fi
if [ -n "$ERRORS" ]; then
echo ""
echo -e "$ERRORS"
exit 1
fi
echo "✅ All feature flags are properly configured"
- name:Check subblock ID stability
run:|
if [ "${{ github.event_name }}" = "pull_request" ]; then
Use `devtools` middleware. Use `persist` only when data should survive reload with `partialize` to persist only necessary state.
## React Query
All React Query hooks live in `hooks/queries/`. All server state must go through React Query — never use `useState` + `fetch` in components for data fetching or mutations.
### Query Key Factory
Every file must have a hierarchical key factory with an `all` root key and intermediate plural keys for prefix invalidation:
Import from `@/components/emcn`, never from subpaths (except CSS files). Use CVA when 2+ variants exist.
## Testing
Use Vitest. Test files: `feature.ts` → `feature.test.ts`. See `.cursor/rules/sim-testing.mdc` for full details.
### Global Mocks (vitest.setup.ts)
`@sim/db`, `drizzle-orm`, `@sim/logger`, `@/blocks/registry`, `@trigger.dev/sdk`, and store mocks are provided globally. Do NOT re-mock them unless overriding behavior.
tools:{access:['service_action'],config:{tool:(p)=>`service_${p.operation}`,params:(p)=>({/* type coercions here */})}},
inputs:{/* ... */},
outputs:{/* ... */},
}
```
Register in `blocks/registry.ts` (alphabetically).
**Important:**`tools.config.tool` runs during serialization (before variable resolution). Never do `Number()` or other type coercions there — dynamic references like `<Block.output>` will be destroyed. Use `tools.config.params` for type coercions (it runs during execution, after variables are resolved).
For file uploads, create an internal API route (`/api/tools/{service}/upload`) that uses `downloadFileFromStorage` to get file content from `UserFile` objects.
<p align="center">Build and deploy AI agent workflows in minutes.</p>
<p align="center">The open-source platform to build AI agents and run your agentic workforce. Connect 1,000+ integrations and LLMs to orchestrate agentic workflows.</p>
**Recommended approach - run both servers together (from project root):**
4. Run migrations:
```bash
bun run dev:full
cd packages/db && bunx drizzle-kit migrate --config=./drizzle.config.ts
```
This starts both the main Next.js application and the realtime socket server required for full functionality.
5. Start development servers:
**Alternative - run servers separately:**
Next.js app (from project root):
```bash
bun run dev
bun run dev:full # Starts both Next.js app and realtime socket server
```
Realtime socket server (from `apps/sim` directory in a separate terminal):
```bash
cd apps/sim
bun run dev:sockets
```
Or run separately: `bun run dev` (Next.js) and `cd apps/sim && bun run dev:sockets` (realtime).
## Copilot API Keys
@@ -173,6 +157,21 @@ Copilot is a Sim-managed service. To use Copilot on a self-hosted instance:
- Go to https://sim.ai → Settings → Copilot and generate a Copilot API key
- Set `COPILOT_API_KEY` environment variable in your self-hosted apps/sim/.env file to that value
## Environment Variables
Key environment variables for self-hosted deployments. See [`.env.example`](apps/sim/.env.example) for defaults or [`env.ts`](apps/sim/lib/core/config/env.ts) for the full list.
'Documentation for Sim — the open-source platform to build AI agents and run your agentic workforce. Connect 1,000+ integrations and LLMs to deploy and orchestrate agentic workflows.',
@@ -7,24 +7,31 @@ export default function RootLayout({ children }: { children: ReactNode }) {
exportconstmetadata={
metadataBase: newURL('https://docs.sim.ai'),
title:{
default:'Sim Documentation - Visual Workflow Builder for AI Applications',
default:'Sim Documentation — Build AI Agents & Run Your Agentic Workforce',
template:'%s',
},
description:
'Comprehensive documentation for Sim - the visual workflow builder for AI applications. Create powerful AI agents, automation workflows, and data processing pipelines by connecting blocks on a canvas—no coding required.',
'Documentation for Sim — the open-source platform to build AI agents and run your agentic workforce. Connect 1,000+ integrations and LLMs to deploy and orchestrate agentic workflows.',
title:'Sim Documentation - Visual Workflow Builder for AI Applications',
title:'Sim Documentation — Build AI Agents & Run Your Agentic Workforce',
description:
'Comprehensive documentation for Sim - the visual workflow builder for AI applications. Create powerful AI agents, automation workflows, and data processing pipelines.',
'Documentation for Sim — the open-source platform to build AI agents and run your agentic workforce. Connect 1,000+ integrations and LLMs to deploy and orchestrate agentic workflows.',
title:'Sim Documentation - Visual Workflow Builder for AI Applications',
card:'summary_large_image',
title:'Sim Documentation — Build AI Agents & Run Your Agentic Workforce',
description:
'Comprehensive documentation for Sim - the visual workflow builder for AI applications.',
creator:'@sim_ai',
'Documentation for Sim — the open-source platform to build AI agents and run your agentic workforce. Connect 1,000+ integrations and LLMs to deploy and orchestrate agentic workflows.',
> The open-source platform to build AI agents and run your agentic workforce.
Sim is the open-source platform to build AI agents and run your agentic workforce. Connect 1,000+ integrations and LLMs to deploy and orchestrate agentic workflows. Create agents, workflows, knowledge bases, tables, and docs. Trusted by over 100,000 builders.
## Documentation Overview
This file provides an overview of our documentation. For full content of all pages, see ${baseUrl}/llms-full.txt
@@ -74,7 +74,7 @@ export function StructuredData({
name:'Sim Documentation',
url: baseUrl,
description:
'Comprehensive documentation for Sim visual workflow builder for AI applications. Create powerful AI agents, automation workflows, and data processing pipelines.',
'Documentation for Sim — the open-source platform to build AI agents and run your agentic workforce. Connect 1,000+ integrations and LLMs to deploy and orchestrate agentic workflows.',
publisher:{
'@type':'Organization',
name:'Sim',
@@ -88,13 +88,7 @@ export function StructuredData({
@@ -104,7 +98,7 @@ export function StructuredData({
applicationCategory:'DeveloperApplication',
operatingSystem:'Any',
description:
'Visual workflow builder for AI applications. Create powerful AI agents, automation workflows, and data processing pipelines by connecting blocks on a canvas—no coding required.',
'Sim is the open-source platform to build AI agents and run your agentic workforce. Connect 1,000+ integrations and LLMs to deploy and orchestrate agentic workflows. Create agents, workflows, knowledge bases, tables, and docs.',
url: baseUrl,
author:{
'@type':'Organization',
@@ -115,12 +109,13 @@ export function StructuredData({
category:'Developer Tools',
},
featureList:[
'Visual workflow builder with drag-and-drop interface',
description: API key types, generation, and how to authenticate requests
---
import { Callout } from 'fumadocs-ui/components/callout'
import { Tab, Tabs } from 'fumadocs-ui/components/tabs'
To access the Sim API, you need an API key. Sim supports two types of API keys — **personal keys** and **workspace keys** — each with different billing and access behaviors.
description: Base URL, first API call, response format, error handling, and pagination
---
import { Callout } from 'fumadocs-ui/components/callout'
import { Tab, Tabs } from 'fumadocs-ui/components/tabs'
import { Step, Steps } from 'fumadocs-ui/components/steps'
## Base URL
All API requests are made to:
```
https://www.sim.ai
```
## Quick Start
<Steps>
<Step>
### Get your API key
Go to the Sim dashboard and navigate to **Settings → Sim Keys**, then click **Create**. See [Authentication](/api-reference/authentication) for details on key types.
</Step>
<Step>
### Find your workflow ID
Open a workflow in the Sim editor. The workflow ID is in the URL:
By default, workflow executions are **synchronous** — the API blocks until the workflow completes and returns the result directly.
For long-running workflows, use **asynchronous execution** by passing `async: true`:
```bash
curl -X POST https://www.sim.ai/api/workflows/{workflowId}/execute \
-H "Content-Type: application/json" \
-H "X-API-Key: YOUR_API_KEY" \
-d '{"inputs": {}, "async": true}'
```
This returns immediately with a `taskId`:
```json
{
"success": true,
"taskId": "job_abc123",
"status": "queued"
}
```
Poll the [Get Job Status](/api-reference/workflows/getJobStatus) endpoint until the status is `completed` or `failed`:
```bash
curl https://www.sim.ai/api/jobs/{taskId} \
-H "X-API-Key: YOUR_API_KEY"
```
<Callout type="info">
Job status transitions follow: `queued` → `processing` → `completed` or `failed`. The `output` field is only present when status is `completed`.
</Callout>
## Response Format
Successful responses include an `output` object with your workflow results and a `limits` object with your current rate limit and usage status:
```json
{
"success": true,
"output": {
"result": "Hello, world!"
},
"limits": {
"workflowExecutionRateLimit": {
"sync": {
"requestsPerMinute": 60,
"maxBurst": 10,
"remaining": 59,
"resetAt": "2025-01-01T00:01:00Z"
},
"async": {
"requestsPerMinute": 30,
"maxBurst": 5,
"remaining": 30,
"resetAt": "2025-01-01T00:01:00Z"
}
},
"usage": {
"currentPeriodCost": 1.25,
"limit": 50.00,
"plan": "pro",
"isExceeded": false
}
}
}
```
## Error Handling
The API uses standard HTTP status codes. Error responses include a human-readable `error` message:
```json
{
"error": "Workflow not found"
}
```
| Status | Meaning | What to do |
| --- | --- | --- |
| `400` | Invalid request parameters | Check the `details` array for specific field errors |
| `401` | Missing or invalid API key | Verify your `X-API-Key` header |
| `403` | Access denied | Check you have permission for this resource |
| `404` | Resource not found | Verify the ID exists and belongs to your workspace |
| `429` | Rate limit exceeded | Wait for the duration in the `Retry-After` header |
<Callout type="info">
Use the [Get Usage Limits](/api-reference/usage/getUsageLimits) endpoint to check your current rate limit status and billing usage at any time.
</Callout>
## Rate Limits
Rate limits depend on your subscription plan and apply separately to synchronous and asynchronous executions. Every execution response includes a `limits` object showing your current rate limit status.
When rate limited, the API returns a `429` response with a `Retry-After` header indicating how many seconds to wait before retrying.
## Pagination
List endpoints (workflows, logs, audit logs) use **cursor-based pagination**:
```bash
# First page
curl "https://www.sim.ai/api/v1/logs?limit=20" \
-H "X-API-Key: YOUR_API_KEY"
# Next page — use the nextCursor from the previous response
import { Callout } from 'fumadocs-ui/components/callout'
import { Card, Cards } from 'fumadocs-ui/components/card'
import { Step, Steps } from 'fumadocs-ui/components/steps'
import { Tab, Tabs } from 'fumadocs-ui/components/tabs'
Das offizielle Python SDK für Sim ermöglicht es Ihnen, Workflows programmatisch aus Ihren Python-Anwendungen heraus mit dem offiziellen Python SDK auszuführen.
<Callout type="info">
Das Python SDK unterstützt Python 3.8+ mit Unterstützung für asynchrone Ausführung, automatischer Ratenbegrenzung mit exponentiellem Backoff und Nutzungsverfolgung.
</Callout>
## Installation
Installieren Sie das SDK mit pip:
```bash
pip install simstudio-sdk
```
## Schnellstart
Hier ist ein einfaches Beispiel für den Einstieg:
```python
from simstudio import SimStudioClient
# Initialize the client
client = SimStudioClient(
api_key="your-api-key-here",
base_url="https://sim.ai" # optional, defaults to https://sim.ai
Die Wiederholungslogik verwendet exponentielles Backoff (1s → 2s → 4s → 8s...) mit ±25% Jitter, um Thundering Herd zu verhindern. Wenn die API einen `retry-after`-Header bereitstellt, wird dieser stattdessen verwendet.
##### get_rate_limit_info()
Ruft die aktuellen Rate-Limit-Informationen aus der letzten API-Antwort ab.
Navigieren Sie zu [Sim](https://sim.ai) und melden Sie sich in Ihrem Konto an.
</Step>
<Step title="Workflow öffnen">
Navigieren Sie zu dem Workflow, den Sie programmatisch ausführen möchten.
</Step>
<Step title="Workflow bereitstellen">
Klicken Sie auf "Bereitstellen", um Ihren Workflow bereitzustellen, falls dies noch nicht geschehen ist.
</Step>
<Step title="API-Schlüssel erstellen oder auswählen">
Wählen oder erstellen Sie während des Bereitstellungsprozesses einen API-Schlüssel.
</Step>
<Step title="API-Schlüssel kopieren">
Kopieren Sie den API-Schlüssel, um ihn in Ihrer Python-Anwendung zu verwenden.
</Step>
</Steps>
## Voraussetzungen
- Python 3.8+
- requests >= 2.25.0
## Lizenz
Apache-2.0
Some files were not shown because too many files have changed in this diff
Show More
Reference in New Issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.