Compare commits

..

342 Commits

Author SHA1 Message Date
Siddharth Ganesan
160aa7b664 Fix handler 2026-03-14 11:31:11 -07:00
Siddharth Ganesan
cd055842e3 Fix lint 2026-03-13 20:44:59 -07:00
Siddharth Ganesan
2c85dea590 Context tags 2026-03-13 20:44:35 -07:00
waleed
ab939eb7dd 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>
2026-03-13 20:42:28 -07:00
waleed
e0af69c2ef 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>
2026-03-13 20:39:58 -07:00
Theodore Li
7ad813b554 Add download file shortcut on mothership file view 2026-03-13 20:32:48 -07:00
Siddharth Ganesan
7501ab15bb Fix fast edit 2026-03-13 20:19:34 -07:00
waleed
d7a1353975 fix build, speedup tests by up to 40% 2026-03-13 20:04:55 -07:00
Emir Karabeg
7cc013e523 subagent thinking text 2026-03-13 20:04:45 -07:00
waleed
9953fda800 clamp logs panel 2026-03-13 19:44:52 -07:00
waleed
ed7ac935e4 reactquery best practices, UI alignment in restore 2026-03-13 19:34:44 -07:00
Emir Karabeg
709f91fd29 improvements: ui/ux around mothership 2026-03-13 19:15:49 -07:00
Siddharth Ganesan
0c9ab10b12 Lint 2026-03-13 19:09:33 -07:00
Vikhyath Mondreti
39477d970b Merge branch 'feat/mothership-copilot' of github.com:simstudioai/sim into feat/mothership-copilot 2026-03-13 19:04:41 -07:00
Vikhyath Mondreti
afaad519d9 fix type errors 2026-03-13 19:04:28 -07:00
Theodore Li
f5ae4686a2 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>
2026-03-13 22:03:40 -04:00
waleed
22c2571661 standardize back buttons in settings 2026-03-13 18:43:35 -07:00
waleed
4f21ceb049 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>
2026-03-13 18:41:03 -07:00
Vikhyath Mondreti
af434a121f Merge branch 'staging' into feat/mothership-copilot 2026-03-13 18:40:36 -07:00
Waleed
54e14f47f9 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>
2026-03-13 18:20:19 -07:00
waleed
cbe8fe300d 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>
2026-03-13 17:03:44 -07:00
waleed
4948fc8af2 upgrade turbo 2026-03-13 16:49:55 -07:00
waleed
1d36de26a0 updated docs styling, added FAQs, updated content 2026-03-13 16:47:36 -07:00
Siddharth Ganesan
b2919baa8e Fix fast edit route 2026-03-13 15:33:37 -07:00
waleed
dd314decf8 update docs styling, add delete confirmation on inbox 2026-03-13 15:18:01 -07:00
Theodore Li
5ba7a7e53a 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>
2026-03-13 14:36:45 -07:00
waleed
0de4f73e75 added docs for sim mailer 2026-03-13 13:13:41 -07:00
waleed
f9db9c0e33 added agentmail domain for mailer 2026-03-13 13:07:42 -07:00
waleed
5ad18083cc 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>
2026-03-13 13:01:00 -07:00
waleed
56ac18021b 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>
2026-03-13 13:00:46 -07:00
waleed
41674dedf3 cleanup resource definition 2026-03-13 12:46:19 -07:00
waleed
f2a5694298 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>
2026-03-13 12:38:39 -07:00
waleed
9171973c7e 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>
2026-03-13 12:15:31 -07:00
waleed
2f7b90b117 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>
2026-03-13 12:12:44 -07:00
waleed
85c5da62ff 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>
2026-03-13 12:08:53 -07:00
Siddharth Ganesan
f33cf83fc5 Kb args 2026-03-13 11:39:58 -07:00
Waleed
33bb01bccb 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>
2026-03-13 03:20:35 -07:00
Vikhyath Mondreti
6a71daf77f 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
2026-03-13 02:34:45 -07:00
Theodore Li
8dbdebd01b 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>
2026-03-13 04:32:37 -04:00
Theodore Li
2d8899b2ff 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>
2026-03-13 01:08:31 -04:00
Emir Karabeg
7a1b0a99e6 reverted task logic 2026-03-12 21:09:00 -07:00
Emir Karabeg
0ba69d5992 improvement: notifications, terminal, globals 2026-03-12 21:03:06 -07:00
Emir Karabeg
3613a3aef6 improvement(ui): dropdown menus, icons, globals 2026-03-12 20:03:11 -07:00
Theodore Li
af35717a89 Fix new resource tab button not appearing on tasks 2026-03-12 19:58:06 -07:00
Theodore Li
295978a38b 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>
2026-03-12 22:36:37 -04:00
Waleed
b7c76888c7 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
2026-03-12 18:32:15 -07:00
Waleed
7bd03cfb33 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>
2026-03-12 18:13:15 -07:00
Siddharth Ganesan
3ab5ca0596 Credential id field 2026-03-12 13:55:23 -07:00
Siddharth Ganesan
cc9399dfbf Credential tags 2026-03-12 13:53:04 -07:00
Vikhyath Mondreti
0dd70b78d9 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
2026-03-12 13:43:37 -07:00
Theodore Li
6b3ca1f4c1 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>
2026-03-12 15:56:44 -04:00
Waleed
5d57faf050 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>
2026-03-12 12:46:50 -07:00
Waleed
0aeb860f6e 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>
2026-03-12 12:41:41 -07:00
waleed
bb944d6a54 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>
2026-03-12 10:50:36 -07:00
Vikhyath Mondreti
1413d8a47c Merge branch 'feat/mothership-copilot' of github.com:simstudioai/sim into feat/mothership-copilot 2026-03-12 10:02:34 -07:00
Theodore Li
f7acc18690 fix(agent) subagent and main agent text being merged without spacing 2026-03-11 20:52:28 -07:00
Vikhyath Mondreti
60e326f043 edit existing workflow should bring up artifact 2026-03-11 19:01:58 -07:00
Emir Karabeg
4df7e78019 fix: chat scrollbar on sidebar collapse/open 2026-03-11 18:56:07 -07:00
Theodore Li
1266a66838 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>
2026-03-11 21:51:06 -04:00
Theodore Li
68909e71d0 fix(import) fix missing file 2026-03-11 18:41:49 -07:00
Theodore Li
c2bf65fcf1 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>
2026-03-11 21:28:32 -04:00
waleed
8927807398 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>
2026-03-11 17:55:28 -07:00
waleed
38ee79da85 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>
2026-03-11 17:47:20 -07:00
waleed
28c8afcb96 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>
2026-03-11 16:55:02 -07:00
waleed
511e3a9011 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>
2026-03-11 16:45:03 -07:00
waleed
6fd871268e 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>
2026-03-11 16:28:03 -07:00
Emir Karabeg
26d62fc176 improvement: schedules, auto-scroll 2026-03-11 15:01:00 -07:00
Theodore Li
1628ffea40 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>
2026-03-11 17:36:28 -04:00
Emir Karabeg
95efa50f69 improvement: home, sidebar 2026-03-11 14:28:57 -07:00
Theodore Li
a29717e7aa fix(remove-speed-hosted-key) Remove maps speed limit hosted key, it's deprecated (#3521)
Co-authored-by: Theodore Li <theo@sim.ai>
2026-03-11 16:24:51 -04:00
Theodore Li
f161c261ef feat(resource-tab-scroll): Allow vertical scrolling to scroll resource tab 2026-03-11 13:07:15 -07:00
Theodore Li
d347b8c4af 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>
2026-03-11 15:59:56 -04:00
Vikhyath Mondreti
10e8eeda67 fix plan display name 2026-03-11 11:11:27 -07:00
Vikhyath Mondreti
7bd2562c99 fix stale query 2026-03-11 11:04:02 -07:00
Vikhyath Mondreti
982e84cbd9 fix tests 2026-03-11 10:56:02 -07:00
Vikhyath Mondreti
767006b1e6 fix(mothership): lint (#3517)
* fix(mothership): lint

* fix typing
2026-03-11 10:46:25 -07:00
Theodore Li
69820a486a Fix workspace dropdown getting cut off when sidebar is collapsed 2026-03-11 10:06:01 -07:00
waleed
aed74b9573 added back integrations page, reverted secrets page back to old UI 2026-03-11 06:44:27 -07:00
waleed
dc17b9642f autofill fixes 2026-03-11 04:56:31 -07:00
waleed
6fed0195fd fix(home): prevent initial view from being scrollable
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-11 04:46:48 -07:00
waleed
95557bda79 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>
2026-03-11 04:45:02 -07:00
Emir Karabeg
079c7caec3 feat(templates): create home templates 2026-03-11 04:15:01 -07:00
Emir Karabeg
f86e67dbf3 improvement: loading and file dropping 2026-03-11 03:15:19 -07:00
Emir Karabeg
c8098d38e3 improvement: chat 2026-03-11 02:35:36 -07:00
Emir Karabeg
00eb812365 improvement: panel, special tags 2026-03-10 23:43:25 -07:00
waleed
75d2dabafc fix(font): added back old font for emcn code editor 2026-03-10 23:41:06 -07:00
waleed
f5eb76c703 fix(diff-controls): fixed positioning for copilot diff controls 2026-03-10 23:37:17 -07:00
Siddharth Ganesan
b024d63dbf Update oauth cred tool 2026-03-10 23:35:10 -07:00
waleed
aa3be4b1d0 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>
2026-03-10 23:25:57 -07:00
Vikhyath Mondreti
4509a75a02 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
2026-03-10 23:10:37 -07:00
Emir Karabeg
b34bb643a5 improvement: search modal 2026-03-10 22:54:12 -07:00
waleed
1de25af341 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>
2026-03-10 22:43:45 -07:00
waleed
5d308b3529 fix(mothership): fix hardcoded workflow color, tables drag line overflowing 2026-03-10 22:43:21 -07:00
Emir Karabeg
0bb756be34 ran migrations 2026-03-10 22:31:05 -07:00
Emir Karabeg
3c0da7671a improvement: modals 2026-03-10 22:30:35 -07:00
Theodore Li
a4ac7155f2 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>
2026-03-11 01:01:31 -04:00
Waleed
89dafb3b47 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
2026-03-10 21:42:52 -07:00
Emir Karabeg
87e2910e19 improvement: thinking 2026-03-10 21:29:08 -07:00
Emir Karabeg
f780aaffc6 improvement(ux): streaming 2026-03-10 21:08:43 -07:00
Siddharth Ganesan
a4e5e30c1a Don't drop suabgent text 2026-03-10 20:50:42 -07:00
Siddharth Ganesan
f448134618 Subagent tool call persistence 2026-03-10 20:34:58 -07:00
Emir Karabeg
7b53137d22 fix(sidebar): task navigation 2026-03-10 19:48:57 -07:00
Emir Karabeg
c0c139cccf fix(sidebar): workspace header collapse 2026-03-10 19:45:42 -07:00
Siddharth Ganesan
9854e43687 Plan prompt 2026-03-10 19:45:21 -07:00
Siddharth Ganesan
663524971c Usage limit 2026-03-10 19:40:10 -07:00
Emir Karabeg
80830f5311 improvement: sidebar, chat 2026-03-10 19:35:38 -07:00
Theodore Li
7151e81fff 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>
2026-03-10 22:34:29 -04:00
Vikhyath Mondreti
5815d9f556 fix(credentials): autosync behaviour cross workspace (#3511)
* fix(credentials): autosync behaviour cross workspace

* address comments
2026-03-10 19:23:44 -07:00
waleed
e6c511a6f3 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>
2026-03-10 19:02:17 -07:00
Siddharth Ganesan
a1f917d552 Fix tests 2026-03-10 18:49:19 -07:00
Siddharth Ganesan
3b7fc9a971 Fix tool call ordering 2026-03-10 18:34:10 -07:00
waleed
ab1205efec 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>
2026-03-10 18:29:13 -07:00
waleed
aa0ce77005 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>
2026-03-10 18:07:56 -07:00
Siddharth Ganesan
fdf4f033ad Fixes 2026-03-10 18:06:42 -07:00
Theodore Li
5a86b4e979 Fix schema mismatch (#3510)
Co-authored-by: Theodore Li <theo@sim.ai>
2026-03-10 20:31:25 -04:00
Emir Karabeg
2587406b2a chat metadata 2026-03-10 17:27:48 -07:00
Emir Karabeg
18dacc53bf improvement: chat, workspace header 2026-03-10 16:49:25 -07:00
waleed
4a135aa871 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>
2026-03-10 16:48:31 -07:00
Siddharth Ganesan
b5c2070baf Fix signaling 2026-03-10 16:47:57 -07:00
waleed
865108109f 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>
2026-03-10 16:15:37 -07:00
Vikhyath Mondreti
5362f7417f feat(autosave): files and chunk editor autosave with debounce + refetch (#3508)
* feat(files): debounced autosave while editing

* address review comments

* more comments
2026-03-10 15:36:00 -07:00
waleed
de36e332d7 fix dysfunctional unique operation in tables 2026-03-10 14:56:44 -07:00
Waleed
2afe917e4e 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>
2026-03-10 14:37:49 -07:00
Siddharth Ganesan
6f694e5201 Update vfs to handle hosted keys 2026-03-10 14:23:39 -07:00
Theodore Li
fa1ae1398e 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>
2026-03-10 16:53:56 -04:00
Siddharth Ganesan
6db8bc4934 Add piping 2026-03-10 12:36:28 -07:00
Vikhyath Mondreti
9ca539b626 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
2026-03-10 12:23:45 -07:00
Siddharth Ganesan
4751612b5f Make mothership block use long input instead of prompt input 2026-03-10 11:06:03 -07:00
Siddharth Ganesan
2e8e578ede Streaming fix -- need to test more 2026-03-10 11:01:14 -07:00
Waleed
8afa184c64 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>
2026-03-10 01:55:54 -07:00
Emir Karabeg
9b10e4464e fix: copilot, improvement: tables, mothership 2026-03-09 21:52:57 -07:00
waleed
5c6797a0bd revert hardcoded ff 2026-03-09 21:09:29 -07:00
waleed
57f5f6e59a 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.
2026-03-09 21:08:24 -07:00
waleed
f26a375f3c chore: lint fixes 2026-03-09 20:59:46 -07:00
waleed
1cb8a28727 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
2026-03-09 20:59:18 -07:00
waleed
f62fddfac5 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.
2026-03-09 20:45:35 -07:00
waleed
5184580dbd Merge branch 'improvement/settings-perf' into feat/mothership-copilot 2026-03-09 20:35:39 -07:00
waleed
1aa9dc9ea7 fix(settings): use emcn Input for file input in general settings 2026-03-09 20:34:52 -07:00
waleed
37a1d66127 fix(byok): use ui Input for search bar to match other settings pages 2026-03-09 20:33:03 -07:00
waleed
5a5bf5ca7e 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.
2026-03-09 20:29:45 -07:00
waleed
4ccc1e5997 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.
2026-03-09 20:29:06 -07:00
waleed
80f032b9be update byok page 2026-03-09 20:22:45 -07:00
waleed
63927e5afc 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.
2026-03-09 20:21:43 -07:00
waleed
ab61f5188c fix(settings): use emcn Skeleton in extracted skeleton files 2026-03-09 20:09:19 -07:00
waleed
94914b848e 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>
2026-03-09 20:07:27 -07:00
waleed
4c7e63cf7a improvement(settings): SSR prefetch, code splitting, dedicated skeletons 2026-03-09 20:01:29 -07:00
Theodore Li
8fc75a6e9d 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>
2026-03-09 22:56:45 -04:00
Vikhyath Mondreti
9400df6085 Merge branch 'feat/mothership-copilot' of github.com:simstudioai/sim into feat/mothership-copilot 2026-03-09 19:23:06 -07:00
Vikhyath Mondreti
d23afb97c5 fix(credentials): block usage at execution layer without perms + fix invites 2026-03-09 19:22:35 -07:00
Siddharth Ganesan
1ff89cd416 Table batch ops 2026-03-09 19:04:30 -07:00
waleed
b7a6fe574c small table rename bug, files updates not persisting 2026-03-09 18:38:40 -07:00
Siddharth Ganesan
8abe717b85 Fix table column delete 2026-03-09 18:25:07 -07:00
Emir Karabeg
d815568315 improvement: tables, chat 2026-03-09 18:23:52 -07:00
waleed
5dc026c72e upgrade turbo 2026-03-09 18:22:20 -07:00
waleed
86b67823ce update docs 2026-03-09 18:21:53 -07:00
Vikhyath Mondreti
65448766fc Merge branch 'feat/mothership-copilot' of github.com:simstudioai/sim into feat/mothership-copilot 2026-03-09 18:03:49 -07:00
Vikhyath Mondreti
9098f0b805 fix(credentials): exclude regular login methods from credential sync 2026-03-09 18:03:25 -07:00
waleed
78e3d840dd updated document icon 2026-03-09 18:00:26 -07:00
waleed
09af6fb33d improve resizer for file preview for html files 2026-03-09 17:48:01 -07:00
Emir Karabeg
523aff8ab0 improvements(tables): styling improvements 2026-03-09 17:46:27 -07:00
Emir Karabeg
4fe9509e70 styling alignment 2026-03-09 17:46:27 -07:00
Emir Karabeg
9a1cb10d7a improvement(ui): consistent styling 2026-03-09 17:46:27 -07:00
Theodore Li
898f8ce1c1 feat(exa-hosted-key): Restore exa hosted key (#3499)
Co-authored-by: Theodore Li <theo@sim.ai>
2026-03-09 20:40:54 -04:00
Waleed
39334bdf7d fix(tables): one small tables ting (#3497) 2026-03-09 16:43:15 -07:00
Waleed
a6d3b3a9ad 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>
2026-03-09 16:37:48 -07:00
Emir Karabeg
8fd8b1a248 improvement(mothership): chat history and stability 2026-03-09 15:57:13 -07:00
Emir Karabeg
917af6d141 improvement(mothership): chat stability 2026-03-09 15:42:12 -07:00
Vikhyath Mondreti
fe5f809e1a Merge branch 'feat/mothership-copilot' of github.com:simstudioai/sim into feat/mothership-copilot 2026-03-09 15:28:07 -07:00
Vikhyath Mondreti
2f2c2b05e8 feat(templates): landing page templates workflow states 2026-03-09 15:22:14 -07:00
Siddharth Ganesan
0c44332172 File uploads to mothership 2026-03-09 15:19:56 -07:00
Siddharth Ganesan
7c0cd36936 Fix error status 2026-03-09 14:30:46 -07:00
Siddharth Ganesan
2788c68e45 Tool results 2026-03-09 14:24:44 -07:00
Siddharth Ganesan
cf9cc0377d Fix tool call persistence in chat 2026-03-09 14:24:44 -07:00
Emir Karabeg
a091149da4 improvement(mothership): worklfow resource 2026-03-09 14:20:59 -07:00
Waleed
64cedfcff7 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
2026-03-09 13:27:33 -07:00
Vikhyath Mondreti
15db69231f fix tests 2026-03-09 12:22:40 -07:00
Vikhyath Mondreti
7b43091984 Merge branch 'feat/mothership-copilot' of github.com:simstudioai/sim into feat/mothership-copilot 2026-03-09 12:13:34 -07:00
Emir Karabeg
48f280427e feat(mothership): resource viewer 2026-03-09 12:07:06 -07:00
Vikhyath Mondreti
1430eb66de fix(landing): wire agent input to mothership 2026-03-09 11:58:16 -07:00
Siddharth Ganesan
2ace7252f9 Store tool call results 2026-03-09 11:35:20 -07:00
Siddharth Ganesan
bcdfc85ccb Tool updates 2026-03-09 11:28:22 -07:00
Vikhyath Mondreti
e921448bf2 fix(selections): more nested folder inaccuracies 2026-03-09 11:17:43 -07:00
Vikhyath Mondreti
71d8e227bd improvement(folder-selection): folder deselection + selection order should match visual 2026-03-09 11:00:22 -07:00
Siddharth Ganesan
4593a8a471 Table tools 2026-03-09 10:21:12 -07:00
Emir Karabeg
301fdb94ff improvement(tables): multi-select and efficiencies 2026-03-09 10:07:21 -07:00
Emir Karabeg
4afc3bbff8 improvement: logs 2026-03-09 09:13:01 -07:00
waleed
76981c356f update schedule creation ui and run lint 2026-03-09 02:18:43 -07:00
Waleed
4c562c8e04 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>
2026-03-09 02:14:38 -07:00
Emir Karabeg
d4eb25df91 fix(files): icon 2026-03-09 02:12:27 -07:00
Emir Karabeg
ac2af53884 improvement: icons 2026-03-09 02:10:54 -07:00
Emir Karabeg
016d353baf improvement: icon, resource header options 2026-03-09 01:47:08 -07:00
Emir Karabeg
d9c1a53cad improvement(resource): layout 2026-03-09 01:20:50 -07:00
Waleed
2bdc073d7b 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>
2026-03-09 00:50:28 -07:00
Waleed
13d2a134d0 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>
2026-03-09 00:22:09 -07:00
Emir Karabeg
a61dc23d43 improvement: tables, dropdown 2026-03-09 00:17:52 -07:00
Waleed
12c1ede336 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>
2026-03-09 00:07:35 -07:00
Emir Karabeg
627eaaf343 improvement: tables, favicon 2026-03-08 19:21:21 -07:00
Waleed Latif
1dbfaa4d23 style(schedules): apply linter formatting 2026-03-08 18:41:29 -07:00
Waleed Latif
4946571922 feat(schedules): add edit support with context menu for standalone jobs 2026-03-08 18:41:17 -07:00
Waleed Latif
6295fd1a11 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>
2026-03-08 18:17:11 -07:00
Emir Karabeg
de5faa5265 improvement(tables): consolidation 2026-03-08 17:31:58 -07:00
Waleed
7d360649e9 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
2026-03-08 16:16:14 -07:00
Vikhyath Mondreti
1d955fc43a 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
2026-03-08 03:37:54 -07:00
Waleed
1def94392b 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
2026-03-07 22:59:29 -08:00
Emir Karabeg
77bd2553f2 fix(resource): sorting 2026-03-07 21:26:54 -08:00
Emir Karabeg
8170488488 improvement(resource): sorting and icons 2026-03-07 21:19:04 -08:00
Waleed
0b42e26f10 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.
2026-03-07 21:09:31 -08:00
Emir Karabeg
4b7a9b20c4 improvement(resources): segmented API 2026-03-07 20:48:08 -08:00
Waleed
76486ebcc8 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>
2026-03-07 20:00:38 -08:00
Emir Karabeg
13d49da8bd improvement(resources): layout and items 2026-03-07 18:01:29 -08:00
Waleed
05b8481a89 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.
2026-03-07 16:55:06 -08:00
Emir Karabeg
6690c55721 improvement(resource): layout 2026-03-07 16:25:53 -08:00
Siddharth Ganesan
88a8c5f4a1 Update mothership to match copilot in logs 2026-03-07 16:18:34 -08:00
Siddharth Ganesan
91ca6a531e Fix tables row count 2026-03-07 16:04:36 -08:00
Emir Karabeg
2f45f935e4 ran lint 2026-03-07 15:47:53 -08:00
Waleed
2cb12de546 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>
2026-03-07 15:15:10 -08:00
Emir Karabeg
de32644940 improvement(resources): all outer page structure complete 2026-03-07 14:42:11 -08:00
Emir Karabeg
8ff93fe842 improvement(resource): tables, files 2026-03-07 13:42:22 -08:00
Waleed
0d9e04181f 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
2026-03-07 13:08:26 -08:00
Waleed
1324987def 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
2026-03-07 12:38:46 -08:00
Waleed
9c4abf7b9b 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.
2026-03-07 12:12:15 -08:00
Siddharth Ganesan
00c9b72bdd Fix lint 2026-03-07 12:06:12 -08:00
Siddharth Ganesan
386df7a062 Fix 2026-03-07 11:47:53 -08:00
Siddharth Ganesan
0967755ad4 Clean vfs 2026-03-07 11:29:20 -08:00
Siddharth Ganesan
b50ccdf314 Fixes 2026-03-07 11:14:13 -08:00
Siddharth Ganesan
7247a5f4d8 Fixes 2026-03-07 10:43:41 -08:00
Waleed Latif
875498c9aa 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>
2026-03-07 09:49:57 -08:00
Waleed Latif
3c196d180f lint 2026-03-07 01:45:56 -08:00
Waleed Latif
2940de946c 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>
2026-03-07 01:38:05 -08:00
Waleed Latif
212f912827 Merge staging into feat/mothership-copilot
Resolved conflicts:
- oauth-required-modal.tsx: removed local SCOPE_DESCRIPTIONS (moved to lib/oauth/utils)
- credential-selector.tsx (2 files): kept useSettingsNavigation import, removed duplicate getMissingRequiredScopes
- airtable.ts: combined HEAD's dependsOn/getSchema with staging's mode:'advanced'

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-07 01:25:48 -08:00
Emir Karabeg
9a505919b0 refactor, improvement 2026-03-06 23:44:34 -08:00
Waleed
e6ca3b3311 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
2026-03-06 17:58:33 -08:00
Waleed
b93c87c521 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>
2026-03-06 17:46:42 -08:00
Siddharth Ganesan
06a4a8162a Add context 2026-03-06 17:11:18 -08:00
Waleed
96c2ae2c39 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>
2026-03-06 16:48:39 -08:00
Theodore Li
1e53d5748a Fix oauth link callback from mothership task 2026-03-06 13:46:08 -08:00
Waleed Latif
6d803bcde2 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>
2026-03-06 13:08:14 -08:00
Waleed Latif
bca131d597 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>
2026-03-06 12:55:06 -08:00
Waleed Latif
0202c60d26 Revert "fix(connectors): remove legacy requiredScopes from Jira and Confluence connectors"
This reverts commit a0be3ff414.
2026-03-06 12:52:29 -08:00
Waleed
82ba3d7dd1 feat(tasks): add rename to task context menu (#3442) 2026-03-06 12:49:32 -08:00
Waleed Latif
a0be3ff414 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.
2026-03-06 12:44:46 -08:00
Waleed Latif
6cda9e60e8 fix(connectors): remove unverifiable requiredScopes for Linear connector 2026-03-06 12:40:15 -08:00
Siddharth Ganesan
a6abb9da67 Job logs 2026-03-06 12:30:33 -08:00
Siddharth Ganesan
777e4f57de Job exeuction logs 2026-03-06 11:34:48 -08:00
Waleed
695628de75 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
2026-03-06 11:29:28 -08:00
Siddharth Ganesan
d71e4e51ea Fix mothership block logs 2026-03-06 10:57:16 -08:00
Siddharth Ganesan
576d9d3025 Mothership block logs 2026-03-06 10:46:30 -08:00
Waleed
43509374a2 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.
2026-03-06 06:35:19 -08:00
Emir Karabeg
0e7c719e82 improvement(sidebar): loading 2026-03-06 02:35:24 -08:00
Siddharth Ganesan
226a3f64fb Fix lint 2026-03-05 22:10:27 -08:00
Siddharth Ganesan
6c6b3579c9 Triggers in the vfs 2026-03-05 20:57:58 -08:00
Siddharth Ganesan
a5b148e19e Native kb connectors 2026-03-05 20:17:23 -08:00
Emir Karabeg
9665f49492 fix(workflow): editor visible 2026-03-05 20:07:44 -08:00
Waleed Latif
ff4b2f8c6a lint 2026-03-05 19:38:51 -08:00
Waleed Latif
4735245c8f feat(tables): inline cell editing with optimistic updates 2026-03-05 19:37:06 -08:00
Waleed
aac9e74283 feat(knowledge): add 10 new knowledge base connectors (#3430)
* feat(knowledge): add 10 new knowledge base connectors

Add connectors for Dropbox, OneDrive, SharePoint, Slack, Google Docs,
Asana, HubSpot, Salesforce, WordPress, and Webflow. Each connector
implements listDocuments, getDocument, validateConfig with proper
pagination, content hashing, and tag definitions.

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

* fix(connectors): address audit findings across 5 connectors

OneDrive: fix encodeURIComponent breaking folder paths with slashes,
add recursive folder traversal via folder queue in cursor state.
Slack: add missing requiredScopes.
Asana: pass retryOptions as 3rd arg to fetchWithRetry instead of
spreading into RequestInit; add missing requiredScopes.
HubSpot: add missing requiredScopes; fix sort property to use
hs_lastmodifieddate for non-contact object types.
Google Docs: remove orphaned title tag that was never populated.

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

* fix(connectors): add missing requiredScopes to OneDrive and HubSpot

OneDrive: add requiredScopes: ['Files.Read']
HubSpot: add missing crm.objects.tickets.read scope

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

* chore(connectors): lint fixes

* fix(connectors): slice documents to respect max limit on last page

* fix(connectors): use per-segment encodeURIComponent for SharePoint folder paths

encodeURI does not encode #, ?, &, + or = which are valid in folder
names but break the Microsoft Graph URL. Apply the same per-segment
encoding fix already used in the OneDrive connector.

* fix(connectors): address PR review findings

- Slack: remove private_channel from conversations.list types param
  since requiredScopes only cover public channels (channels:read,
  channels:history). Adding groups:read/groups:history would force
  all users to grant private channel access unnecessarily.
- OneDrive/SharePoint: add .htm to supported extensions and handle
  it in content processing (htmlToPlainText), matching Dropbox.
- Salesforce: guard getDocument for KnowledgeArticleVersion to skip
  records that are no longer PublishStatus='Online', preventing
  un-published articles from being re-synced.

* fix(connectors): pre-download size check and remove dead parameter

- OneDrive/SharePoint: add file size check against MAX_FILE_SIZE before
  downloading, matching Dropbox's behavior. Prevents OOM on large files.
- Slack: remove unused syncContext parameter from fetchChannelMessages.

* fix(connectors): slack getDocument user cache & wordpress scope reduction

- Slack: pass a local syncContext to formatMessages in getDocument so
  resolveUserName caches user lookups across messages. Without this,
  every message triggered a fresh users.info API call.
- WordPress: replace 'global' scope with 'posts' and 'sites' following
  principle of least privilege. The connector only reads posts and
  validates site existence.

* fix(connectors): revert wordpress scope and slack local cache changes

- WordPress: revert requiredScopes to ['global'] — the scope check
  does literal string matching, so ['posts', 'sites'] would always
  fail since auth.ts requests 'global' from WordPress.com OAuth.
  Reducing scope requires changing both auth.ts and the connector.
- Slack: remove local syncContext from getDocument — the perf impact
  of uncached users.info calls is negligible for typical channels
  (bounded by unique users, not message count).

* fix(connectors): align requiredScopes with auth.ts registrations

The scope check in getMissingRequiredScopes does literal string matching
against the OAuth token's granted scopes. requiredScopes must match what
auth.ts actually requests (since that's what the provider returns).

- HubSpot: use 'tickets' (legacy scope in auth.ts) instead of
  'crm.objects.tickets.read' (v3 granular scope not requested)
- Google Docs: use 'drive' (what auth.ts requests) instead of
  'documents.readonly' and 'drive.readonly' (never requested,
  so never in the granted set)

* fix(connectors): align Google Drive requiredScopes with auth.ts

Google Drive connector required 'drive.readonly' but auth.ts requests
'drive' (the superset). Since scope validation does literal matching,
this caused a spurious 'Additional permissions required' warning.

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-05 19:31:17 -08:00
Siddharth Ganesan
d6b97fee08 Fix lint 2026-03-05 17:37:41 -08:00
Siddharth Ganesan
280ac30d55 Jobs 2026-03-05 17:36:24 -08:00
Siddharth Ganesan
5c24d2422e Jobs 2026-03-05 17:35:38 -08:00
Siddharth Ganesan
9d001eaf70 Jobs 2026-03-05 17:32:36 -08:00
Siddharth Ganesan
17e1bb5331 Nuke migrations 2026-03-05 17:22:40 -08:00
Siddharth Ganesan
443e15eb01 Jobs 2026-03-05 16:43:48 -08:00
Waleed
dbef14ba26 feat(knowledge): connectors, user exclusions, expanded tools & airtable integration (#3230)
* feat(knowledge): connectors, user exclusions, expanded tools & airtable integration

* improvements

* removed redundant util

* ack PR comments

* remove module level cache, use syncContext between paginated calls to avoid redundant schema fetches

* regen migrations, ack PR comments

* ack PR comment

* added tests

* ack comments

* ack comments

* feat(db): add knowledge connector migration after merge

Generated migration 0162 for knowledge_connector and
knowledge_connector_sync_log tables after resolving merge
conflicts with feat/mothership-copilot.

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

* fix(connectors): audit fixes for sync engine, connectors, and knowledge tools

- Extract shared computeContentHash to connectors/utils.ts (dedup across 7 connectors)
- Include error'd connectors in cron auto-retry query
- Add syncContext caching for Confluence (cloudId, spaceId)
- Batch Confluence label fetches with concurrency limit of 10
- Enforce maxPages in Confluence v2 path
- Clean up stale storage files on document update
- Retry stuck documents (pending/failed) after sync completes
- Soft-delete documents and reclaim tag slots on connector deletion
- Add incremental sync support to ConnectorConfig interface
- Fix offset:0 falsy check in list_documents tool

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

* perf(connectors): deep audit — extract shared utils, fix pagination, optimize API calls

- Extract shared htmlToPlainText to connectors/utils.ts (dedup Confluence + Google Drive)
- Add syncContext caching for Jira cloudId, Notion/Linear/Google Drive cumulative limits
- Fix cumulative maxPages/maxIssues/maxFiles enforcement across pagination pages
- Bump Notion page_size from 20 to 100 (5x fewer API round-trips)
- Batch Notion child page fetching with concurrency=5 (was serial N+1)
- Bump Confluence v2 limit from 50 to 250 (v2 API supports it)
- Pass syncContext through Confluence CQL path for cumulative tracking
- Upgrade GitHub tree truncation warning to error level
- Fix sync-engine test mock to include inArray export

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

* refactor(connectors): extract tag helpers, fix Notion maxPages, rewrite broken tests

- Add parseTagDate and joinTagArray helpers to connectors/utils.ts
- Update all 7 connectors to use shared tag mapping helpers (removes 12+ duplication instances)
- Fix Notion listFromParentPage cumulative maxPages check (was using local count)
- Rewrite 3 broken connector route test files to use vi.hoisted() + static vi.mock()
  pattern instead of deprecated vi.doMock/vi.resetModules (all 86 tests now pass)

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

* fix(connectors): add loading skeletons, delete pending state, and pause feedback

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

* fix(knowledge): escape LIKE wildcards, guard restore from un-deleting, fix offset=0

- Escape %, _, \ in tag filter LIKE patterns to prevent incorrect matches
- Add isNull(deletedAt) guard to restore operation to prevent un-deleting soft-deleted docs
- Change offset check from falsy to != null so offset=0 is not dropped

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

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-05 15:40:00 -08:00
Siddharth Ganesan
7140867ff9 Jobs 2026-03-05 15:14:45 -08:00
Siddharth Ganesan
73cd10ca21 Jobs 2 2026-03-05 14:40:49 -08:00
Waleed
a368827f1e feat(api): add tables and files v1 REST API with OpenAPI docs (#3422)
* feat(api): add tables and files v1 REST API with OpenAPI docs

* fix(api): address review feedback for tables/files REST API

* fix(api): reject empty filters, consolidate PUT/DELETE into service helpers

* fix(api): upsert unique constraints, POST response fields, uploadedAt timestamp

* fix(api): stop leaking internal fields in list tables, fix deleteTable requestId

* fix(api): atomic table-count limit in createTable, stop leaking internal fields

* fix(api): error classification in PATCH, z.coerce→preprocess, requestId in logs

* fix(api): audit logging, PATCH service consolidation, Content-Disposition encoding

- Add TABLE_CREATED/TABLE_DELETED audit events to v1 table routes
- Consolidate PATCH handlers to use updateRow service function
- Fix Content-Disposition header with RFC 5987 dual-parameter form
- Normalize schema in POST /tables response with normalizeColumn

* lint

* fix(api): upsert unique constraint 400, guard request.json() parse errors

- Add 'Unique constraint violation' to upsert error classification
- Wrap PUT/DELETE request.json() in try/catch to return 400 on malformed body
- Apply fixes to both v1 and internal routes

* fix(api): guard PATCH request.json(), accurate deleteRowsByIds count

- Wrap PATCH request.json() in try/catch for both v1 and internal routes
- Rewrite deleteRowsByIds to use .returning() for accurate deletedCount
  under concurrent requests (eliminates SELECT-then-DELETE race)

* fix(api): guard all remaining request.json() calls in table routes

- Wrap POST handler request.json() in try/catch across all table routes
- Also fix internal DELETE single-row handler
- Every request.json() in table routes now returns 400 on malformed body

* fix(api): safe type check on formData workspaceId in file upload

- Replace unsafe `as string | null` cast with typeof check
- Prevents File object from bypassing workspaceId validation

* fix(api): safe File cast in upload, validate column name before sql.raw()

- Use instanceof File check instead of unsafe `as File | null` cast
- Add regex validation on column name before sql.raw() interpolation

* fix(api): comprehensive hardening pass across all table/file routes

- Guard request.formData() with try/catch in file upload
- Guard all .toISOString() calls with instanceof Date checks
- Replace verifyTableWorkspace double-fetch with direct comparison
- Fix relative imports to absolute (@/app/api/table/utils)
- Fix internal list tables leaking fields via ...t spread
- Normalize schema in internal POST create table response
- Remove redundant pre-check in internal create (service handles atomically)
- Make 'maximum table limit' return 403 consistently (was 400 in internal)
- Add 'Row not found' → 404 classification in PATCH handlers
- Add NAME_PATTERN validation before sql.raw() in validation.ts

* chore: lint fixes
2026-03-05 13:16:13 -08:00
Siddharth Ganesan
eac8aca0c0 Schedules page for workflows 2026-03-05 10:31:01 -08:00
Siddharth Ganesan
337154054e Oauth link 2026-03-04 17:35:32 -08:00
Siddharth Ganesan
c6ac0b4445 Agent subdir 2026-03-04 16:50:24 -08:00
Waleed
b07925fcc0 feat(settings): migrate settings from modal to route-based pages (#3413) 2026-03-04 15:20:52 -08:00
Siddharth Ganesan
08fb8c1651 Tool perms 2026-03-04 13:44:46 -08:00
Siddharth Ganesan
37337aece5 Scope perms 2026-03-04 12:44:04 -08:00
Siddharth Ganesan
da349176ab Fix merge conflicts 2026-03-04 11:17:01 -08:00
Siddharth Ganesan
6f3559ce8f Fix merge conflicts 2026-03-04 11:15:43 -08:00
Siddharth Ganesan
9a7b5ffe64 Fix merge conflicts 2026-03-04 11:13:42 -08:00
Siddharth Ganesan
4ede071ecb Fix merge conflicts 2026-03-04 11:12:51 -08:00
Siddharth Ganesan
161fb37244 Remove migrations 2026-03-04 10:48:12 -08:00
Emir Karabeg
d1575927a2 improvement(theme): system default 2026-03-04 01:29:47 -08:00
Emir Karabeg
a3b19fb32a improvement(user-input): ui, files 2026-03-03 22:56:07 -08:00
Emir Karabeg
21404d17e8 fix: message stream pickup and task ordering 2026-03-03 17:29:36 -08:00
Siddharth Ganesan
df7e731c9c Add payload 2026-03-03 16:15:01 -08:00
Emir Karabeg
4f4191fe1b fix: task ordering 2026-03-03 15:45:15 -08:00
Emir Karabeg
b57636e5b1 finalized task navigation 2026-03-03 15:24:31 -08:00
Emir Karabeg
38c9ecd259 resolved merge conflicts 2026-03-03 14:49:56 -08:00
Emir Karabeg
fadda6aaef improvement: task routing optimizations 2026-03-03 14:48:43 -08:00
Emir Karabeg
82f541e9de improvement: ui 2026-03-03 14:46:09 -08:00
Siddharth Ganesan
1339915957 Task vfs 2026-03-03 13:12:13 -08:00
Siddharth Ganesan
7fafc00a07 Task management 2026-03-03 12:00:03 -08:00
Emir Karabeg
fe5ab8aee8 improved streaming 2026-03-03 11:40:42 -08:00
Siddharth Ganesan
b3a639a693 Logs 2026-03-03 11:38:06 -08:00
Siddharth Ganesan
0249ca1480 Fix files 2026-03-03 10:49:59 -08:00
Siddharth Ganesan
553c376289 Fix routes 2026-03-03 10:23:11 -08:00
Emir Karabeg
4622966643 improvement(home): interactions 2026-03-02 17:25:32 -08:00
Siddharth Ganesan
e9550c624d Wand 2026-03-02 15:12:59 -08:00
Siddharth Ganesan
1d48289c53 Mothership block pudate 2026-03-02 15:05:56 -08:00
Siddharth Ganesan
fce10241a5 Mothership block 2026-03-02 14:55:04 -08:00
Emir Karabeg
ae080f125c Merge branch 'feat/landing' into feat/mothership-copilot 2026-03-02 13:44:12 -08:00
Emir Karabeg
0fb840c8fd Cleaned up home 2026-03-02 13:39:34 -08:00
Emir Karabeg
2c20519bbd improvement: ui/ux 2026-03-02 12:36:32 -08:00
Siddharth Ganesan
f3474b0c90 Tool call loop 2026-03-02 11:15:17 -08:00
Siddharth Ganesan
b2cc5b6738 Billing 2026-02-28 17:51:26 -08:00
Siddharth Ganesan
d49a2c1c25 Fixes 2026-02-27 15:56:04 -08:00
Siddharth Ganesan
8fa4745893 MCP commented out 2026-02-27 11:18:38 -08:00
Siddharth Ganesan
c168e36a05 Fix 2026-02-26 17:48:53 -08:00
Siddharth Ganesan
9cc46ffa43 Edit subagents 2026-02-26 15:53:58 -08:00
Siddharth Ganesan
cc5e592c46 Kb checkpoint 2026-02-26 14:59:56 -08:00
Siddharth Ganesan
7276136398 Piping 2026-02-26 12:32:09 -08:00
Siddharth Ganesan
3ad7af4b97 File creation 2026-02-25 19:23:24 -08:00
Siddharth Ganesan
3cb1768a44 Move files to separate resource 2026-02-25 18:33:07 -08:00
Siddharth Ganesan
11e6387a7d Fix run workflow 2026-02-25 18:12:13 -08:00
Siddharth Ganesan
57a91027de Fix condition edges 2026-02-25 17:48:33 -08:00
Emir Karabeg
49c29d5f7d feat: pricing, collaboration improvement, features skeleton 2026-02-25 16:28:56 -08:00
Emir Karabeg
843af915bc feat: integrations skeleton, realtime complete 2026-02-25 16:28:56 -08:00
Emir Karabeg
bb3e899f74 feat(landing): template, generic workflow 2026-02-25 16:28:56 -08:00
Emir Karabeg
e47dcdcc43 feat(landing): navbar, metadata, hero, templates header 2026-02-25 16:28:55 -08:00
Emir Karabeg
3e6cf24762 feat(landing): structure 2026-02-25 16:28:55 -08:00
Siddharth Ganesan
90a12546b2 Fix lint 2026-02-25 12:56:58 -08:00
Siddharth Ganesan
b6f8439267 Remove dead code 2026-02-25 12:55:50 -08:00
Siddharth Ganesan
4f74a8b845 Checkpopint 2026-02-25 12:45:55 -08:00
Siddharth Ganesan
f12d8f631f Split 2026-02-25 12:37:23 -08:00
Siddharth Ganesan
41f0957ccc Separation of route 2026-02-25 12:19:26 -08:00
Siddharth Ganesan
7b813be1dd Fix truncation 2026-02-25 11:09:04 -08:00
Siddharth Ganesan
704fa16bb4 run workflow checkpoint 2026-02-25 11:08:44 -08:00
Siddharth Ganesan
eccad2a8ce Remove dup code from tool calls 2026-02-24 16:59:40 -08:00
Siddharth Ganesan
87f5c464d9 Consolidation 2026-02-24 14:55:35 -08:00
Siddharth Ganesan
724aaa1432 table tools 2026-02-24 14:32:55 -08:00
Siddharth Ganesan
3de3ef4786 Readd migration 2026-02-24 14:03:30 -08:00
Siddharth Ganesan
743f048442 Merge with origin staging 2026-02-24 14:02:59 -08:00
Siddharth Ganesan
bbcf346df0 Nuke migration 2026-02-24 13:57:31 -08:00
Siddharth Ganesan
b9c3c2f78f Checkpoint interface consolidation 2026-02-24 13:55:50 -08:00
Siddharth Ganesan
d333307a17 Checkpoint 2026-02-24 13:47:29 -08:00
Siddharth Ganesan
134c4c4f2a Checkpoint 2026-02-24 12:22:19 -08:00
Siddharth Ganesan
03908edcbb Checkpoint 2026-02-19 14:47:57 -08:00
Siddharth Ganesan
3112485c31 Checkpoint 2026-02-19 11:08:32 -08:00
Siddharth Ganesan
459c2930ae Checkpoint 2026-02-19 10:14:24 -08:00
Siddharth Ganesan
3338b25c30 Checkpoint 2026-02-18 18:55:10 -08:00
Siddharth Ganesan
4c3002f97d Checkpoint 2026-02-18 18:38:37 -08:00
Siddharth Ganesan
632e0e0762 Checkpoitn 2026-02-18 15:29:58 -08:00
Siddharth Ganesan
7599774974 Checkpoint 2026-02-17 18:54:15 -08:00
Siddharth Ganesan
471e58a2d0 Checkpoint 2026-02-17 17:04:34 -08:00
Siddharth Ganesan
231ddc59a0 V0 2026-02-17 16:07:55 -08:00
Siddharth Ganesan
b197f68828 v0 2026-02-17 15:28:23 -08:00
1405 changed files with 27158 additions and 163942 deletions

View File

@@ -19,7 +19,7 @@ When the user asks you to create a block:
```typescript
import { {ServiceName}Icon } from '@/components/icons'
import type { BlockConfig } from '@/blocks/types'
import { AuthMode, IntegrationType } from '@/blocks/types'
import { AuthMode } from '@/blocks/types'
import { getScopesForService } from '@/lib/oauth/utils'
export const {ServiceName}Block: BlockConfig = {
@@ -29,8 +29,6 @@ export const {ServiceName}Block: BlockConfig = {
longDescription: 'Detailed description for docs',
docsLink: 'https://docs.sim.ai/tools/{service}',
category: 'tools', // 'tools' | 'blocks' | 'triggers'
integrationType: IntegrationType.X, // Primary category (see IntegrationType enum)
tags: ['oauth', 'api'], // Cross-cutting tags (see IntegrationTag type)
bgColor: '#HEXCOLOR', // Brand color
icon: {ServiceName}Icon,
@@ -631,7 +629,7 @@ export const registry: Record<string, BlockConfig> = {
```typescript
import { ServiceIcon } from '@/components/icons'
import type { BlockConfig } from '@/blocks/types'
import { AuthMode, IntegrationType } from '@/blocks/types'
import { AuthMode } from '@/blocks/types'
import { getScopesForService } from '@/lib/oauth/utils'
export const ServiceBlock: BlockConfig = {
@@ -641,8 +639,6 @@ export const ServiceBlock: BlockConfig = {
longDescription: 'Full description for documentation...',
docsLink: 'https://docs.sim.ai/tools/service',
category: 'tools',
integrationType: IntegrationType.DeveloperTools,
tags: ['oauth', 'api'],
bgColor: '#FF6B6B',
icon: ServiceIcon,
authMode: AuthMode.OAuth,
@@ -800,8 +796,6 @@ All tool IDs referenced in `tools.access` and returned by `tools.config.tool` MU
## Checklist Before Finishing
- [ ] `integrationType` is set to the correct `IntegrationType` enum value
- [ ] `tags` array includes all applicable `IntegrationTag` values
- [ ] All subBlocks have `id`, `title` (except switch), and `type`
- [ ] Conditions use correct syntax (field, value, not, and)
- [ ] DependsOn set for fields that need other values

View File

@@ -117,8 +117,6 @@ export const {service}Connector: ConnectorConfig = {
The add-connector modal renders these automatically — no custom UI needed.
Three field types are supported: `short-input`, `dropdown`, and `selector`.
```typescript
// Text input
{
@@ -143,136 +141,6 @@ Three field types are supported: `short-input`, `dropdown`, and `selector`.
}
```
## 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
placeholder: 'Select a table',
required: true,
},
{
id: 'tableIdOrName',
title: 'Table Name or ID',
type: 'short-input',
canonicalParamId: 'tableIdOrName',
mode: 'advanced',
placeholder: 'e.g. Tasks',
required: true,
},
// Non-selector fields stay as-is
{ id: 'maxRecords', title: 'Max Records', type: 'short-input', ... },
]
```
### 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`):
```
oauthCredential, domain, teamId, projectId, knowledgeBaseId, planId,
siteId, collectionId, spreadsheetId, fileId, baseId, datasetId, serviceDeskId
```
### Available selector keys
Check `hooks/selectors/types.ts` for the full `SelectorKey` union. Common ones for connectors:
| SelectorKey | Context Deps | Returns |
|-------------|-------------|---------|
| `airtable.bases` | credential | Base ID + name |
| `airtable.tables` | credential, `baseId` | Table ID + name |
| `slack.channels` | credential | Channel ID + name |
| `gmail.labels` | credential | Label ID + name |
| `google.calendar` | credential | Calendar ID + name |
| `linear.teams` | credential | Team ID + name |
| `linear.projects` | credential, `teamId` | Project ID + name |
| `jira.projects` | credential, `domain` | Project key + name |
| `confluence.spaces` | credential, `domain` | Space key + name |
| `notion.databases` | credential | Database ID + name |
| `asana.workspaces` | credential | Workspace GID + name |
| `microsoft.teams` | credential | Team ID + name |
| `microsoft.channels` | credential, `teamId` | Channel ID + name |
| `webflow.sites` | credential | Site ID + name |
| `outlook.folders` | credential | Folder ID + name |
## ExternalDocument Shape
Every document returned from `listDocuments`/`getDocument` must include:
@@ -419,12 +287,6 @@ export const CONNECTOR_REGISTRY: ConnectorRegistry = {
- [ ] **Auth configured correctly:**
- OAuth: `auth.provider` matches an existing `OAuthService` in `lib/oauth/types.ts`
- API key: `auth.label` and `auth.placeholder` set appropriately
- [ ] **Selector fields configured correctly (if applicable):**
- Every `type: 'selector'` field has a canonical pair (`short-input` or `dropdown` with same `canonicalParamId` and `mode: 'advanced'`)
- `required` is identical on both fields in each canonical pair
- `selectorKey` exists in `hooks/selectors/registry.ts`
- `dependsOn` references selector field IDs (not `canonicalParamId`)
- Dependency `canonicalParamId` values exist in `SELECTOR_CONTEXT_FIELDS`
- [ ] `listDocuments` handles pagination and computes content hashes
- [ ] `sourceUrl` set on each ExternalDocument (full URL, not relative)
- [ ] `metadata` includes source-specific data for tag mapping

View File

@@ -113,7 +113,7 @@ export const {service}{Action}Tool: ToolConfig<Params, Response> = {
```typescript
import { {Service}Icon } from '@/components/icons'
import type { BlockConfig } from '@/blocks/types'
import { AuthMode, IntegrationType } from '@/blocks/types'
import { AuthMode } from '@/blocks/types'
import { getScopesForService } from '@/lib/oauth/utils'
export const {Service}Block: BlockConfig = {
@@ -123,8 +123,6 @@ export const {Service}Block: BlockConfig = {
longDescription: '...',
docsLink: 'https://docs.sim.ai/tools/{service}',
category: 'tools',
integrationType: IntegrationType.X, // Primary category (see IntegrationType enum)
tags: ['oauth', 'api'], // Cross-cutting tags (see IntegrationTag type)
bgColor: '#HEXCOLOR',
icon: {Service}Icon,
authMode: AuthMode.OAuth, // or AuthMode.ApiKey
@@ -412,8 +410,6 @@ If creating V2 versions (API-aligned outputs):
### Block
- [ ] Created `blocks/blocks/{service}.ts`
- [ ] Set `integrationType` to the correct `IntegrationType` enum value
- [ ] Set `tags` array with all applicable `IntegrationTag` values
- [ ] Defined operation dropdown with all operations
- [ ] Added credential field with `requiredScopes: getScopesForService('{service}')`
- [ ] Added conditional fields per operation

View File

@@ -1,316 +0,0 @@
---
description: Validate an existing knowledge base connector against its service's API docs
argument-hint: <service-name> [api-docs-url]
---
# Validate Connector Skill
You are an expert auditor for Sim knowledge base connectors. Your job is to thoroughly validate that an existing connector is correct, complete, and follows all conventions.
## Your Task
When the user asks you to validate a connector:
1. Read the service's API documentation (via Context7 or WebFetch)
2. Read the connector implementation, OAuth config, 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 connector — do not skip any:
```
apps/sim/connectors/{service}/{service}.ts # Connector implementation
apps/sim/connectors/{service}/index.ts # Barrel export
apps/sim/connectors/registry.ts # Connector registry entry
apps/sim/connectors/types.ts # ConnectorConfig interface, ExternalDocument, etc.
apps/sim/connectors/utils.ts # Shared utilities (computeContentHash, htmlToPlainText, etc.)
apps/sim/lib/oauth/oauth.ts # OAUTH_PROVIDERS — single source of truth for scopes
apps/sim/lib/oauth/utils.ts # getCanonicalScopesForProvider, getScopesForService, SCOPE_DESCRIPTIONS
apps/sim/lib/oauth/types.ts # OAuthService union type
apps/sim/components/icons.tsx # Icon definition for the service
```
If the connector uses selectors, also read:
```
apps/sim/hooks/selectors/registry.ts # Selector key definitions
apps/sim/hooks/selectors/types.ts # SelectorKey union type
apps/sim/lib/workflows/subblocks/context.ts # SELECTOR_CONTEXT_FIELDS
```
## Step 2: Pull API Documentation
Fetch the official API docs for the service. This is the **source of truth** for:
- Endpoint URLs, HTTP methods, and auth headers
- Required vs optional parameters
- Parameter types and allowed values
- Response shapes and field names
- Pagination patterns (cursor, offset, next token)
- Rate limits and error formats
- OAuth scopes and their meanings
Use Context7 (resolve-library-id → query-docs) or WebFetch to retrieve documentation. If both fail, note which claims are based on training knowledge vs verified docs.
## Step 3: Validate API Endpoints
For **every** API call in the connector (`listDocuments`, `getDocument`, `validateConfig`, and any helper functions), verify against the API docs:
### URLs and Methods
- [ ] Base URL is correct for the service's API version
- [ ] Endpoint paths match the API docs exactly
- [ ] HTTP method is correct (GET, POST, PUT, PATCH, DELETE)
- [ ] Path parameters are correctly interpolated and URI-encoded where needed
- [ ] Query parameters use correct names and formats per the API docs
### Headers
- [ ] Authorization header uses the correct format:
- OAuth: `Authorization: Bearer ${accessToken}`
- API Key: correct header name per the service's docs
- [ ] `Content-Type` is set for POST/PUT/PATCH requests
- [ ] Any service-specific headers are present (e.g., `Notion-Version`, `Dropbox-API-Arg`)
- [ ] No headers are sent that the API doesn't support or silently ignores
### Request Bodies
- [ ] POST/PUT body fields match API parameter names exactly
- [ ] Required fields are always sent
- [ ] Optional fields are conditionally included (not sent as `null` or empty unless the API expects that)
- [ ] Field value types match API expectations (string vs number vs boolean)
### Input Sanitization
- [ ] User-controlled values interpolated into query strings are properly escaped:
- OData `$filter`: single quotes escaped with `''` (e.g., `externalId.replace(/'/g, "''")`)
- SOQL: single quotes escaped with `\'`
- GraphQL variables: passed as variables, not interpolated into query strings
- URL path segments: `encodeURIComponent()` applied
- [ ] URL-type config fields (e.g., `siteUrl`, `instanceUrl`) are normalized:
- Strip `https://` / `http://` prefix if the API expects bare domains
- Strip trailing `/`
- Apply `.trim()` before validation
### Response Parsing
- [ ] Response structure is correctly traversed (e.g., `data.results` vs `data.items` vs `data`)
- [ ] Field names extracted match what the API actually returns
- [ ] Nullable fields are handled with `?? null` or `|| undefined`
- [ ] Error responses are checked before accessing data fields
## Step 4: Validate OAuth Scopes (if OAuth connector)
Scopes must be correctly declared and sufficient for all API calls the connector makes.
### Connector requiredScopes
- [ ] `requiredScopes` in the connector's `auth` config lists all scopes needed by the connector
- [ ] Each scope in `requiredScopes` is a real, valid scope recognized by the service's API
- [ ] No invalid, deprecated, or made-up scopes are listed
- [ ] No unnecessary excess scopes beyond what the connector actually needs
### Scope Subset Validation (CRITICAL)
- [ ] Every scope in `requiredScopes` exists in the OAuth provider's `scopes` array in `lib/oauth/oauth.ts`
- [ ] Find the provider in `OAUTH_PROVIDERS[providerGroup].services[serviceId].scopes`
- [ ] Verify: `requiredScopes``OAUTH_PROVIDERS scopes` (every required scope is present in the provider config)
- [ ] If a required scope is NOT in the provider config, flag as **critical** — the connector will fail at runtime
### Scope Sufficiency
For each API endpoint the connector calls:
- [ ] Identify which scopes are required per the API docs
- [ ] Verify those scopes are included in the connector's `requiredScopes`
- [ ] If the connector calls endpoints requiring scopes not in `requiredScopes`, flag as **warning**
### Token Refresh Config
- [ ] Check the `getOAuthTokenRefreshConfig` function in `lib/oauth/oauth.ts` for this provider
- [ ] `useBasicAuth` matches the service's token exchange requirements
- [ ] `supportsRefreshTokenRotation` matches whether the service issues rotating refresh tokens
- [ ] Token endpoint URL is correct
## Step 5: Validate Pagination
### listDocuments Pagination
- [ ] Cursor/pagination parameter name matches the API docs
- [ ] Response pagination field is correctly extracted (e.g., `next_cursor`, `nextPageToken`, `@odata.nextLink`, `offset`)
- [ ] `hasMore` is correctly determined from the response
- [ ] `nextCursor` is correctly passed back for the next page
- [ ] `maxItems` / `maxRecords` cap is correctly applied across pages using `syncContext.totalDocsFetched`
- [ ] Page size is within the API's allowed range (not exceeding max page size)
- [ ] Last page precision: when a `maxItems` cap exists, the final page request uses `Math.min(PAGE_SIZE, remaining)` to avoid fetching more records than needed
- [ ] No off-by-one errors in pagination tracking
- [ ] The connector does NOT hit known API pagination limits silently (e.g., HubSpot search 10k cap)
### Pagination State Across Pages
- [ ] `syncContext` is used to cache state across pages (user names, field maps, instance URLs, portal IDs, etc.)
- [ ] Cached state in `syncContext` is correctly initialized on first page and reused on subsequent pages
## Step 6: Validate Data Transformation
### ExternalDocument Construction
- [ ] `externalId` is a stable, unique identifier from the source API
- [ ] `title` is extracted from the correct field and has a sensible fallback (e.g., `'Untitled'`)
- [ ] `content` is plain text — HTML content is stripped using `htmlToPlainText` from `@/connectors/utils`
- [ ] `mimeType` is `'text/plain'`
- [ ] `contentHash` is computed using `computeContentHash` from `@/connectors/utils`
- [ ] `sourceUrl` is a valid, complete URL back to the original resource (not relative)
- [ ] `metadata` contains all fields referenced by `mapTags` and `tagDefinitions`
### Content Extraction
- [ ] Rich text / HTML fields are converted to plain text before indexing
- [ ] Important content is not silently dropped (e.g., nested blocks, table cells, code blocks)
- [ ] Content is not silently truncated without logging a warning
- [ ] Empty/blank documents are properly filtered out
- [ ] Size checks use `Buffer.byteLength(text, 'utf8')` not `text.length` when comparing against byte-based limits (e.g., `MAX_FILE_SIZE` in bytes)
## Step 7: Validate Tag Definitions and mapTags
### tagDefinitions
- [ ] Each `tagDefinition` has an `id`, `displayName`, and `fieldType`
- [ ] `fieldType` matches the actual data type: `'text'` for strings, `'number'` for numbers, `'date'` for dates, `'boolean'` for booleans
- [ ] Every `id` in `tagDefinitions` is returned by `mapTags`
- [ ] No `tagDefinition` references a field that `mapTags` never produces
### mapTags
- [ ] Return keys match `tagDefinition` `id` values exactly
- [ ] Date values are properly parsed using `parseTagDate` from `@/connectors/utils`
- [ ] Array values are properly joined using `joinTagArray` from `@/connectors/utils`
- [ ] Number values are validated (not `NaN`)
- [ ] Metadata field names accessed in `mapTags` match what `listDocuments`/`getDocument` store in `metadata`
## Step 8: Validate Config Fields and Validation
### configFields
- [ ] Every field has `id`, `title`, `type`
- [ ] `required` is set explicitly (not omitted)
- [ ] Dropdown fields have `options` with `label` and `id` for each option
- [ ] Selector fields follow the canonical pair pattern:
- A `type: 'selector'` field with `selectorKey`, `canonicalParamId`, `mode: 'basic'`
- A `type: 'short-input'` field with the same `canonicalParamId`, `mode: 'advanced'`
- `required` is identical on both fields in the pair
- [ ] `selectorKey` values exist in the selector registry
- [ ] `dependsOn` references selector field `id` values, not `canonicalParamId`
### validateConfig
- [ ] Validates all required fields are present before making API calls
- [ ] Validates optional numeric fields (checks `Number.isNaN`, positive values)
- [ ] Makes a lightweight API call to verify access (e.g., fetch 1 record, get profile)
- [ ] Uses `VALIDATE_RETRY_OPTIONS` for retry budget
- [ ] Returns `{ valid: true }` on success
- [ ] Returns `{ valid: false, error: 'descriptive message' }` on failure
- [ ] Catches exceptions and returns user-friendly error messages
- [ ] Does NOT make expensive calls (full data listing, large queries)
## Step 9: Validate getDocument
- [ ] Fetches a single document by `externalId`
- [ ] Returns `null` for 404 / not found (does not throw)
- [ ] Returns the same `ExternalDocument` shape as `listDocuments`
- [ ] Handles all content types that `listDocuments` can produce (e.g., if `listDocuments` returns both pages and blogposts, `getDocument` must handle both — not hardcode one endpoint)
- [ ] Forwards `syncContext` if it needs cached state (user names, field maps, etc.)
- [ ] Error handling is graceful (catches, logs, returns null or throws with context)
- [ ] Does not redundantly re-fetch data already included in the initial API response (e.g., if comments come back with the post, don't fetch them again separately)
## Step 10: Validate General Quality
### fetchWithRetry Usage
- [ ] All external API calls use `fetchWithRetry` from `@/lib/knowledge/documents/utils`
- [ ] No raw `fetch()` calls to external APIs
- [ ] `VALIDATE_RETRY_OPTIONS` used in `validateConfig`
- [ ] If `validateConfig` calls a shared helper (e.g., `linearGraphQL`, `resolveId`), that helper must accept and forward `retryOptions` to `fetchWithRetry`
- [ ] Default retry options used in `listDocuments`/`getDocument`
### API Efficiency
- [ ] APIs that support field selection (e.g., `$select`, `sysparm_fields`, `fields`) should request only the fields the connector needs — in both `listDocuments` AND `getDocument`
- [ ] No redundant API calls: if a helper already fetches data (e.g., site metadata), callers should reuse the result instead of making a second call for the same information
- [ ] Sequential per-item API calls (fetching details for each document in a loop) should be batched with `Promise.all` and a concurrency limit of 3-5
### Error Handling
- [ ] Individual document failures are caught and logged without aborting the sync
- [ ] API error responses include status codes in error messages
- [ ] No unhandled promise rejections in concurrent operations
### Concurrency
- [ ] Concurrent API calls use reasonable batch sizes (3-5 is typical)
- [ ] No unbounded `Promise.all` over large arrays
### Logging
- [ ] Uses `createLogger` from `@sim/logger` (not `console.log`)
- [ ] Logs sync progress at `info` level
- [ ] Logs errors at `warn` or `error` level with context
### Registry
- [ ] Connector is exported from `connectors/{service}/index.ts`
- [ ] Connector is registered in `connectors/registry.ts`
- [ ] Registry key matches the connector's `id` field
## Step 11: Report and Fix
### Report Format
Group findings by severity:
**Critical** (will cause runtime errors, data loss, or auth failures):
- Wrong API endpoint URL or HTTP method
- Invalid or missing OAuth scopes (not in provider config)
- Incorrect response field mapping (accessing wrong path)
- SOQL/query fields that don't exist on the target object
- Pagination that silently hits undocumented API limits
- Missing error handling that would crash the sync
- `requiredScopes` not a subset of OAuth provider scopes
- Query/filter injection: user-controlled values interpolated into OData `$filter`, SOQL, or query strings without escaping
**Warning** (incorrect behavior, data quality issues, or convention violations):
- HTML content not stripped via `htmlToPlainText`
- `getDocument` not forwarding `syncContext`
- `getDocument` hardcoded to one content type when `listDocuments` returns multiple (e.g., only pages but not blogposts)
- Missing `tagDefinition` for metadata fields returned by `mapTags`
- Incorrect `useBasicAuth` or `supportsRefreshTokenRotation` in token refresh config
- Invalid scope names that the API doesn't recognize (even if silently ignored)
- Private resources excluded from name-based lookup despite scopes being available
- Silent data truncation without logging
- Size checks using `text.length` (character count) instead of `Buffer.byteLength` (byte count) for byte-based limits
- URL-type config fields not normalized (protocol prefix, trailing slashes cause API failures)
- `VALIDATE_RETRY_OPTIONS` not threaded through helper functions called by `validateConfig`
**Suggestion** (minor improvements):
- Missing incremental sync support despite API supporting it
- Overly broad scopes that could be narrowed (not wrong, but could be tighter)
- Source URL format could be more specific
- Missing `orderBy` for deterministic pagination
- Redundant API calls that could be cached in `syncContext`
- Sequential per-item API calls that could be batched with `Promise.all` (concurrency 3-5)
- API supports field selection but connector fetches all fields (e.g., missing `$select`, `sysparm_fields`, `fields`)
- `getDocument` re-fetches data already included in the initial API response (e.g., comments returned with post)
- Last page of pagination requests full `PAGE_SIZE` when fewer records remain (`Math.min(PAGE_SIZE, remaining)`)
### Fix All Issues
After reporting, fix every **critical** and **warning** issue. Apply **suggestions** where they don't add unnecessary complexity.
### Validation Output
After fixing, confirm:
1. `bun run lint` passes
2. TypeScript compiles clean
3. Re-read all modified files to verify fixes are correct
## Checklist Summary
- [ ] Read connector implementation, types, utils, registry, and OAuth config
- [ ] Pulled and read official API documentation for the service
- [ ] Validated every API endpoint URL, method, headers, and body against API docs
- [ ] Validated input sanitization: no query/filter injection, URL fields normalized
- [ ] Validated OAuth scopes: `requiredScopes` ⊆ OAuth provider `scopes` in `oauth.ts`
- [ ] Validated each scope is real and recognized by the service's API
- [ ] Validated scopes are sufficient for all API endpoints the connector calls
- [ ] Validated token refresh config (`useBasicAuth`, `supportsRefreshTokenRotation`)
- [ ] Validated pagination: cursor names, page sizes, hasMore logic, no silent caps
- [ ] Validated data transformation: plain text extraction, HTML stripping, content hashing
- [ ] Validated tag definitions match mapTags output, correct fieldTypes
- [ ] Validated config fields: canonical pairs, selector keys, required flags
- [ ] Validated validateConfig: lightweight check, error messages, retry options
- [ ] Validated getDocument: null on 404, all content types handled, no redundant re-fetches, syncContext forwarding
- [ ] Validated fetchWithRetry used for all external calls (no raw fetch), VALIDATE_RETRY_OPTIONS threaded through helpers
- [ ] Validated API efficiency: field selection used, no redundant calls, sequential fetches batched
- [ ] Validated error handling: graceful failures, no unhandled rejections
- [ ] Validated logging: createLogger, no console.log
- [ ] Validated registry: correct export, correct key
- [ ] Reported all issues grouped by severity
- [ ] Fixed all critical and warning issues
- [ ] Ran `bun run lint` after fixes
- [ ] Verified TypeScript compiles clean

View File

@@ -1,21 +1,9 @@
import type { ReactNode } from 'react'
import type { Viewport } from 'next'
export default function RootLayout({ children }: { children: ReactNode }) {
return children
}
export const viewport: Viewport = {
width: 'device-width',
initialScale: 1,
maximumScale: 1,
userScalable: false,
themeColor: [
{ media: '(prefers-color-scheme: light)', color: '#ffffff' },
{ media: '(prefers-color-scheme: dark)', color: '#0c0c0c' },
],
}
export const metadata = {
metadataBase: new URL('https://docs.sim.ai'),
title: {
@@ -24,9 +12,6 @@ export const metadata = {
},
description:
'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.',
applicationName: 'Sim Docs',
generator: 'Next.js',
referrer: 'origin-when-cross-origin' as const,
keywords: [
'AI agents',
'agentic workforce',
@@ -52,28 +37,17 @@ export const metadata = {
manifest: '/favicon/site.webmanifest',
icons: {
icon: [
{ url: '/icon.svg', type: 'image/svg+xml', sizes: 'any' },
{ url: '/favicon/favicon-16x16.png', sizes: '16x16', type: 'image/png' },
{ url: '/favicon/favicon-32x32.png', sizes: '32x32', type: 'image/png' },
{ url: '/favicon/android-chrome-192x192.png', sizes: '192x192', type: 'image/png' },
{ url: '/favicon/android-chrome-512x512.png', sizes: '512x512', type: 'image/png' },
],
apple: '/favicon/apple-touch-icon.png',
shortcut: '/icon.svg',
shortcut: '/favicon/favicon.ico',
},
appleWebApp: {
capable: true,
statusBarStyle: 'default',
title: 'Sim Docs',
},
formatDetection: {
telephone: false,
},
other: {
'apple-mobile-web-app-capable': 'yes',
'mobile-web-app-capable': 'yes',
'msapplication-TileColor': '#33C482',
},
openGraph: {
type: 'website',
locale: 'en_US',

View File

@@ -124,34 +124,6 @@ export function NoteIcon(props: SVGProps<SVGSVGElement>) {
)
}
export function WorkdayIcon(props: SVGProps<SVGSVGElement>) {
const id = useId()
const clipId = `workday_clip_${id}`
return (
<svg {...props} viewBox='0 0 64 64' fill='none' xmlns='http://www.w3.org/2000/svg'>
<g clipPath={`url(#${clipId})`} transform='matrix(0.53333333,0,0,0.53333333,-124.63685,-16)'>
<path
fillRule='evenodd'
clipRule='evenodd'
d='m 251.21,88.7755 h 8.224 c 1.166,0 2.178,0.7836 2.444,1.8924 l 11.057,44.6751 c 0.152,0.002 12.182,-44.6393 12.182,-44.6393 0.306,-1.1361 1.36,-1.9282 2.566,-1.9282 h 12.74 c 1.144,0 2.144,0.7515 2.435,1.8296 l 12.118,44.9289 c 0.448,-0.282 11.147,-44.8661 11.147,-44.8661 0.267,-1.1088 1.279,-1.8924 2.444,-1.8924 h 8.219 c 1.649,0 2.854,1.5192 2.437,3.0742 l -15.08,56.3173 c -0.286,1.072 -1.272,1.823 -2.406,1.833 l -12.438,-0.019 c -1.142,-0.002 -2.137,-0.744 -2.429,-1.819 -2.126,-7.805 -12.605,-47.277 -12.605,-47.277 0,0 -11.008,39.471 -13.133,47.277 -0.293,1.075 -1.288,1.817 -2.429,1.819 L 266.264,150 c -1.133,-0.01 -2.119,-0.761 -2.406,-1.833 L 248.777,91.8438 c -0.416,-1.5524 0.786,-3.0683 2.433,-3.0683 z'
fill='#005cb9'
/>
<path
fillRule='evenodd'
clipRule='evenodd'
d='m 333.324,72.2449 c 0.531,0 1.071,-0.0723 1.608,-0.2234 3.18,-0.8968 5.039,-4.2303 4.153,-7.446 -0.129,-0.4673 -0.265,-0.9327 -0.408,-1.3936 C 332.529,43.3349 314.569,30 293.987,30 c -20.557,0 -38.51,13.3133 -44.673,33.1281 -0.136,0.4355 -0.267,0.8782 -0.391,1.3232 -0.902,3.2119 0.943,6.5541 4.12,7.4645 3.173,0.9112 6.48,-0.9547 7.381,-4.1666 0.094,-0.3322 0.19,-0.6616 0.292,-0.9892 4.591,-14.7582 17.961,-24.6707 33.271,-24.6707 15.329,0 28.704,9.9284 33.281,24.7063 0.105,0.3397 0.206,0.682 0.301,1.0263 0.737,2.6726 3.139,4.423 5.755,4.423 z'
fill='#f38b00'
/>
</g>
<defs>
<clipPath id={clipId}>
<path d='M 354,30 H 234 v 120 h 120 z' fill='#ffffff' />
</clipPath>
</defs>
</svg>
)
}
export function WorkflowIcon(props: SVGProps<SVGSVGElement>) {
return (
<svg
@@ -1174,25 +1146,6 @@ export function DevinIcon(props: SVGProps<SVGSVGElement>) {
)
}
export function DocuSignIcon(props: SVGProps<SVGSVGElement>) {
return (
<svg {...props} viewBox='0 0 1547 1549' xmlns='http://www.w3.org/2000/svg'>
<path
d='m1113.4 1114.9v395.6c0 20.8-16.7 37.6-37.5 37.6h-1038.4c-20.7 0-37.5-16.8-37.5-37.6v-1039c0-20.7 16.8-37.5 37.5-37.5h394.3v643.4c0 20.7 16.8 37.5 37.5 37.5z'
fill='#4c00ff'
/>
<path
d='m1546 557.1c0 332.4-193.9 557-432.6 557.8v-418.8c0-12-4.8-24-13.5-31.9l-217.1-217.4c-8.8-8.8-20-13.6-32-13.6h-418.2v-394.8c0-20.8 16.8-37.6 37.5-37.6h585.1c277.7-0.8 490.8 223 490.8 556.3z'
fill='#ff5252'
/>
<path
d='m1099.9 663.4c8.7 8.7 13.5 19.9 13.5 31.9v418.8h-643.3c-20.7 0-37.5-16.8-37.5-37.5v-643.4h418.2c12 0 24 4.8 32 13.6z'
fill='#000000'
/>
</svg>
)
}
export function DiscordIcon(props: SVGProps<SVGSVGElement>) {
return (
<svg
@@ -1437,7 +1390,7 @@ export function AmplitudeIcon(props: SVGProps<SVGSVGElement>) {
return (
<svg {...props} xmlns='http://www.w3.org/2000/svg' viewBox='0 0 49 49'>
<path
fill='currentColor'
fill='#FFFFFF'
d='M23.4,15.3c0.6,1.8,1.2,4.1,1.9,6.7c-2.6,0-5.3-0.1-7.8-0.1h-1.3c1.5-5.7,3.2-10.1,4.6-11.1 c0.1-0.1,0.2-0.1,0.4-0.1c0.2,0,0.3,0.1,0.5,0.3C21.9,11.5,22.5,12.7,23.4,15.3z M49,24.5C49,38,38,49,24.5,49S0,38,0,24.5 S11,0,24.5,0S49,11,49,24.5z M42.7,23.9c0-0.6-0.4-1.2-1-1.3l0,0l0,0l0,0c-0.1,0-0.1,0-0.2,0h-0.2c-4.1-0.3-8.4-0.4-12.4-0.5l0,0 C27,14.8,24.5,7.4,21.3,7.4c-3,0-5.8,4.9-8.2,14.5c-1.7,0-3.2,0-4.6-0.1c-0.1,0-0.2,0-0.2,0c-0.3,0-0.5,0-0.5,0 c-0.8,0.1-1.4,0.9-1.4,1.7c0,0.8,0.6,1.6,1.5,1.7l0,0h4.6c-0.4,1.9-0.8,3.8-1.1,5.6l-0.1,0.8l0,0c0,0.6,0.5,1.1,1.1,1.1 c0.4,0,0.8-0.2,1-0.5l0,0l2.2-7.1h10.7c0.8,3.1,1.7,6.3,2.8,9.3c0.6,1.6,2,5.4,4.4,5.4l0,0c3.6,0,5-5.8,5.9-9.6 c0.2-0.8,0.4-1.5,0.5-2.1l0.1-0.2l0,0c0-0.1,0-0.2,0-0.3c-0.1-0.2-0.2-0.3-0.4-0.4c-0.3-0.1-0.5,0.1-0.6,0.4l0,0l-0.1,0.2 c-0.3,0.8-0.6,1.6-0.8,2.3v0.1c-1.6,4.4-2.3,6.4-3.7,6.4l0,0l0,0l0,0c-1.8,0-3.5-7.3-4.1-10.1c-0.1-0.5-0.2-0.9-0.3-1.3h11.7 c0.2,0,0.4-0.1,0.6-0.1l0,0c0,0,0,0,0.1,0c0,0,0,0,0.1,0l0,0c0,0,0.1,0,0.1-0.1l0,0C42.5,24.6,42.7,24.3,42.7,23.9z'
/>
</svg>
@@ -3132,22 +3085,6 @@ export function QdrantIcon(props: SVGProps<SVGSVGElement>) {
)
}
export function QuiverIcon(props: SVGProps<SVGSVGElement>) {
return (
<svg {...props} viewBox='0 0 250 250' fill='none' xmlns='http://www.w3.org/2000/svg'>
<path d='m249.3 0.88h-248.5v248.2h248.5v-248.2z' fill='#F6F6F7' />
<path
d='m124.3 25h-5.93l-1.95 0.59-7.9 0.29-1.47 0.88-7.9 1.18-1.18 0.88-9.09 2.85-0.88 0.88-11.86 5.93-0.88 1.18-6.23 2.55-8.29 8.3-7.61 4.75-5.34 8.6-5.04 4.75-4.46 8.6-2.05 1.18-3.26 8.6-0.88 0.59-3.85 12.16-0.59 0.59-2.35 13.04v1.47l-0.59 7.12 0.3 1.18-0.3 3.15 1.18 13.04 0.59 0.88 0.88 7.51 0.88 1.18 3.85 12.16 0.88 0.6 4.44 9.97 1.18 0.88 4.15 8 12.73 16.17 4.45 2.06 8.8 8.3 0.88 0.29 4.16 3.15h1.18l8.2 4.75h0.88l7.9 3.44h0.88l9.38 2.85 0.88 0.3 13.33 1.46h107.9v-101.3l-0.88-2.06v-8.3l-0.59-0.88v-4.16l-4.75-14.23v-4.16l-11.26-19.46-1.48-1.48-10.37-13.05-5.63-3.15-7.61-7.31-3.15-1.18-5.93-4.75-1.48-0.29-7.01-4.15h-1.18l-8.2-3.15h-0.88l-10.37-3.14h-1.18l-8.49-1.18-2.06-0.88h-7.5z'
fill='#333'
/>
<path
d='m78.38 72.26 118.6 41.21c4.65 1.69 3.47 8.5-1.47 8.5h-74v74.32c0 5.04-7.11 5.92-8.78 1.17l-40.58-118.5c-1.28-3.95 2.27-8.11 6.19-6.72z'
fill='#F9F9F9'
/>
</svg>
)
}
export function AshbyIcon(props: SVGProps<SVGSVGElement>) {
return (
<svg {...props} viewBox='0 0 254 260' fill='none' xmlns='http://www.w3.org/2000/svg'>
@@ -4154,16 +4091,6 @@ export function IncidentioIcon(props: SVGProps<SVGSVGElement>) {
)
}
export function InfisicalIcon(props: SVGProps<SVGSVGElement>) {
return (
<svg {...props} viewBox='20 25 233 132' xmlns='http://www.w3.org/2000/svg'>
<path
d='m191.6 39.4c-20.3 0-37.15 13.21-52.9 30.61-12.99-16.4-29.8-30.61-51.06-30.61-27.74 0-50.44 23.86-50.44 51.33 0 26.68 21.43 51.8 48.98 51.8 20.55 0 37.07-13.86 51.32-31.81 12.69 16.97 29.1 31.41 53.2 31.41 27.13 0 49.85-22.96 49.85-51.4 0-27.12-20.44-51.33-48.95-51.33zm-104.3 77.94c-14.56 0-25.51-12.84-25.51-26.07 0-13.7 10.95-28.29 25.51-28.29 14.93 0 25.71 11.6 37.6 27.34-11.31 15.21-22.23 27.02-37.6 27.02zm104.4 0.25c-15 0-25.28-11.13-37.97-27.37 12.69-16.4 22.01-27.24 37.59-27.24 14.97 0 24.79 13.25 24.79 27.26 0 13-10.17 27.35-24.41 27.35z'
fill='#000000'
/>
</svg>
)
}
export function IntercomIcon(props: SVGProps<SVGSVGElement>) {
return (
<svg
@@ -4269,7 +4196,7 @@ export function ZoomIcon(props: SVGProps<SVGSVGElement>) {
fill='currentColor'
width='800px'
height='800px'
viewBox='-1 9.5 34 13'
viewBox='0 0 32 32'
version='1.1'
xmlns='http://www.w3.org/2000/svg'
>
@@ -4642,17 +4569,11 @@ export function ShopifyIcon(props: SVGProps<SVGSVGElement>) {
export function BoxCompanyIcon(props: SVGProps<SVGSVGElement>) {
return (
<svg
{...props}
xmlns='http://www.w3.org/2000/svg'
width='2500'
height='1379'
viewBox='0 0 444.893 245.414'
>
<g fill='#0075C9'>
<path d='M239.038 72.43c-33.081 0-61.806 18.6-76.322 45.904-14.516-27.305-43.24-45.902-76.32-45.902-19.443 0-37.385 6.424-51.821 17.266V16.925h-.008C34.365 7.547 26.713 0 17.286 0 7.858 0 .208 7.547.008 16.925H0v143.333h.036c.768 47.051 39.125 84.967 86.359 84.967 33.08 0 61.805-18.603 76.32-45.908 14.517 27.307 43.241 45.906 76.321 45.906 47.715 0 86.396-38.684 86.396-86.396.001-47.718-38.682-86.397-86.394-86.397zM86.395 210.648c-28.621 0-51.821-23.201-51.821-51.82 0-28.623 23.201-51.823 51.821-51.823 28.621 0 51.822 23.2 51.822 51.823 0 28.619-23.201 51.82-51.822 51.82zm152.643 0c-28.622 0-51.821-23.201-51.821-51.822 0-28.623 23.2-51.821 51.821-51.821 28.619 0 51.822 23.198 51.822 51.821-.001 28.621-23.203 51.822-51.822 51.822z' />
<path d='M441.651 218.033l-44.246-59.143 44.246-59.144-.008-.007c5.473-7.62 3.887-18.249-3.652-23.913-7.537-5.658-18.187-4.221-23.98 3.157l-.004-.002-38.188 51.047-38.188-51.047-.006.009c-5.793-7.385-16.441-8.822-23.981-3.16-7.539 5.664-9.125 16.293-3.649 23.911l-.008.005 44.245 59.144-44.245 59.143.008.005c-5.477 7.62-3.89 18.247 3.649 23.909 7.54 5.664 18.188 4.225 23.981-3.155l.006.007 38.188-51.049 38.188 51.049.004-.002c5.794 7.377 16.443 8.814 23.98 3.154 7.539-5.662 9.125-16.291 3.652-23.91l.008-.008z' />
</g>
<svg {...props} xmlns='http://www.w3.org/2000/svg' viewBox='0 0 41 22'>
<path
d='M39.7 19.2c.5.7.4 1.6-.2 2.1-.7.5-1.7.4-2.2-.2l-3.5-4.5-3.4 4.4c-.5.7-1.5.7-2.2.2-.7-.5-.8-1.4-.3-2.1l4-5.2-4-5.2c-.5-.7-.3-1.7.3-2.2.7-.5 1.7-.3 2.2.3l3.4 4.5L37.3 7c.5-.7 1.4-.8 2.2-.3.7.5.7 1.5.2 2.2L35.8 14l3.9 5.2zm-18.2-.6c-2.6 0-4.7-2-4.7-4.6 0-2.5 2.1-4.6 4.7-4.6s4.7 2.1 4.7 4.6c-.1 2.6-2.2 4.6-4.7 4.6zm-13.8 0c-2.6 0-4.7-2-4.7-4.6 0-2.5 2.1-4.6 4.7-4.6s4.7 2.1 4.7 4.6c0 2.6-2.1 4.6-4.7 4.6zM21.5 6.4c-2.9 0-5.5 1.6-6.8 4-1.3-2.4-3.9-4-6.9-4-1.8 0-3.4.6-4.7 1.5V1.5C3.1.7 2.4 0 1.6 0 .7 0 0 .7 0 1.5v12.6c.1 4.2 3.5 7.5 7.7 7.5 3 0 5.6-1.7 6.9-4.1 1.3 2.4 3.9 4.1 6.8 4.1 4.3 0 7.8-3.4 7.8-7.7.1-4.1-3.4-7.5-7.7-7.5z'
fill='currentColor'
/>
</svg>
)
}
@@ -6122,19 +6043,6 @@ export function AgentSkillsIcon(props: SVGProps<SVGSVGElement>) {
)
}
export function OktaIcon(props: SVGProps<SVGSVGElement>) {
return (
<svg {...props} viewBox='0 0 63 63' xmlns='http://www.w3.org/2000/svg'>
<path
fillRule='evenodd'
clipRule='evenodd'
d='M34.6.4l-1.3 16c-.6-.1-1.2-.1-1.9-.1-.8 0-1.6.1-2.3.2l-.7-7.7c0-.2.2-.5.4-.5h1.3L29.5.5c0-.2.2-.5.4-.5h4.3c.3 0 .5.2.4.4zm-10.8.8c-.1-.2-.3-.4-.5-.3l-4 1.5c-.3.1-.4.4-.3.6l3.3 7.1-1.2.5c-.2.1-.3.3-.2.6l3.3 7c1.2-.7 2.5-1.2 3.9-1.5L23.8 1.2zM14 5.7l9.3 13.1c-1.2.8-2.2 1.7-3.1 2.7L14.5 16c-.2-.2-.2-.5 0-.6l1-.8L10 9c-.2-.2-.2-.5 0-.6l3.3-2.7c.2-.3.5-.2.7 0zM6.2 13.2c-.2-.1-.5-.1-.6.1l-2.1 3.7c-.1.2 0 .5.2.6l7.1 3.4-.7 1.1c-.1.2 0 .5.2.6l7.1 3.2c.5-1.3 1.2-2.5 2-3.6L6.2 13.2zM.9 23.3c0-.2.3-.4.5-.3l15.5 4c-.4 1.3-.6 2.7-.7 4.1l-7.8-.6c-.2 0-.4-.2-.4-.5l.2-1.3L.6 28c-.2 0-.4-.2-.4-.5l.7-4.2zM.4 33.8c-.3 0-.4.2-.4.5l.8 4.2c0 .2.3.4.5.3l7.6-2 .2 1.3c0 .2.3.4.5.3l7.5-2.1c-.4-1.3-.7-2.7-.8-4.1L.4 33.8zm2.5 11.1c-.1-.2 0-.5.2-.6l14.5-6.9c.5 1.3 1.3 2.5 2.2 3.6l-6.3 4.5c-.2.1-.5.1-.6-.1L12 44.3l-6.5 4.5c-.2.1-.5.1-.6-.1l-2-3.8zm17.5-3L9.1 53.3c-.2.2-.2.5 0 .6l3.3 2.7c.2.2.5.1.6-.1l4.6-6.4 1 .9c.2.2.5.1.6-.1l4.4-6.4c-1.2-.7-2.3-1.6-3.2-2.6zm-2.2 18.2c-.2-.1-.3-.3-.2-.6L24.6 45c1.2.6 2.6 1.1 3.9 1.4l-2 7.5c-.1.2-.3.4-.5.3l-1.2-.5-2.1 7.6c-.1.2-.3.4-.5.3l-4-1.5zm10.9-13.5l-1.3 16c0 .2.2.5.4.5H33c.2 0 .4-.2.4-.5l-.6-7.8h1.3c.2 0 .4-.2.4-.5l-.7-7.7c-.8.1-1.5.2-2.3.2-.6 0-1.3 0-1.9-.1zm16-43.2c.1-.2 0-.5-.2-.6l-4-1.5c-.2-.1-.5.1-.5.3l-2.1 7.6-1.2-.5c-.2-.1-.5.1-.5.3l-2 7.5c1.4.3 2.7.8 3.9 1.4l6.6-14.5zm8.8 6.3L42.6 21.1c-.9-1-2-1.9-3.2-2.6l4.4-6.4c.1-.2.4-.2.6-.1l1 .9 4.6-6.4c.1-.2.4-.2.6-.1l3.3 2.7c.2.2.2.5 0 .6zM59.9 18.7c.2-.1.3-.4.2-.6L58 14.4c-.1-.2-.4-.3-.6-.1l-6.5 4.5-.7-1.1c-.1-.2-.4-.3-.6-.1L43.3 22c.9 1.1 1.6 2.3 2.2 3.6l14.4-6.9zm2.3 5.8l.7 4.2c0 .2-.1.5-.4.5l-15.9 1.5c-.1-1.4-.4-2.8-.8-4.1l7.5-2.1c.2-.1.5.1.5.3l.2 1.3 7.6-2c.3-.1.5.1.6.4zM61.5 40c.2.1.5-.1.5-.3l.7-4.2c0-.2-.1-.5-.4-.5l-7.8-.7.2-1.3c0-.2-.1-.5-.4-.5l-7.8-.6c0 1.4-.3 2.8-.7 4.1L61.5 40zm-4.1 9.6c-.1.2-.4.3-.6.1l-13.2-9.1c.8-1.1 1.5-2.3 2-3.6l7.1 3.2c.2.1.3.4.2.6L52.2 42l7.1 3.4c.2.1.3.4.2.6l-2.1 3.6zm-17.7-5.4L49 57.3c.1.2.4.2.6.1l3.3-2.7c.2-.2.2-.4 0-.6l-5.5-5.6 1-.8c.2-.2.2-.4 0-.6l-5.5-5.5c1.1.8 0 1.7-1.2 2.4zm0 17.8c-.2.1-.5-.1-.5-.3l-4.2-15.4c1.4-.3 2.7-.8 3.9-1.5l3.3 7c.1.2 0 .5-.2.6l-1.2.5 3.3 7.1c.1.2 0 .5-.2.6L39.7 62z'
fill='currentColor'
/>
</svg>
)
}
export function OnePasswordIcon(props: SVGProps<SVGSVGElement>) {
return (
<svg {...props} viewBox='0 0 48 48' xmlns='http://www.w3.org/2000/svg' fill='none'>

View File

@@ -1,7 +1,18 @@
import { memo } from 'react'
'use client'
import { memo, useEffect, useState } from 'react'
/** Shared corner radius from Figma export for all decorative rects. */
const RX = '2.59574'
const ENTER_STAGGER = 0.06
const ENTER_DURATION = 0.3
const EXIT_STAGGER = 0.12
const EXIT_DURATION = 0.5
const INITIAL_HOLD = 3000
const HOLD_BETWEEN = 3000
const TRANSITION_PAUSE = 400
interface BlockRect {
opacity: number
width: string
@@ -12,6 +23,8 @@ interface BlockRect {
transform?: string
}
type AnimState = 'visible' | 'exiting' | 'hidden'
const RECTS = {
topRight: [
{ opacity: 1, x: '0', y: '0', width: '16.8626', height: '33.7252', fill: '#2ABBF8' },
@@ -54,33 +67,76 @@ const RECTS = {
fill: '#FA4EDF',
},
],
bottomLeft: [
{ opacity: 1, x: '0', y: '0', width: '16.8626', height: '33.7252', fill: '#2ABBF8' },
{ opacity: 0.6, x: '0', y: '0', width: '85.3433', height: '16.8626', fill: '#2ABBF8' },
{ opacity: 1, x: '0', y: '0', width: '16.8626', height: '16.8626', fill: '#2ABBF8' },
{ opacity: 0.6, x: '34.2403', y: '0', width: '34.2403', height: '33.7252', fill: '#2ABBF8' },
{ opacity: 1, x: '34.2403', y: '0', width: '16.8626', height: '16.8626', fill: '#2ABBF8' },
left: [
{
opacity: 0.6,
width: '34.240',
height: '33.725',
fill: '#FA4EDF',
transform: 'matrix(0 1 1 0 0 0)',
},
{
opacity: 0.6,
width: '16.8626',
height: '68.480',
fill: '#FA4EDF',
transform: 'matrix(-1 0 0 1 33.727 0)',
},
{
opacity: 1,
x: '51.6188',
y: '16.8626',
width: '16.8626',
height: '16.8626',
fill: '#2ABBF8',
fill: '#FA4EDF',
transform: 'matrix(-1 0 0 1 33.727 17.378)',
},
{
opacity: 0.6,
width: '16.8626',
height: '33.986',
fill: '#FA4EDF',
transform: 'matrix(0 1 1 0 0 51.616)',
},
{
opacity: 0.6,
width: '16.8626',
height: '140.507',
fill: '#00F701',
transform: 'matrix(-1 0 0 1 33.986 85.335)',
},
{
opacity: 0.4,
x: '17.119',
y: '136.962',
width: '34.240',
height: '16.8626',
fill: '#FFCC02',
transform: 'rotate(-90 17.119 136.962)',
},
{
opacity: 1,
x: '17.119',
y: '136.962',
width: '16.8626',
height: '16.8626',
fill: '#FFCC02',
transform: 'rotate(-90 17.119 136.962)',
},
{
opacity: 0.5,
width: '34.240',
height: '33.725',
fill: '#00F701',
transform: 'matrix(0 1 1 0 0.257 153.825)',
},
{ opacity: 1, x: '68.4812', y: '0', width: '54.6502', height: '16.8626', fill: '#00F701' },
{ opacity: 0.6, x: '106.268', y: '0', width: '34.2403', height: '33.7252', fill: '#00F701' },
{ opacity: 0.6, x: '106.268', y: '0', width: '51.103', height: '16.8626', fill: '#00F701' },
{
opacity: 1,
x: '123.6484',
y: '16.8626',
width: '16.8626',
height: '16.8626',
fill: '#00F701',
transform: 'matrix(0 1 1 0 0.257 153.825)',
},
],
bottomRight: [
right: [
{
opacity: 0.6,
width: '16.8626',
@@ -119,33 +175,68 @@ const RECTS = {
{
opacity: 0.6,
width: '16.8626',
height: '34.24',
height: '33.726',
fill: '#FA4EDF',
transform: 'matrix(0 1 1 0 0.012 68.510)',
},
{
opacity: 0.6,
width: '16.8626',
height: '102.384',
fill: '#2ABBF8',
transform: 'matrix(-1 0 0 1 33.787 68)',
transform: 'matrix(-1 0 0 1 33.787 102.384)',
},
{
opacity: 0.4,
x: '17.131',
y: '153.859',
width: '34.241',
height: '16.8626',
fill: '#00F701',
transform: 'rotate(-90 17.131 153.859)',
},
{
opacity: 1,
x: '17.131',
y: '153.859',
width: '16.8626',
height: '16.8626',
fill: '#1A8FCC',
transform: 'matrix(-1 0 0 1 33.787 85)',
fill: '#00F701',
transform: 'rotate(-90 17.131 153.859)',
},
],
} as const satisfies Record<string, readonly BlockRect[]>
const GLOBAL_OPACITY = 0.55
type Position = keyof typeof RECTS
function enterTime(pos: Position): number {
return (RECTS[pos].length - 1) * ENTER_STAGGER + ENTER_DURATION
}
function exitTime(pos: Position): number {
return (RECTS[pos].length - 1) * EXIT_STAGGER + EXIT_DURATION
}
interface BlockGroupProps {
width: number
height: number
viewBox: string
rects: readonly BlockRect[]
animState: AnimState
globalOpacity: number
}
const BlockGroup = memo(function BlockGroup({
width,
height,
viewBox,
rects,
}: {
width: number
height: number
viewBox: string
rects: readonly BlockRect[]
}) {
animState,
globalOpacity,
}: BlockGroupProps) {
const isVisible = animState === 'visible'
const isExiting = animState === 'exiting'
return (
<svg
width={width}
@@ -154,7 +245,7 @@ const BlockGroup = memo(function BlockGroup({
fill='none'
xmlns='http://www.w3.org/2000/svg'
className='h-auto w-full'
style={{ opacity: GLOBAL_OPACITY }}
style={{ opacity: globalOpacity }}
>
{rects.map((r, i) => (
<rect
@@ -166,29 +257,114 @@ const BlockGroup = memo(function BlockGroup({
rx={RX}
fill={r.fill}
transform={r.transform}
opacity={r.opacity}
style={{
opacity: isVisible ? r.opacity : 0,
transition: `opacity ${isExiting ? EXIT_DURATION : ENTER_DURATION}s ease ${
isVisible ? i * ENTER_STAGGER : isExiting ? i * EXIT_STAGGER : 0
}s`,
}}
/>
))}
</svg>
)
})
function useGroupState(): [AnimState, (s: AnimState) => void] {
return useState<AnimState>('visible')
}
function useBlockCycle() {
const [topRight, setTopRight] = useGroupState()
const [left, setLeft] = useGroupState()
const [right, setRight] = useGroupState()
useEffect(() => {
if (typeof window !== 'undefined' && !window.matchMedia('(min-width: 1024px)').matches) return
const cancelled = { current: false }
const wait = (ms: number) => new Promise<void>((r) => setTimeout(r, ms))
async function exit(setter: (s: AnimState) => void, pos: Position, pauseAfter: number) {
if (cancelled.current) return
setter('exiting')
await wait(exitTime(pos) * 1000)
if (cancelled.current) return
setter('hidden')
await wait(pauseAfter)
}
async function enter(setter: (s: AnimState) => void, pos: Position, pauseAfter: number) {
if (cancelled.current) return
setter('visible')
await wait(enterTime(pos) * 1000 + pauseAfter)
}
const run = async () => {
await wait(INITIAL_HOLD)
while (!cancelled.current) {
await exit(setTopRight, 'topRight', TRANSITION_PAUSE)
await exit(setLeft, 'left', HOLD_BETWEEN)
await enter(setLeft, 'left', TRANSITION_PAUSE)
await enter(setTopRight, 'topRight', TRANSITION_PAUSE)
await exit(setRight, 'right', HOLD_BETWEEN)
await enter(setRight, 'right', HOLD_BETWEEN)
}
}
run()
return () => {
cancelled.current = true
}
}, [])
return { topRight, left, right } as const
}
/**
* Ambient animated block decorations for the docs layout.
* Adapts the landing page's colorful block patterns with slightly reduced
* opacity and the same staggered enter/exit animation cycle.
*/
export function AnimatedBlocks() {
const states = useBlockCycle()
return (
<div
className='pointer-events-none fixed inset-0 z-0 hidden overflow-hidden lg:block'
aria-hidden='true'
>
<div className='absolute top-[93px] right-0 w-[calc(140px+10.76vw)] max-w-[295px]'>
<BlockGroup width={295} height={34} viewBox='0 0 295 34' rects={RECTS.topRight} />
<BlockGroup
width={295}
height={34}
viewBox='0 0 295 34'
rects={RECTS.topRight}
animState={states.topRight}
globalOpacity={0.75}
/>
</div>
<div className='-left-24 absolute bottom-0 w-[calc(140px+10.76vw)] max-w-[295px] rotate-180'>
<BlockGroup width={295} height={34} viewBox='0 0 295 34' rects={RECTS.bottomLeft} />
<div className='-translate-y-1/2 absolute top-[50%] left-0 w-[calc(16px+1.25vw)] max-w-[34px] scale-x-[-1]'>
<BlockGroup
width={34}
height={226}
viewBox='0 0 34 226.021'
rects={RECTS.left}
animState={states.left}
globalOpacity={0.75}
/>
</div>
<div className='-bottom-2 absolute right-0 w-[calc(16px+1.25vw)] max-w-[34px]'>
<BlockGroup width={34} height={102} viewBox='0 0 34 102' rects={RECTS.bottomRight} />
<div className='-translate-y-1/2 absolute top-[50%] right-0 w-[calc(16px+1.25vw)] max-w-[34px]'>
<BlockGroup
width={34}
height={205}
viewBox='0 0 34 204.769'
rects={RECTS.right}
animState={states.right}
globalOpacity={0.75}
/>
</div>
</div>
)

View File

@@ -16,8 +16,6 @@ import {
AsanaIcon,
AshbyIcon,
AttioIcon,
AzureIcon,
BoxCompanyIcon,
BrainIcon,
BrandfetchIcon,
BrowserUseIcon,
@@ -34,7 +32,6 @@ import {
DevinIcon,
DiscordIcon,
DocumentIcon,
DocuSignIcon,
DropboxIcon,
DsPyIcon,
DubIcon,
@@ -82,7 +79,6 @@ import {
HunterIOIcon,
ImageIcon,
IncidentioIcon,
InfisicalIcon,
IntercomIcon,
JinaAIIcon,
JiraIcon,
@@ -111,7 +107,6 @@ import {
Neo4jIcon,
NotionIcon,
ObsidianIcon,
OktaIcon,
OnePasswordIcon,
OpenAIIcon,
OutlookIcon,
@@ -126,7 +121,6 @@ import {
PosthogIcon,
PulseIcon,
QdrantIcon,
QuiverIcon,
RDSIcon,
RedditIcon,
RedisIcon,
@@ -168,7 +162,6 @@ import {
WhatsAppIcon,
WikipediaIcon,
WordpressIcon,
WorkdayIcon,
xIcon,
YouTubeIcon,
ZendeskIcon,
@@ -191,7 +184,6 @@ export const blockTypeToIconMap: Record<string, IconComponent> = {
asana: AsanaIcon,
ashby: AshbyIcon,
attio: AttioIcon,
box: BoxCompanyIcon,
brandfetch: BrandfetchIcon,
browser_use: BrowserUseIcon,
calcom: CalComIcon,
@@ -206,7 +198,6 @@ export const blockTypeToIconMap: Record<string, IconComponent> = {
datadog: DatadogIcon,
devin: DevinIcon,
discord: DiscordIcon,
docusign: DocuSignIcon,
dropbox: DropboxIcon,
dspy: DsPyIcon,
dub: DubIcon,
@@ -255,7 +246,6 @@ export const blockTypeToIconMap: Record<string, IconComponent> = {
image_generator: ImageIcon,
imap: MailServerIcon,
incidentio: IncidentioIcon,
infisical: InfisicalIcon,
intercom_v2: IntercomIcon,
jina: JinaAIIcon,
jira: JiraIcon,
@@ -273,7 +263,6 @@ export const blockTypeToIconMap: Record<string, IconComponent> = {
mailgun: MailgunIcon,
mem0: Mem0Icon,
memory: BrainIcon,
microsoft_ad: AzureIcon,
microsoft_dataverse: MicrosoftDataverseIcon,
microsoft_excel_v2: MicrosoftExcelIcon,
microsoft_planner: MicrosoftPlannerIcon,
@@ -284,7 +273,6 @@ export const blockTypeToIconMap: Record<string, IconComponent> = {
neo4j: Neo4jIcon,
notion_v2: NotionIcon,
obsidian: ObsidianIcon,
okta: OktaIcon,
onedrive: MicrosoftOneDriveIcon,
onepassword: OnePasswordIcon,
openai: OpenAIIcon,
@@ -299,7 +287,6 @@ export const blockTypeToIconMap: Record<string, IconComponent> = {
posthog: PosthogIcon,
pulse_v2: PulseIcon,
qdrant: QdrantIcon,
quiver: QuiverIcon,
rds: RDSIcon,
reddit: RedditIcon,
redis: RedisIcon,
@@ -344,7 +331,6 @@ export const blockTypeToIconMap: Record<string, IconComponent> = {
whatsapp: WhatsAppIcon,
wikipedia: WikipediaIcon,
wordpress: WordpressIcon,
workday: WorkdayIcon,
x: xIcon,
youtube: YouTubeIcon,
zendesk: ZendeskIcon,

View File

@@ -13,7 +13,6 @@
"mailer",
"skills",
"knowledgebase",
"tables",
"variables",
"credentials",
"execution",

View File

@@ -1,158 +0,0 @@
---
title: Tables
description: Store, query, and manage structured data directly within your workspace
---
import { Callout } from 'fumadocs-ui/components/callout'
import { Image } from '@/components/ui/image'
import { FAQ } from '@/components/ui/faq'
Tables let you store and manage structured data directly in your workspace. Use them to maintain reference data, collect workflow outputs, or build lightweight databases — all without leaving Sim.
<Image src="/static/tables/tables-overview.png" alt="Tables view showing structured data with typed columns for name, title, company, role, and more" width={800} height={500} />
Each table has a schema of typed columns, supports filtering and sorting, and is fully accessible through the [Tables API](/docs/en/api-reference/(generated)/tables).
## Creating a Table
1. Open the **Tables** section from your workspace sidebar
2. Click **New table**
3. Name your table and start adding columns
Tables start with a single text column. Add more columns by clicking **New column** in the column header area.
## Column Types
Each column has a type that determines how values are stored and validated.
| Type | Description | Example Values |
|------|-------------|----------------|
| **Text** | Free-form string | `"Acme Corp"`, `"hello@example.com"` |
| **Number** | Numeric value | `42`, `3.14`, `-100` |
| **Boolean** | True or false | `true`, `false` |
| **Date** | Date value | `2026-03-16` |
| **JSON** | Structured object or array | `{"key": "value"}`, `[1, 2, 3]` |
<Callout type="info">
Column types are enforced on input. For example, typing into a Number column is restricted to digits, dots, and minus signs. Non-numeric values entered via paste are coerced to `0`.
</Callout>
## Working with Rows
### Adding Rows
- Click **New row** below the last row to append a new row
- Press **Shift + Enter** while a cell is selected to insert a row below
- Paste tabular data (from a spreadsheet or TSV) to bulk-create rows
### Editing Cells
Click a cell to select it, then press **Enter**, **F2**, or start typing to edit. Press **Escape** to cancel, or **Tab** to save and move to the next cell.
### Selecting Rows
Click a row's checkbox to select it. Selecting additional checkboxes adds to the selection without clearing previous selections.
| Action | Behavior |
|--------|----------|
| Click checkbox | Toggle that row's selection |
| Shift + click checkbox | Select range from last clicked to current |
| Click header checkbox | Select all / deselect all |
| Shift + Space | Toggle row selection from keyboard |
### Deleting Rows
Right-click a selected row (or group of selected rows) and choose **Delete row** from the context menu.
## Filtering and Sorting
Use the toolbar above the table to filter and sort your data.
- **Filter**: Set conditions on any column (e.g., "Name contains Acme"). Multiple filters are combined with AND logic.
- **Sort**: Order rows by any column, ascending or descending.
Filters and sorts are applied in real time and do not modify the underlying data.
## Keyboard Shortcuts
All shortcuts work when the table is focused and no cell is being edited.
<Callout type="info">
**Mod** refers to `Cmd` on macOS and `Ctrl` on Windows/Linux.
</Callout>
### Navigation
| Shortcut | Action |
|----------|--------|
| Arrow keys | Move one cell |
| `Mod` + Arrow keys | Jump to edge of table |
| `Tab` / `Shift` + `Tab` | Move to next / previous cell |
| `Escape` | Clear selection |
### Selection
| Shortcut | Action |
|----------|--------|
| `Shift` + Arrow keys | Extend selection by one cell |
| `Mod` + `Shift` + Arrow keys | Extend selection to edge |
| `Mod` + `A` | Select all rows |
| `Shift` + `Space` | Toggle current row selection |
### Editing
| Shortcut | Action |
|----------|--------|
| `Enter` or `F2` | Start editing selected cell |
| `Escape` | Cancel editing |
| Type any character | Start editing with that character |
| `Shift` + `Enter` | Insert new row below |
| `Space` | Expand row details |
### Clipboard
| Shortcut | Action |
|----------|--------|
| `Mod` + `C` | Copy selected cells |
| `Mod` + `X` | Cut selected cells |
| `Mod` + `V` | Paste |
| `Delete` / `Backspace` | Clear selected cells (all columns when using checkbox selection) |
### History
| Shortcut | Action |
|----------|--------|
| `Mod` + `Z` | Undo |
| `Mod` + `Shift` + `Z` | Redo |
| `Mod` + `Y` | Redo (alternative) |
## Using Tables in Workflows
Tables can be read from and written to within your workflows using the **Table** block. Common patterns include:
- **Lookup**: Query a table for reference data (e.g., pricing rules, customer metadata)
- **Write-back**: Store workflow outputs in a table for later review or reporting
- **Iteration**: Process each row in a table as part of a batch workflow
## API Access
Tables are fully accessible through the REST API. You can create, read, update, and delete both tables and rows programmatically.
See the [Tables API Reference](/docs/en/api-reference/(generated)/tables) for endpoints, parameters, and examples.
## Best Practices
- **Use typed columns** to enforce data integrity — prefer Number and Boolean over storing everything as Text
- **Name columns descriptively** so they are self-documenting when referenced in workflows
- **Use JSON columns sparingly** — they are flexible but harder to filter and sort against
- **Leverage the API** for bulk imports rather than manually entering large datasets
<FAQ items={[
{ question: "Is there a row limit per table?", answer: "Tables are designed for working datasets. For very large datasets (100k+ rows), consider paginating API reads or splitting data across multiple tables." },
{ question: "Can I import data from a spreadsheet?", answer: "Yes. Copy rows from any spreadsheet application and paste them directly into the table. Column values will be validated against the column types." },
{ question: "Do tables support formulas?", answer: "Tables store raw data and do not support computed formulas. Use workflow logic (Function block or Agent block) to derive computed values and write them back to the table." },
{ question: "Can multiple workflows write to the same table?", answer: "Yes. Table writes are atomic at the row level, so multiple workflows can safely write to the same table concurrently." },
{ question: "How do I reference a table from a workflow?", answer: "Use the Table block in your workflow. Select the target table from the dropdown, choose an operation (read, write, update), and configure the parameters." },
{ question: "Are tables shared across workspace members?", answer: "Yes. Tables are workspace-scoped and accessible to all members with appropriate permissions." },
{ question: "Can I undo changes?", answer: "In the table editor, Cmd/Ctrl+Z undoes recent cell edits, row insertions, and row deletions. API-driven changes are not covered by the editor's undo history." },
]} />

View File

@@ -30,50 +30,12 @@ In Sim, the Ashby integration enables your agents to programmatically manage you
## Usage Instructions
Integrate Ashby into the workflow. Manage candidates (list, get, create, update, search, tag), applications (list, get, create, change stage), jobs (list, get), job postings (list, get), offers (list, get), notes (list, create), interviews (list), and reference data (sources, tags, archive reasons, custom fields, departments, locations, openings, users).
Integrate Ashby into the workflow. Can list, search, create, and update candidates, list and get job details, create notes, list notes, list and get applications, create applications, and list offers.
## Tools
### `ashby_add_candidate_tag`
Adds a tag to a candidate in Ashby.
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `apiKey` | string | Yes | Ashby API Key |
| `candidateId` | string | Yes | The UUID of the candidate to add the tag to |
| `tagId` | string | Yes | The UUID of the tag to add |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `success` | boolean | Whether the tag was successfully added |
### `ashby_change_application_stage`
Moves an application to a different interview stage. Requires an archive reason when moving to an Archived stage.
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `apiKey` | string | Yes | Ashby API Key |
| `applicationId` | string | Yes | The UUID of the application to update the stage of |
| `interviewStageId` | string | Yes | The UUID of the interview stage to move the application to |
| `archiveReasonId` | string | No | Archive reason UUID. Required when moving to an Archived stage, ignored otherwise |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `applicationId` | string | Application UUID |
| `stageId` | string | New interview stage UUID |
### `ashby_create_application`
Creates a new application for a candidate on a job. Optionally specify interview plan, stage, source, and credited user.
@@ -95,7 +57,23 @@ Creates a new application for a candidate on a job. Optionally specify interview
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `applicationId` | string | Created application UUID |
| `id` | string | Created application UUID |
| `status` | string | Application status \(Active, Hired, Archived, Lead\) |
| `candidate` | object | Associated candidate |
| ↳ `id` | string | Candidate UUID |
| ↳ `name` | string | Candidate name |
| `job` | object | Associated job |
| ↳ `id` | string | Job UUID |
| ↳ `title` | string | Job title |
| `currentInterviewStage` | object | Current interview stage |
| ↳ `id` | string | Stage UUID |
| ↳ `title` | string | Stage title |
| ↳ `type` | string | Stage type |
| `source` | object | Application source |
| ↳ `id` | string | Source UUID |
| ↳ `title` | string | Source title |
| `createdAt` | string | ISO 8601 creation timestamp |
| `updatedAt` | string | ISO 8601 last update timestamp |
### `ashby_create_candidate`
@@ -107,8 +85,10 @@ Creates a new candidate record in Ashby.
| --------- | ---- | -------- | ----------- |
| `apiKey` | string | Yes | Ashby API Key |
| `name` | string | Yes | The candidate full name |
| `email` | string | Yes | Primary email address for the candidate |
| `email` | string | No | Primary email address for the candidate |
| `emailType` | string | No | Email address type: Personal, Work, or Other \(default Work\) |
| `phoneNumber` | string | No | Primary phone number for the candidate |
| `phoneType` | string | No | Phone number type: Personal, Work, or Other \(default Work\) |
| `linkedInUrl` | string | No | LinkedIn profile URL |
| `githubUrl` | string | No | GitHub profile URL |
| `sourceId` | string | No | UUID of the source to attribute the candidate to |
@@ -147,7 +127,14 @@ Creates a note on a candidate in Ashby. Supports plain text and HTML content (bo
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `noteId` | string | Created note UUID |
| `id` | string | Created note UUID |
| `content` | string | Note content as stored |
| `author` | object | Note author |
| ↳ `id` | string | Author user UUID |
| ↳ `firstName` | string | First name |
| ↳ `lastName` | string | Last name |
| ↳ `email` | string | Email address |
| `createdAt` | string | ISO 8601 creation timestamp |
### `ashby_get_application`
@@ -241,7 +228,7 @@ Retrieves full details about a single job by its ID.
| --------- | ---- | ----------- |
| `id` | string | Job UUID |
| `title` | string | Job title |
| `status` | string | Job status \(Open, Closed, Draft, Archived\) |
| `status` | string | Job status \(Open, Closed, Draft, Archived, On Hold\) |
| `employmentType` | string | Employment type \(FullTime, PartTime, Intern, Contract, Temporary\) |
| `departmentId` | string | Department UUID |
| `locationId` | string | Location UUID |
@@ -250,58 +237,6 @@ Retrieves full details about a single job by its ID.
| `createdAt` | string | ISO 8601 creation timestamp |
| `updatedAt` | string | ISO 8601 last update timestamp |
### `ashby_get_job_posting`
Retrieves full details about a single job posting by its ID.
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `apiKey` | string | Yes | Ashby API Key |
| `jobPostingId` | string | Yes | The UUID of the job posting to fetch |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `id` | string | Job posting UUID |
| `title` | string | Job posting title |
| `jobId` | string | Associated job UUID |
| `locationName` | string | Location name |
| `departmentName` | string | Department name |
| `employmentType` | string | Employment type \(e.g. FullTime, PartTime, Contract\) |
| `descriptionPlain` | string | Job posting description in plain text |
| `isListed` | boolean | Whether the posting is publicly listed |
| `publishedDate` | string | ISO 8601 published date |
| `externalLink` | string | External link to the job posting |
### `ashby_get_offer`
Retrieves full details about a single offer by its ID.
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `apiKey` | string | Yes | Ashby API Key |
| `offerId` | string | Yes | The UUID of the offer to fetch |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `id` | string | Offer UUID |
| `offerStatus` | string | Offer status \(e.g. WaitingOnCandidateResponse, CandidateAccepted\) |
| `acceptanceStatus` | string | Acceptance status \(e.g. Accepted, Declined, Pending\) |
| `applicationId` | string | Associated application UUID |
| `startDate` | string | Offer start date |
| `salary` | object | Salary details |
| ↳ `currencyCode` | string | ISO 4217 currency code |
| ↳ `value` | number | Salary amount |
| `openingId` | string | Associated opening UUID |
| `createdAt` | string | ISO 8601 creation timestamp \(from latest version\) |
### `ashby_list_applications`
Lists all applications in an Ashby organization with pagination and optional filters for status, job, candidate, and creation date.
@@ -343,45 +278,6 @@ Lists all applications in an Ashby organization with pagination and optional fil
| `moreDataAvailable` | boolean | Whether more pages of results exist |
| `nextCursor` | string | Opaque cursor for fetching the next page |
### `ashby_list_archive_reasons`
Lists all archive reasons configured in Ashby.
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `apiKey` | string | Yes | Ashby API Key |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `archiveReasons` | array | List of archive reasons |
| ↳ `id` | string | Archive reason UUID |
| ↳ `text` | string | Archive reason text |
| ↳ `reasonType` | string | Reason type |
| ↳ `isArchived` | boolean | Whether the reason is archived |
### `ashby_list_candidate_tags`
Lists all candidate tags configured in Ashby.
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `apiKey` | string | Yes | Ashby API Key |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `tags` | array | List of candidate tags |
| ↳ `id` | string | Tag UUID |
| ↳ `title` | string | Tag title |
| ↳ `isArchived` | boolean | Whether the tag is archived |
### `ashby_list_candidates`
Lists all candidates in an Ashby organization with cursor-based pagination.
@@ -414,98 +310,6 @@ Lists all candidates in an Ashby organization with cursor-based pagination.
| `moreDataAvailable` | boolean | Whether more pages of results exist |
| `nextCursor` | string | Opaque cursor for fetching the next page |
### `ashby_list_custom_fields`
Lists all custom field definitions configured in Ashby.
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `apiKey` | string | Yes | Ashby API Key |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `customFields` | array | List of custom field definitions |
| ↳ `id` | string | Custom field UUID |
| ↳ `title` | string | Custom field title |
| ↳ `fieldType` | string | Field type \(e.g. String, Number, Boolean\) |
| ↳ `objectType` | string | Object type the field applies to \(e.g. Candidate, Application, Job\) |
| ↳ `isArchived` | boolean | Whether the custom field is archived |
### `ashby_list_departments`
Lists all departments in Ashby.
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `apiKey` | string | Yes | Ashby API Key |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `departments` | array | List of departments |
| ↳ `id` | string | Department UUID |
| ↳ `name` | string | Department name |
| ↳ `isArchived` | boolean | Whether the department is archived |
| ↳ `parentId` | string | Parent department UUID |
### `ashby_list_interviews`
Lists interview schedules in Ashby, optionally filtered by application or interview stage.
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `apiKey` | string | Yes | Ashby API Key |
| `applicationId` | string | No | The UUID of the application to list interview schedules for |
| `interviewStageId` | string | No | The UUID of the interview stage to list interview schedules for |
| `cursor` | string | No | Opaque pagination cursor from a previous response nextCursor value |
| `perPage` | number | No | Number of results per page \(default 100\) |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `interviewSchedules` | array | List of interview schedules |
| ↳ `id` | string | Interview schedule UUID |
| ↳ `applicationId` | string | Associated application UUID |
| ↳ `interviewStageId` | string | Interview stage UUID |
| ↳ `status` | string | Schedule status |
| ↳ `createdAt` | string | ISO 8601 creation timestamp |
| `moreDataAvailable` | boolean | Whether more pages of results exist |
| `nextCursor` | string | Opaque cursor for fetching the next page |
### `ashby_list_job_postings`
Lists all job postings in Ashby.
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `apiKey` | string | Yes | Ashby API Key |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `jobPostings` | array | List of job postings |
| ↳ `id` | string | Job posting UUID |
| ↳ `title` | string | Job posting title |
| ↳ `jobId` | string | Associated job UUID |
| ↳ `locationName` | string | Location name |
| ↳ `departmentName` | string | Department name |
| ↳ `employmentType` | string | Employment type \(e.g. FullTime, PartTime, Contract\) |
| ↳ `isListed` | boolean | Whether the posting is publicly listed |
| ↳ `publishedDate` | string | ISO 8601 published date |
### `ashby_list_jobs`
Lists all jobs in an Ashby organization. By default returns Open, Closed, and Archived jobs. Specify status to filter.
@@ -535,30 +339,6 @@ Lists all jobs in an Ashby organization. By default returns Open, Closed, and Ar
| `moreDataAvailable` | boolean | Whether more pages of results exist |
| `nextCursor` | string | Opaque cursor for fetching the next page |
### `ashby_list_locations`
Lists all locations configured in Ashby.
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `apiKey` | string | Yes | Ashby API Key |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `locations` | array | List of locations |
| ↳ `id` | string | Location UUID |
| ↳ `name` | string | Location name |
| ↳ `isArchived` | boolean | Whether the location is archived |
| ↳ `isRemote` | boolean | Whether this is a remote location |
| ↳ `address` | object | Location address |
| ↳ `city` | string | City |
| ↳ `region` | string | State or region |
| ↳ `country` | string | Country |
### `ashby_list_notes`
Lists all notes on a candidate with pagination support.
@@ -606,106 +386,18 @@ Lists all offers with their latest version in an Ashby organization.
| --------- | ---- | ----------- |
| `offers` | array | List of offers |
| ↳ `id` | string | Offer UUID |
| ↳ `offerStatus` | string | Offer status |
| ↳ `acceptanceStatus` | string | Acceptance status |
| ↳ `applicationId` | string | Associated application UUID |
| ↳ `startDate` | string | Offer start date |
| ↳ `salary` | object | Salary details |
| ↳ `currencyCode` | string | ISO 4217 currency code |
| ↳ `value` | number | Salary amount |
| ↳ `openingId` | string | Associated opening UUID |
| ↳ `status` | string | Offer status |
| ↳ `candidate` | object | Associated candidate |
| ↳ `id` | string | Candidate UUID |
| ↳ `name` | string | Candidate name |
| ↳ `job` | object | Associated job |
| ↳ `id` | string | Job UUID |
| ↳ `title` | string | Job title |
| ↳ `createdAt` | string | ISO 8601 creation timestamp |
| ↳ `updatedAt` | string | ISO 8601 last update timestamp |
| `moreDataAvailable` | boolean | Whether more pages of results exist |
| `nextCursor` | string | Opaque cursor for fetching the next page |
### `ashby_list_openings`
Lists all openings in Ashby with pagination.
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `apiKey` | string | Yes | Ashby API Key |
| `cursor` | string | No | Opaque pagination cursor from a previous response nextCursor value |
| `perPage` | number | No | Number of results per page \(default 100\) |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `openings` | array | List of openings |
| ↳ `id` | string | Opening UUID |
| ↳ `openingState` | string | Opening state \(Approved, Closed, Draft, Filled, Open\) |
| ↳ `isArchived` | boolean | Whether the opening is archived |
| ↳ `openedAt` | string | ISO 8601 opened timestamp |
| ↳ `closedAt` | string | ISO 8601 closed timestamp |
| `moreDataAvailable` | boolean | Whether more pages of results exist |
| `nextCursor` | string | Opaque cursor for fetching the next page |
### `ashby_list_sources`
Lists all candidate sources configured in Ashby.
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `apiKey` | string | Yes | Ashby API Key |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `sources` | array | List of sources |
| ↳ `id` | string | Source UUID |
| ↳ `title` | string | Source title |
| ↳ `isArchived` | boolean | Whether the source is archived |
### `ashby_list_users`
Lists all users in Ashby with pagination.
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `apiKey` | string | Yes | Ashby API Key |
| `cursor` | string | No | Opaque pagination cursor from a previous response nextCursor value |
| `perPage` | number | No | Number of results per page \(default 100\) |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `users` | array | List of users |
| ↳ `id` | string | User UUID |
| ↳ `firstName` | string | First name |
| ↳ `lastName` | string | Last name |
| ↳ `email` | string | Email address |
| ↳ `isEnabled` | boolean | Whether the user account is enabled |
| ↳ `globalRole` | string | User role \(Organization Admin, Elevated Access, Limited Access, External Recruiter\) |
| `moreDataAvailable` | boolean | Whether more pages of results exist |
| `nextCursor` | string | Opaque cursor for fetching the next page |
### `ashby_remove_candidate_tag`
Removes a tag from a candidate in Ashby.
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `apiKey` | string | Yes | Ashby API Key |
| `candidateId` | string | Yes | The UUID of the candidate to remove the tag from |
| `tagId` | string | Yes | The UUID of the tag to remove |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `success` | boolean | Whether the tag was successfully removed |
### `ashby_search_candidates`
Searches for candidates by name and/or email with AND logic. Results are limited to 100 matches. Use candidate.list for full pagination.
@@ -733,8 +425,6 @@ Searches for candidates by name and/or email with AND logic. Results are limited
| ↳ `value` | string | Phone number |
| ↳ `type` | string | Contact type \(Personal, Work, Other\) |
| ↳ `isPrimary` | boolean | Whether this is the primary phone |
| ↳ `createdAt` | string | ISO 8601 creation timestamp |
| ↳ `updatedAt` | string | ISO 8601 last update timestamp |
### `ashby_update_candidate`
@@ -748,7 +438,9 @@ Updates an existing candidate record in Ashby. Only provided fields are changed.
| `candidateId` | string | Yes | The UUID of the candidate to update |
| `name` | string | No | Updated full name |
| `email` | string | No | Updated primary email address |
| `emailType` | string | No | Email address type: Personal, Work, or Other \(default Work\) |
| `phoneNumber` | string | No | Updated primary phone number |
| `phoneType` | string | No | Phone number type: Personal, Work, or Other \(default Work\) |
| `linkedInUrl` | string | No | LinkedIn profile URL |
| `githubUrl` | string | No | GitHub profile URL |
| `websiteUrl` | string | No | Personal website URL |

View File

@@ -1,440 +0,0 @@
---
title: Box
description: Manage files, folders, and e-signatures with Box
---
import { BlockInfoCard } from "@/components/ui/block-info-card"
<BlockInfoCard
type="box"
color="#FFFFFF"
/>
{/* MANUAL-CONTENT-START:intro */}
[Box](https://www.box.com/) is a leading cloud content management and file sharing platform trusted by enterprises worldwide to securely store, manage, and collaborate on files. Box provides robust APIs for automating file operations and integrating with business workflows, including [Box Sign](https://www.box.com/esignature) for native e-signatures.
With the Box integration in Sim, you can:
- **Upload files**: Upload documents, images, and other files to any Box folder
- **Download files**: Retrieve file content from Box for processing in your workflows
- **Get file info**: Access detailed metadata including size, owner, timestamps, tags, and shared links
- **List folder contents**: Browse files and folders with sorting and pagination support
- **Create folders**: Organize your Box storage by creating new folders programmatically
- **Delete files and folders**: Remove content with optional recursive deletion for folders
- **Copy files**: Duplicate files across folders with optional renaming
- **Search**: Find files and folders by name, content, extension, or location
- **Update file metadata**: Rename, move, add descriptions, or tag files
- **Create sign requests**: Send documents for e-signature with one or more signers
- **Track signing status**: Monitor the progress of sign requests
- **List sign requests**: View all sign requests with marker-based pagination
- **Cancel sign requests**: Cancel pending sign requests that are no longer needed
- **Resend sign reminders**: Send reminder notifications to signers who haven't completed signing
These capabilities allow your Sim agents to automate Box operations directly within your workflows — from organizing documents and distributing content to processing uploaded files, managing e-signature workflows for offer letters and contracts, and maintaining structured cloud storage as part of your business processes.
{/* MANUAL-CONTENT-END */}
## Usage Instructions
Integrate Box into your workflow to manage files, folders, and e-signatures. Upload and download files, search content, create folders, send documents for e-signature, track signing status, and more.
## Tools
### `box_upload_file`
Upload a file to a Box folder
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `parentFolderId` | string | Yes | The ID of the folder to upload the file to \(use "0" for root\) |
| `file` | file | No | The file to upload \(UserFile object\) |
| `fileContent` | string | No | Legacy: base64 encoded file content |
| `fileName` | string | No | Optional filename override |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `id` | string | File ID |
| `name` | string | File name |
| `size` | number | File size in bytes |
| `sha1` | string | SHA1 hash of file content |
| `createdAt` | string | Creation timestamp |
| `modifiedAt` | string | Last modified timestamp |
| `parentId` | string | Parent folder ID |
| `parentName` | string | Parent folder name |
### `box_download_file`
Download a file from Box
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `fileId` | string | Yes | The ID of the file to download |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `file` | file | Downloaded file stored in execution files |
| `content` | string | Base64 encoded file content |
### `box_get_file_info`
Get detailed information about a file in Box
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `fileId` | string | Yes | The ID of the file to get information about |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `id` | string | File ID |
| `name` | string | File name |
| `description` | string | File description |
| `size` | number | File size in bytes |
| `sha1` | string | SHA1 hash of file content |
| `createdAt` | string | Creation timestamp |
| `modifiedAt` | string | Last modified timestamp |
| `createdBy` | object | User who created the file |
| `modifiedBy` | object | User who last modified the file |
| `ownedBy` | object | User who owns the file |
| `parentId` | string | Parent folder ID |
| `parentName` | string | Parent folder name |
| `sharedLink` | json | Shared link details |
| `tags` | array | File tags |
| `commentCount` | number | Number of comments |
### `box_list_folder_items`
List files and folders in a Box folder
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `folderId` | string | Yes | The ID of the folder to list items from \(use "0" for root\) |
| `limit` | number | No | Maximum number of items to return per page |
| `offset` | number | No | The offset for pagination |
| `sort` | string | No | Sort field: id, name, date, or size |
| `direction` | string | No | Sort direction: ASC or DESC |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `entries` | array | List of items in the folder |
| ↳ `type` | string | Item type \(file, folder, web_link\) |
| ↳ `id` | string | Item ID |
| ↳ `name` | string | Item name |
| ↳ `size` | number | Item size in bytes |
| ↳ `createdAt` | string | Creation timestamp |
| ↳ `modifiedAt` | string | Last modified timestamp |
| `totalCount` | number | Total number of items in the folder |
| `offset` | number | Current pagination offset |
| `limit` | number | Current pagination limit |
### `box_create_folder`
Create a new folder in Box
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `name` | string | Yes | Name for the new folder |
| `parentFolderId` | string | Yes | The ID of the parent folder \(use "0" for root\) |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `id` | string | Folder ID |
| `name` | string | Folder name |
| `createdAt` | string | Creation timestamp |
| `modifiedAt` | string | Last modified timestamp |
| `parentId` | string | Parent folder ID |
| `parentName` | string | Parent folder name |
### `box_delete_file`
Delete a file from Box
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `fileId` | string | Yes | The ID of the file to delete |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `deleted` | boolean | Whether the file was successfully deleted |
| `message` | string | Success confirmation message |
### `box_delete_folder`
Delete a folder from Box
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `folderId` | string | Yes | The ID of the folder to delete |
| `recursive` | boolean | No | Delete folder and all its contents recursively |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `deleted` | boolean | Whether the folder was successfully deleted |
| `message` | string | Success confirmation message |
### `box_copy_file`
Copy a file to another folder in Box
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `fileId` | string | Yes | The ID of the file to copy |
| `parentFolderId` | string | Yes | The ID of the destination folder |
| `name` | string | No | Optional new name for the copied file |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `id` | string | File ID |
| `name` | string | File name |
| `size` | number | File size in bytes |
| `sha1` | string | SHA1 hash of file content |
| `createdAt` | string | Creation timestamp |
| `modifiedAt` | string | Last modified timestamp |
| `parentId` | string | Parent folder ID |
| `parentName` | string | Parent folder name |
### `box_search`
Search for files and folders in Box
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `query` | string | Yes | The search query string |
| `limit` | number | No | Maximum number of results to return |
| `offset` | number | No | The offset for pagination |
| `ancestorFolderId` | string | No | Restrict search to a specific folder and its subfolders |
| `fileExtensions` | string | No | Comma-separated file extensions to filter by \(e.g., pdf,docx\) |
| `type` | string | No | Restrict to a specific content type: file, folder, or web_link |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `results` | array | Search results |
| ↳ `type` | string | Item type \(file, folder, web_link\) |
| ↳ `id` | string | Item ID |
| ↳ `name` | string | Item name |
| ↳ `size` | number | Item size in bytes |
| ↳ `createdAt` | string | Creation timestamp |
| ↳ `modifiedAt` | string | Last modified timestamp |
| ↳ `parentId` | string | Parent folder ID |
| ↳ `parentName` | string | Parent folder name |
| `totalCount` | number | Total number of matching results |
### `box_update_file`
Update file info in Box (rename, move, change description, add tags)
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `fileId` | string | Yes | The ID of the file to update |
| `name` | string | No | New name for the file |
| `description` | string | No | New description for the file \(max 256 characters\) |
| `parentFolderId` | string | No | Move the file to a different folder by specifying the folder ID |
| `tags` | string | No | Comma-separated tags to set on the file |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `id` | string | File ID |
| `name` | string | File name |
| `description` | string | File description |
| `size` | number | File size in bytes |
| `sha1` | string | SHA1 hash of file content |
| `createdAt` | string | Creation timestamp |
| `modifiedAt` | string | Last modified timestamp |
| `createdBy` | object | User who created the file |
| `modifiedBy` | object | User who last modified the file |
| `ownedBy` | object | User who owns the file |
| `parentId` | string | Parent folder ID |
| `parentName` | string | Parent folder name |
| `sharedLink` | json | Shared link details |
| `tags` | array | File tags |
| `commentCount` | number | Number of comments |
### `box_sign_create_request`
Create a new Box Sign request to send documents for e-signature
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `sourceFileIds` | string | Yes | Comma-separated Box file IDs to send for signing |
| `signerEmail` | string | Yes | Primary signer email address |
| `signerRole` | string | No | Primary signer role: signer, approver, or final_copy_reader \(default: signer\) |
| `additionalSigners` | string | No | JSON array of additional signers, e.g. \[\{"email":"user@example.com","role":"signer"\}\] |
| `parentFolderId` | string | No | Box folder ID where signed documents will be stored \(default: user root\) |
| `emailSubject` | string | No | Custom subject line for the signing email |
| `emailMessage` | string | No | Custom message in the signing email body |
| `name` | string | No | Name for the sign request |
| `daysValid` | number | No | Number of days before the request expires \(0-730\) |
| `areRemindersEnabled` | boolean | No | Whether to send automatic signing reminders |
| `areTextSignaturesEnabled` | boolean | No | Whether to allow typed \(text\) signatures |
| `signatureColor` | string | No | Signature color: blue, black, or red |
| `redirectUrl` | string | No | URL to redirect signers to after signing |
| `declinedRedirectUrl` | string | No | URL to redirect signers to after declining |
| `isDocumentPreparationNeeded` | boolean | No | Whether document preparation is needed before sending |
| `externalId` | string | No | External system reference ID |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `id` | string | Sign request ID |
| `status` | string | Request status \(converting, created, sent, viewed, signed, cancelled, declined, expired, error_converting, error_sending, finalizing, error_finalizing\) |
| `name` | string | Sign request name |
| `shortId` | string | Human-readable short ID |
| `signers` | array | List of signers |
| `sourceFiles` | array | Source files for signing |
| `emailSubject` | string | Custom email subject line |
| `emailMessage` | string | Custom email message body |
| `daysValid` | number | Number of days the request is valid |
| `createdAt` | string | Creation timestamp |
| `autoExpireAt` | string | Auto-expiration timestamp |
| `prepareUrl` | string | URL for document preparation \(if preparation is needed\) |
| `senderEmail` | string | Email of the sender |
### `box_sign_get_request`
Get the details and status of a Box Sign request
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `signRequestId` | string | Yes | The ID of the sign request to retrieve |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `id` | string | Sign request ID |
| `status` | string | Request status \(converting, created, sent, viewed, signed, cancelled, declined, expired, error_converting, error_sending, finalizing, error_finalizing\) |
| `name` | string | Sign request name |
| `shortId` | string | Human-readable short ID |
| `signers` | array | List of signers |
| `sourceFiles` | array | Source files for signing |
| `emailSubject` | string | Custom email subject line |
| `emailMessage` | string | Custom email message body |
| `daysValid` | number | Number of days the request is valid |
| `createdAt` | string | Creation timestamp |
| `autoExpireAt` | string | Auto-expiration timestamp |
| `prepareUrl` | string | URL for document preparation \(if preparation is needed\) |
| `senderEmail` | string | Email of the sender |
### `box_sign_list_requests`
List all Box Sign requests
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `limit` | number | No | Maximum number of sign requests to return \(max 1000\) |
| `marker` | string | No | Pagination marker from a previous response |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `signRequests` | array | List of sign requests |
| ↳ `id` | string | Sign request ID |
| ↳ `status` | string | Request status \(converting, created, sent, viewed, signed, cancelled, declined, expired, error_converting, error_sending, finalizing, error_finalizing\) |
| ↳ `name` | string | Sign request name |
| ↳ `shortId` | string | Human-readable short ID |
| ↳ `signers` | array | List of signers |
| ↳ `sourceFiles` | array | Source files for signing |
| ↳ `emailSubject` | string | Custom email subject line |
| ↳ `emailMessage` | string | Custom email message body |
| ↳ `daysValid` | number | Number of days the request is valid |
| ↳ `createdAt` | string | Creation timestamp |
| ↳ `autoExpireAt` | string | Auto-expiration timestamp |
| ↳ `prepareUrl` | string | URL for document preparation \(if preparation is needed\) |
| ↳ `senderEmail` | string | Email of the sender |
| `count` | number | Number of sign requests returned in this page |
| `nextMarker` | string | Marker for next page of results |
### `box_sign_cancel_request`
Cancel a pending Box Sign request
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `signRequestId` | string | Yes | The ID of the sign request to cancel |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `id` | string | Sign request ID |
| `status` | string | Request status \(converting, created, sent, viewed, signed, cancelled, declined, expired, error_converting, error_sending, finalizing, error_finalizing\) |
| `name` | string | Sign request name |
| `shortId` | string | Human-readable short ID |
| `signers` | array | List of signers |
| `sourceFiles` | array | Source files for signing |
| `emailSubject` | string | Custom email subject line |
| `emailMessage` | string | Custom email message body |
| `daysValid` | number | Number of days the request is valid |
| `createdAt` | string | Creation timestamp |
| `autoExpireAt` | string | Auto-expiration timestamp |
| `prepareUrl` | string | URL for document preparation \(if preparation is needed\) |
| `senderEmail` | string | Email of the sender |
### `box_sign_resend_request`
Resend a Box Sign request to signers who have not yet signed
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `signRequestId` | string | Yes | The ID of the sign request to resend |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `message` | string | Success confirmation message |

View File

@@ -1,230 +0,0 @@
---
title: DocuSign
description: Send documents for e-signature via DocuSign
---
import { BlockInfoCard } from "@/components/ui/block-info-card"
<BlockInfoCard
type="docusign"
color="#FFFFFF"
/>
{/* MANUAL-CONTENT-START:intro */}
[DocuSign](https://www.docusign.com) is the world's leading e-signature platform, enabling businesses to send, sign, and manage agreements digitally. With its powerful eSignature REST API, DocuSign supports the full document lifecycle from creation through completion.
With the DocuSign integration in Sim, you can:
- **Send envelopes**: Create and send documents for e-signature with custom recipients and signing tabs
- **Use templates**: Send envelopes from pre-configured DocuSign templates with role assignments
- **Track status**: Get envelope details including signing progress, timestamps, and recipient status
- **List envelopes**: Search and filter envelopes by date range, status, and text
- **Download documents**: Retrieve signed documents as base64-encoded files
- **Manage recipients**: View signer and CC recipient details and signing status
- **Void envelopes**: Cancel in-progress envelopes with a reason
In Sim, the DocuSign integration enables your agents to automate document workflows end-to-end. Agents can generate agreements, send them for signature, monitor completion, and retrieve signed copies—powering contract management, HR onboarding, sales closings, and compliance processes.
{/* MANUAL-CONTENT-END */}
## Usage Instructions
Create and send envelopes for e-signature, use templates, check signing status, download signed documents, and manage recipients with DocuSign.
## Tools
### `docusign_send_envelope`
Create and send a DocuSign envelope with a document for e-signature
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `emailSubject` | string | Yes | Email subject for the envelope |
| `emailBody` | string | No | Email body message |
| `signerEmail` | string | Yes | Email address of the signer |
| `signerName` | string | Yes | Full name of the signer |
| `ccEmail` | string | No | Email address of carbon copy recipient |
| `ccName` | string | No | Full name of carbon copy recipient |
| `file` | file | No | Document file to send for signature |
| `status` | string | No | Envelope status: "sent" to send immediately, "created" for draft \(default: "sent"\) |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `envelopeId` | string | Created envelope ID |
| `status` | string | Envelope status |
| `statusDateTime` | string | Status change datetime |
| `uri` | string | Envelope URI |
### `docusign_create_from_template`
Create and send a DocuSign envelope using a pre-built template
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `templateId` | string | Yes | DocuSign template ID to use |
| `emailSubject` | string | No | Override email subject \(uses template default if not set\) |
| `emailBody` | string | No | Override email body message |
| `templateRoles` | string | Yes | JSON array of template roles, e.g. \[\{"roleName":"Signer","name":"John","email":"john@example.com"\}\] |
| `status` | string | No | Envelope status: "sent" to send immediately, "created" for draft \(default: "sent"\) |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `envelopeId` | string | Created envelope ID |
| `status` | string | Envelope status |
| `statusDateTime` | string | Status change datetime |
| `uri` | string | Envelope URI |
### `docusign_get_envelope`
Get the details and status of a DocuSign envelope
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `envelopeId` | string | Yes | The envelope ID to retrieve |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `envelopeId` | string | Envelope ID |
| `status` | string | Envelope status \(created, sent, delivered, completed, declined, voided\) |
| `emailSubject` | string | Email subject line |
| `sentDateTime` | string | When the envelope was sent |
| `completedDateTime` | string | When all recipients completed signing |
| `createdDateTime` | string | When the envelope was created |
| `statusChangedDateTime` | string | When the status last changed |
| `voidedReason` | string | Reason the envelope was voided |
| `signerCount` | number | Number of signers |
| `documentCount` | number | Number of documents |
### `docusign_list_envelopes`
List envelopes from your DocuSign account with optional filters
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `fromDate` | string | No | Start date filter \(ISO 8601\). Defaults to 30 days ago |
| `toDate` | string | No | End date filter \(ISO 8601\) |
| `envelopeStatus` | string | No | Filter by status: created, sent, delivered, completed, declined, voided |
| `searchText` | string | No | Search text to filter envelopes |
| `count` | string | No | Maximum number of envelopes to return \(default: 25\) |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `envelopes` | array | Array of DocuSign envelopes |
| ↳ `envelopeId` | string | Unique envelope identifier |
| ↳ `status` | string | Envelope status \(created, sent, delivered, completed, declined, voided\) |
| ↳ `emailSubject` | string | Email subject line |
| ↳ `sentDateTime` | string | ISO 8601 datetime when envelope was sent |
| ↳ `completedDateTime` | string | ISO 8601 datetime when envelope was completed |
| ↳ `createdDateTime` | string | ISO 8601 datetime when envelope was created |
| ↳ `statusChangedDateTime` | string | ISO 8601 datetime of last status change |
| `totalSetSize` | number | Total number of matching envelopes |
| `resultSetSize` | number | Number of envelopes returned in this response |
### `docusign_void_envelope`
Void (cancel) a sent DocuSign envelope that has not yet been completed
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `envelopeId` | string | Yes | The envelope ID to void |
| `voidedReason` | string | Yes | Reason for voiding the envelope |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `envelopeId` | string | Voided envelope ID |
| `status` | string | Envelope status \(voided\) |
### `docusign_download_document`
Download a signed document from a completed DocuSign envelope
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `envelopeId` | string | Yes | The envelope ID containing the document |
| `documentId` | string | No | Specific document ID to download, or "combined" for all documents merged \(default: "combined"\) |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `base64Content` | string | Base64-encoded document content |
| `mimeType` | string | MIME type of the document |
| `fileName` | string | Original file name |
### `docusign_list_templates`
List available templates in your DocuSign account
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `searchText` | string | No | Search text to filter templates by name |
| `count` | string | No | Maximum number of templates to return |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `templates` | array | Array of DocuSign templates |
| ↳ `templateId` | string | Template identifier |
| ↳ `name` | string | Template name |
| ↳ `description` | string | Template description |
| ↳ `shared` | boolean | Whether template is shared |
| ↳ `created` | string | ISO 8601 creation date |
| ↳ `lastModified` | string | ISO 8601 last modified date |
| `totalSetSize` | number | Total number of matching templates |
| `resultSetSize` | number | Number of templates returned in this response |
### `docusign_list_recipients`
Get the recipient status details for a DocuSign envelope
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `envelopeId` | string | Yes | The envelope ID to get recipients for |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `signers` | array | Array of DocuSign recipients |
| ↳ `recipientId` | string | Recipient identifier |
| ↳ `name` | string | Recipient name |
| ↳ `email` | string | Recipient email address |
| ↳ `status` | string | Recipient signing status \(sent, delivered, completed, declined\) |
| ↳ `signedDateTime` | string | ISO 8601 datetime when recipient signed |
| ↳ `deliveredDateTime` | string | ISO 8601 datetime when delivered to recipient |
| `carbonCopies` | array | Array of carbon copy recipients |
| ↳ `recipientId` | string | Recipient ID |
| ↳ `name` | string | Recipient name |
| ↳ `email` | string | Recipient email |
| ↳ `status` | string | Recipient status |

View File

@@ -53,9 +53,6 @@ Extract structured content from web pages with comprehensive metadata support. C
| `url` | string | Yes | The URL to scrape content from \(e.g., "https://example.com/page"\) |
| `scrapeOptions` | json | No | Options for content scraping |
| `apiKey` | string | Yes | Firecrawl API key |
| `pricing` | custom | No | No description |
| `metadata` | string | No | No description |
| `rateLimit` | string | No | No description |
#### Output
@@ -89,9 +86,6 @@ Search for information on the web using Firecrawl
| --------- | ---- | -------- | ----------- |
| `query` | string | Yes | The search query to use |
| `apiKey` | string | Yes | Firecrawl API key |
| `pricing` | custom | No | No description |
| `metadata` | string | No | No description |
| `rateLimit` | string | No | No description |
#### Output
@@ -129,9 +123,6 @@ Crawl entire websites and extract structured content from all accessible pages
| `includePaths` | json | No | URL paths to include in crawling \(e.g., \["/docs/*", "/api/*"\]\). Only these paths will be crawled |
| `onlyMainContent` | boolean | No | Extract only main content from pages |
| `apiKey` | string | Yes | Firecrawl API Key |
| `pricing` | custom | No | No description |
| `metadata` | string | No | No description |
| `rateLimit` | string | No | No description |
#### Output
@@ -151,6 +142,7 @@ Crawl entire websites and extract structured content from all accessible pages
| ↳ `statusCode` | number | HTTP status code |
| ↳ `ogLocaleAlternate` | array | Alternate locale versions |
| `total` | number | Total number of pages found during crawl |
| `creditsUsed` | number | Number of credits consumed by the crawl operation |
### `firecrawl_map`
@@ -169,9 +161,6 @@ Get a complete list of URLs from any website quickly and reliably. Useful for di
| `timeout` | number | No | Request timeout in milliseconds |
| `location` | json | No | Geographic context for proxying \(country, languages\) |
| `apiKey` | string | Yes | Firecrawl API key |
| `pricing` | custom | No | No description |
| `metadata` | string | No | No description |
| `rateLimit` | string | No | No description |
#### Output
@@ -198,9 +187,6 @@ Extract structured data from entire webpages using natural language prompts and
| `ignoreInvalidURLs` | boolean | No | Skip invalid URLs in the array \(default: true\) |
| `scrapeOptions` | json | No | Advanced scraping configuration options |
| `apiKey` | string | Yes | Firecrawl API key |
| `pricing` | custom | No | No description |
| `metadata` | string | No | No description |
| `rateLimit` | string | No | No description |
#### Output
@@ -231,6 +217,7 @@ Autonomous web data extraction agent. Searches and gathers information based on
| `success` | boolean | Whether the agent operation was successful |
| `status` | string | Current status of the agent job \(processing, completed, failed\) |
| `data` | object | Extracted data from the agent |
| `creditsUsed` | number | Number of credits consumed by this agent task |
| `expiresAt` | string | Timestamp when the results expire \(24 hours\) |
| `sources` | object | Array of source URLs used by the agent |

View File

@@ -46,8 +46,6 @@ Search for books using the Google Books API
| `startIndex` | number | No | Index of the first result to return \(for pagination\) |
| `maxResults` | number | No | Maximum number of results to return \(1-40\) |
| `langRestrict` | string | No | Restrict results to a specific language \(ISO 639-1 code\) |
| `pricing` | per_request | No | No description |
| `rateLimit` | string | No | No description |
#### Output
@@ -84,8 +82,6 @@ Get detailed information about a specific book volume
| `apiKey` | string | Yes | Google Books API key |
| `volumeId` | string | Yes | The ID of the volume to retrieve |
| `projection` | string | No | Projection level \(full, lite\) |
| `pricing` | per_request | No | No description |
| `rateLimit` | string | No | No description |
#### Output

View File

@@ -50,8 +50,6 @@ Get current air quality data for a location
| `lat` | number | Yes | Latitude coordinate |
| `lng` | number | Yes | Longitude coordinate |
| `languageCode` | string | No | Language code for the response \(e.g., "en", "es"\) |
| `pricing` | per_request | No | No description |
| `rateLimit` | string | No | No description |
#### Output
@@ -93,8 +91,6 @@ Get directions and route information between two locations
| `waypoints` | json | No | Array of intermediate waypoints |
| `units` | string | No | Unit system: metric or imperial |
| `language` | string | No | Language code for results \(e.g., en, es, fr\) |
| `pricing` | per_request | No | No description |
| `rateLimit` | string | No | No description |
#### Output
@@ -139,8 +135,6 @@ Calculate travel distance and time between multiple origins and destinations
| `avoid` | string | No | Features to avoid: tolls, highways, or ferries |
| `units` | string | No | Unit system: metric or imperial |
| `language` | string | No | Language code for results \(e.g., en, es, fr\) |
| `pricing` | per_request | No | No description |
| `rateLimit` | string | No | No description |
#### Output
@@ -169,8 +163,6 @@ Get elevation data for a location
| `apiKey` | string | Yes | Google Maps API key |
| `lat` | number | Yes | Latitude coordinate |
| `lng` | number | Yes | Longitude coordinate |
| `pricing` | per_request | No | No description |
| `rateLimit` | string | No | No description |
#### Output
@@ -193,8 +185,6 @@ Convert an address into geographic coordinates (latitude and longitude)
| `address` | string | Yes | The address to geocode |
| `language` | string | No | Language code for results \(e.g., en, es, fr\) |
| `region` | string | No | Region bias as a ccTLD code \(e.g., us, uk\) |
| `pricing` | per_request | No | No description |
| `rateLimit` | string | No | No description |
#### Output
@@ -227,8 +217,6 @@ Geolocate a device using WiFi access points, cell towers, or IP address
| `considerIp` | boolean | No | Whether to use IP address for geolocation \(default: true\) |
| `cellTowers` | array | No | Array of cell tower objects with cellId, locationAreaCode, mobileCountryCode, mobileNetworkCode |
| `wifiAccessPoints` | array | No | Array of WiFi access point objects with macAddress \(required\), signalStrength, etc. |
| `pricing` | per_request | No | No description |
| `rateLimit` | string | No | No description |
#### Output
@@ -250,8 +238,6 @@ Get detailed information about a specific place
| `placeId` | string | Yes | Google Place ID |
| `fields` | string | No | Comma-separated list of fields to return |
| `language` | string | No | Language code for results \(e.g., en, es, fr\) |
| `pricing` | per_request | No | No description |
| `rateLimit` | string | No | No description |
#### Output
@@ -304,8 +290,6 @@ Search for places using a text query
| `type` | string | No | Place type filter \(e.g., restaurant, cafe, hotel\) |
| `language` | string | No | Language code for results \(e.g., en, es, fr\) |
| `region` | string | No | Region bias as a ccTLD code \(e.g., us, uk\) |
| `pricing` | per_request | No | No description |
| `rateLimit` | string | No | No description |
#### Output
@@ -338,8 +322,6 @@ Convert geographic coordinates (latitude and longitude) into a human-readable ad
| `lat` | number | Yes | Latitude coordinate |
| `lng` | number | Yes | Longitude coordinate |
| `language` | string | No | Language code for results \(e.g., en, es, fr\) |
| `pricing` | per_request | No | No description |
| `rateLimit` | string | No | No description |
#### Output
@@ -364,8 +346,6 @@ Snap GPS coordinates to the nearest road segment
| `apiKey` | string | Yes | Google Maps API key with Roads API enabled |
| `path` | string | Yes | Pipe-separated list of lat,lng coordinates \(e.g., "60.170880,24.942795\|60.170879,24.942796"\) |
| `interpolate` | boolean | No | Whether to interpolate additional points along the road |
| `pricing` | per_request | No | No description |
| `rateLimit` | string | No | No description |
#### Output
@@ -419,8 +399,6 @@ Get timezone information for a location
| `lng` | number | Yes | Longitude coordinate |
| `timestamp` | number | No | Unix timestamp to determine DST offset \(defaults to current time\) |
| `language` | string | No | Language code for timezone name \(e.g., en, es, fr\) |
| `pricing` | per_request | No | No description |
| `rateLimit` | string | No | No description |
#### Output
@@ -446,8 +424,6 @@ Validate and standardize a postal address
| `regionCode` | string | No | ISO 3166-1 alpha-2 country code \(e.g., "US", "CA"\) |
| `locality` | string | No | City or locality name |
| `enableUspsCass` | boolean | No | Enable USPS CASS validation for US addresses |
| `pricing` | per_request | No | No description |
| `rateLimit` | string | No | No description |
#### Output

View File

@@ -55,8 +55,6 @@ Analyze a webpage for performance, accessibility, SEO, and best practices using
| `category` | string | No | Lighthouse categories to analyze \(comma-separated\): performance, accessibility, best-practices, seo |
| `strategy` | string | No | Analysis strategy: desktop or mobile |
| `locale` | string | No | Locale for results \(e.g., en, fr, de\) |
| `pricing` | per_request | No | No description |
| `rateLimit` | string | No | No description |
#### Output

View File

@@ -43,9 +43,6 @@ Translate text between languages using the Google Cloud Translation API. Support
| `target` | string | Yes | Target language code \(e.g., "es", "fr", "de", "ja"\) |
| `source` | string | No | Source language code. If omitted, the API will auto-detect the source language. |
| `format` | string | No | Format of the text: "text" for plain text, "html" for HTML content |
| `pricing` | custom | No | No description |
| `metadata` | string | No | No description |
| `rateLimit` | string | No | No description |
#### Output
@@ -64,9 +61,6 @@ Detect the language of text using the Google Cloud Translation API.
| --------- | ---- | -------- | ----------- |
| `apiKey` | string | Yes | Google Cloud API key with Cloud Translation API enabled |
| `text` | string | Yes | The text to detect the language of |
| `pricing` | custom | No | No description |
| `metadata` | string | No | No description |
| `rateLimit` | string | No | No description |
#### Output

View File

@@ -138,26 +138,6 @@ Get the full transcript of a recording
| ↳ `end` | number | End timestamp in ms |
| ↳ `text` | string | Transcript text |
### `grain_list_views`
List available Grain views for webhook subscriptions
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `apiKey` | string | Yes | Grain API key \(Personal Access Token\) |
| `typeFilter` | string | No | Optional view type filter: recordings, highlights, or stories |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `views` | array | Array of Grain views |
| ↳ `id` | string | View UUID |
| ↳ `name` | string | View name |
| ↳ `type` | string | View type: recordings, highlights, or stories |
### `grain_list_teams`
List all teams in the workspace
@@ -205,9 +185,15 @@ Create a webhook to receive recording events
| --------- | ---- | -------- | ----------- |
| `apiKey` | string | Yes | Grain API key \(Personal Access Token\) |
| `hookUrl` | string | Yes | Webhook endpoint URL \(e.g., "https://example.com/webhooks/grain"\) |
| `viewId` | string | Yes | Grain view ID from GET /_/public-api/views |
| `actions` | array | No | Optional list of actions to subscribe to: added, updated, removed |
| `items` | string | No | No description |
| `hookType` | string | Yes | Type of webhook: "recording_added" or "upload_status" |
| `filterBeforeDatetime` | string | No | Filter: recordings before this ISO8601 date \(e.g., "2024-01-15T00:00:00Z"\) |
| `filterAfterDatetime` | string | No | Filter: recordings after this ISO8601 date \(e.g., "2024-01-01T00:00:00Z"\) |
| `filterParticipantScope` | string | No | Filter: "internal" or "external" |
| `filterTeamId` | string | No | Filter: specific team UUID \(e.g., "a1b2c3d4-e5f6-7890-abcd-ef1234567890"\) |
| `filterMeetingTypeId` | string | No | Filter: specific meeting type UUID \(e.g., "a1b2c3d4-e5f6-7890-abcd-ef1234567890"\) |
| `includeHighlights` | boolean | No | Include highlights in webhook payload |
| `includeParticipants` | boolean | No | Include participants in webhook payload |
| `includeAiSummary` | boolean | No | Include AI summary in webhook payload |
#### Output
@@ -216,8 +202,9 @@ Create a webhook to receive recording events
| `id` | string | Hook UUID |
| `enabled` | boolean | Whether hook is active |
| `hook_url` | string | The webhook URL |
| `view_id` | string | Grain view ID for the webhook |
| `actions` | array | Configured actions for the webhook |
| `hook_type` | string | Type of hook: recording_added or upload_status |
| `filter` | object | Applied filters |
| `include` | object | Included fields |
| `inserted_at` | string | ISO8601 creation timestamp |
### `grain_list_hooks`
@@ -238,8 +225,9 @@ List all webhooks for the account
| ↳ `id` | string | Hook UUID |
| ↳ `enabled` | boolean | Whether hook is active |
| ↳ `hook_url` | string | Webhook URL |
| ↳ `view_id` | string | Grain view ID |
| ↳ `actions` | array | Configured actions |
| ↳ `hook_type` | string | Type: recording_added or upload_status |
| ↳ `filter` | object | Applied filters |
| ↳ `include` | object | Included fields |
| ↳ `inserted_at` | string | Creation timestamp |
### `grain_delete_hook`

View File

@@ -1,255 +0,0 @@
---
title: Infisical
description: Manage secrets with Infisical
---
import { BlockInfoCard } from "@/components/ui/block-info-card"
<BlockInfoCard
type="infisical"
color="#F7FE62"
/>
{/* MANUAL-CONTENT-START:intro */}
[Infisical](https://infisical.com/) is an open-source secrets management platform that helps teams centralize and manage application secrets, environment variables, and sensitive configuration data across their infrastructure. This integration brings Infisical's secrets management capabilities directly into Sim workflows.
With Infisical in Sim, you can:
- **List secrets**: Retrieve all secrets from a project environment with filtering by path, tags, and recursive subdirectory support
- **Get a secret**: Fetch a specific secret by name, with optional version pinning and secret reference expansion
- **Create secrets**: Add new secrets to any project environment with support for comments, paths, and tag assignments
- **Update secrets**: Modify existing secret values, comments, names, and tags
- **Delete secrets**: Remove secrets from a project environment
In Sim, the Infisical integration enables your agents to programmatically manage secrets as part of automated workflows — for example, rotating credentials, syncing environment variables across environments, or auditing secret usage. Simply configure the Infisical block with your API key, select the operation, and provide the project ID and environment slug to get started.
{/* MANUAL-CONTENT-END */}
## Usage Instructions
Integrate Infisical into your workflow. List, get, create, update, and delete secrets across project environments.
## Tools
### `infisical_list_secrets`
List all secrets in a project environment. Returns secret keys, values, comments, tags, and metadata.
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `apiKey` | string | Yes | Infisical API token |
| `baseUrl` | string | No | Infisical instance URL \(default: "https://us.infisical.com"\). Use "https://eu.infisical.com" for EU Cloud or your self-hosted URL. |
| `projectId` | string | Yes | The ID of the project to list secrets from |
| `environment` | string | Yes | The environment slug \(e.g., "dev", "staging", "prod"\) |
| `secretPath` | string | No | The path of the secrets \(default: "/"\) |
| `recursive` | boolean | No | Whether to fetch secrets recursively from subdirectories |
| `expandSecretReferences` | boolean | No | Whether to expand secret references \(default: true\) |
| `viewSecretValue` | boolean | No | Whether to include secret values in the response \(default: true\) |
| `includeImports` | boolean | No | Whether to include imported secrets \(default: true\) |
| `tagSlugs` | string | No | Comma-separated tag slugs to filter secrets by |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `secrets` | array | Array of secrets |
| ↳ `id` | string | Secret ID |
| ↳ `workspace` | string | Workspace/project ID |
| ↳ `secretKey` | string | Secret name/key |
| ↳ `secretValue` | string | Secret value |
| ↳ `secretComment` | string | Secret comment |
| ↳ `secretPath` | string | Secret path |
| ↳ `version` | number | Secret version |
| ↳ `type` | string | Secret type \(shared or personal\) |
| ↳ `environment` | string | Environment slug |
| ↳ `tags` | array | Tags attached to the secret |
| ↳ `id` | string | Tag ID |
| ↳ `slug` | string | Tag slug |
| ↳ `color` | string | Tag color |
| ↳ `name` | string | Tag name |
| ↳ `secretMetadata` | array | Custom metadata key-value pairs |
| ↳ `key` | string | Metadata key |
| ↳ `value` | string | Metadata value |
| ↳ `createdAt` | string | Creation timestamp |
| ↳ `updatedAt` | string | Last update timestamp |
| `count` | number | Total number of secrets returned |
### `infisical_get_secret`
Retrieve a single secret by name from a project environment.
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `apiKey` | string | Yes | Infisical API token |
| `baseUrl` | string | No | Infisical instance URL \(default: "https://us.infisical.com"\). Use "https://eu.infisical.com" for EU Cloud or your self-hosted URL. |
| `projectId` | string | Yes | The ID of the project |
| `environment` | string | Yes | The environment slug \(e.g., "dev", "staging", "prod"\) |
| `secretName` | string | Yes | The name of the secret to retrieve |
| `secretPath` | string | No | The path of the secret \(default: "/"\) |
| `version` | number | No | Specific version of the secret to retrieve |
| `type` | string | No | Secret type: "shared" or "personal" \(default: "shared"\) |
| `viewSecretValue` | boolean | No | Whether to include the secret value in the response \(default: true\) |
| `expandSecretReferences` | boolean | No | Whether to expand secret references \(default: true\) |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `secret` | object | The retrieved secret |
| ↳ `id` | string | Secret ID |
| ↳ `workspace` | string | Workspace/project ID |
| ↳ `secretKey` | string | Secret name/key |
| ↳ `secretValue` | string | Secret value |
| ↳ `secretComment` | string | Secret comment |
| ↳ `secretPath` | string | Secret path |
| ↳ `version` | number | Secret version |
| ↳ `type` | string | Secret type \(shared or personal\) |
| ↳ `environment` | string | Environment slug |
| ↳ `tags` | array | Tags attached to the secret |
| ↳ `id` | string | Tag ID |
| ↳ `slug` | string | Tag slug |
| ↳ `color` | string | Tag color |
| ↳ `name` | string | Tag name |
| ↳ `secretMetadata` | array | Custom metadata key-value pairs |
| ↳ `key` | string | Metadata key |
| ↳ `value` | string | Metadata value |
| ↳ `createdAt` | string | Creation timestamp |
| ↳ `updatedAt` | string | Last update timestamp |
### `infisical_create_secret`
Create a new secret in a project environment.
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `apiKey` | string | Yes | Infisical API token |
| `baseUrl` | string | No | Infisical instance URL \(default: "https://us.infisical.com"\). Use "https://eu.infisical.com" for EU Cloud or your self-hosted URL. |
| `projectId` | string | Yes | The ID of the project |
| `environment` | string | Yes | The environment slug \(e.g., "dev", "staging", "prod"\) |
| `secretName` | string | Yes | The name of the secret to create |
| `secretValue` | string | Yes | The value of the secret |
| `secretPath` | string | No | The path for the secret \(default: "/"\) |
| `secretComment` | string | No | A comment for the secret |
| `type` | string | No | Secret type: "shared" or "personal" \(default: "shared"\) |
| `tagIds` | string | No | Comma-separated tag IDs to attach to the secret |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `secret` | object | The created secret |
| ↳ `id` | string | Secret ID |
| ↳ `workspace` | string | Workspace/project ID |
| ↳ `secretKey` | string | Secret name/key |
| ↳ `secretValue` | string | Secret value |
| ↳ `secretComment` | string | Secret comment |
| ↳ `secretPath` | string | Secret path |
| ↳ `version` | number | Secret version |
| ↳ `type` | string | Secret type \(shared or personal\) |
| ↳ `environment` | string | Environment slug |
| ↳ `tags` | array | Tags attached to the secret |
| ↳ `id` | string | Tag ID |
| ↳ `slug` | string | Tag slug |
| ↳ `color` | string | Tag color |
| ↳ `name` | string | Tag name |
| ↳ `secretMetadata` | array | Custom metadata key-value pairs |
| ↳ `key` | string | Metadata key |
| ↳ `value` | string | Metadata value |
| ↳ `createdAt` | string | Creation timestamp |
| ↳ `updatedAt` | string | Last update timestamp |
### `infisical_update_secret`
Update an existing secret in a project environment.
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `apiKey` | string | Yes | Infisical API token |
| `baseUrl` | string | No | Infisical instance URL \(default: "https://us.infisical.com"\). Use "https://eu.infisical.com" for EU Cloud or your self-hosted URL. |
| `projectId` | string | Yes | The ID of the project |
| `environment` | string | Yes | The environment slug \(e.g., "dev", "staging", "prod"\) |
| `secretName` | string | Yes | The name of the secret to update |
| `secretValue` | string | No | The new value for the secret |
| `secretPath` | string | No | The path of the secret \(default: "/"\) |
| `secretComment` | string | No | A comment for the secret |
| `newSecretName` | string | No | New name for the secret \(to rename it\) |
| `type` | string | No | Secret type: "shared" or "personal" \(default: "shared"\) |
| `tagIds` | string | No | Comma-separated tag IDs to set on the secret |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `secret` | object | The updated secret |
| ↳ `id` | string | Secret ID |
| ↳ `workspace` | string | Workspace/project ID |
| ↳ `secretKey` | string | Secret name/key |
| ↳ `secretValue` | string | Secret value |
| ↳ `secretComment` | string | Secret comment |
| ↳ `secretPath` | string | Secret path |
| ↳ `version` | number | Secret version |
| ↳ `type` | string | Secret type \(shared or personal\) |
| ↳ `environment` | string | Environment slug |
| ↳ `tags` | array | Tags attached to the secret |
| ↳ `id` | string | Tag ID |
| ↳ `slug` | string | Tag slug |
| ↳ `color` | string | Tag color |
| ↳ `name` | string | Tag name |
| ↳ `secretMetadata` | array | Custom metadata key-value pairs |
| ↳ `key` | string | Metadata key |
| ↳ `value` | string | Metadata value |
| ↳ `createdAt` | string | Creation timestamp |
| ↳ `updatedAt` | string | Last update timestamp |
### `infisical_delete_secret`
Delete a secret from a project environment.
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `apiKey` | string | Yes | Infisical API token |
| `baseUrl` | string | No | Infisical instance URL \(default: "https://us.infisical.com"\). Use "https://eu.infisical.com" for EU Cloud or your self-hosted URL. |
| `projectId` | string | Yes | The ID of the project |
| `environment` | string | Yes | The environment slug \(e.g., "dev", "staging", "prod"\) |
| `secretName` | string | Yes | The name of the secret to delete |
| `secretPath` | string | No | The path of the secret \(default: "/"\) |
| `type` | string | No | Secret type: "shared" or "personal" \(default: "shared"\) |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `secret` | object | The deleted secret |
| ↳ `id` | string | Secret ID |
| ↳ `workspace` | string | Workspace/project ID |
| ↳ `secretKey` | string | Secret name/key |
| ↳ `secretValue` | string | Secret value |
| ↳ `secretComment` | string | Secret comment |
| ↳ `secretPath` | string | Secret path |
| ↳ `version` | number | Secret version |
| ↳ `type` | string | Secret type \(shared or personal\) |
| ↳ `environment` | string | Environment slug |
| ↳ `tags` | array | Tags attached to the secret |
| ↳ `id` | string | Tag ID |
| ↳ `slug` | string | Tag slug |
| ↳ `color` | string | Tag color |
| ↳ `name` | string | Tag name |
| ↳ `secretMetadata` | array | Custom metadata key-value pairs |
| ↳ `key` | string | Metadata key |
| ↳ `value` | string | Metadata value |
| ↳ `createdAt` | string | Creation timestamp |
| ↳ `updatedAt` | string | Last update timestamp |

View File

@@ -64,7 +64,6 @@ Extract and process web content into clean, LLM-friendly text using Jina AI Read
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `content` | string | The extracted content from the URL, processed into clean, LLM-friendly text |
| `tokensUsed` | number | Number of Jina tokens consumed by this request |
### `jina_search`
@@ -98,6 +97,5 @@ Search the web and return top 5 results with LLM-friendly content. Each result i
| ↳ `content` | string | LLM-friendly extracted content |
| ↳ `usage` | object | Token usage information |
| ↳ `tokens` | number | Number of tokens consumed by this request |
| `tokensUsed` | number | Number of Jina tokens consumed by this request |

View File

@@ -122,37 +122,6 @@ Create a new document in a knowledge base
| `message` | string | Success or error message describing the operation result |
| `documentId` | string | ID of the created document |
### `knowledge_upsert_document`
Create or update a document in a knowledge base. If a document with the given ID or filename already exists, it will be replaced with the new content.
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `knowledgeBaseId` | string | Yes | ID of the knowledge base containing the document |
| `documentId` | string | No | Optional ID of an existing document to update. If not provided, lookup is done by filename. |
| `name` | string | Yes | Name of the document |
| `content` | string | Yes | Content of the document |
| `documentTags` | json | No | Document tags |
| `documentTags` | string | No | No description |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `data` | object | Information about the upserted document |
| ↳ `documentId` | string | Document ID |
| ↳ `documentName` | string | Document name |
| ↳ `type` | string | Document type |
| ↳ `enabled` | boolean | Whether the document is enabled |
| ↳ `isUpdate` | boolean | Whether an existing document was replaced |
| ↳ `previousDocumentId` | string | ID of the document that was replaced, if any |
| ↳ `createdAt` | string | Creation timestamp |
| ↳ `updatedAt` | string | Last update timestamp |
| `message` | string | Success or error message describing the operation result |
| `documentId` | string | ID of the upserted document |
### `knowledge_list_tags`
List all tag definitions for a knowledge base

View File

@@ -51,9 +51,6 @@ Search the web for information using Linkup
| `includeDomains` | string | No | Comma-separated list of domain names to restrict search results to |
| `includeInlineCitations` | boolean | No | Add inline citations to answers \(only applies when outputType is "sourcedAnswer"\) |
| `includeSources` | boolean | No | Include sources in response |
| `pricing` | custom | No | No description |
| `metadata` | string | No | No description |
| `rateLimit` | string | No | No description |
#### Output

View File

@@ -13,7 +13,6 @@
"asana",
"ashby",
"attio",
"box",
"brandfetch",
"browser_use",
"calcom",
@@ -28,7 +27,6 @@
"datadog",
"devin",
"discord",
"docusign",
"dropbox",
"dspy",
"dub",
@@ -77,7 +75,6 @@
"image_generator",
"imap",
"incidentio",
"infisical",
"intercom",
"jina",
"jira",
@@ -95,7 +92,6 @@
"mailgun",
"mem0",
"memory",
"microsoft_ad",
"microsoft_dataverse",
"microsoft_excel",
"microsoft_planner",
@@ -106,7 +102,6 @@
"neo4j",
"notion",
"obsidian",
"okta",
"onedrive",
"onepassword",
"openai",
@@ -121,7 +116,6 @@
"posthog",
"pulse",
"qdrant",
"quiver",
"rds",
"reddit",
"redis",
@@ -167,7 +161,6 @@
"whatsapp",
"wikipedia",
"wordpress",
"workday",
"x",
"youtube",
"zendesk",

View File

@@ -1,336 +0,0 @@
---
title: Azure AD
description: Manage users and groups in Azure AD (Microsoft Entra ID)
---
import { BlockInfoCard } from "@/components/ui/block-info-card"
<BlockInfoCard
type="microsoft_ad"
color="#0078D4"
/>
{/* MANUAL-CONTENT-START:intro */}
[Azure Active Directory](https://entra.microsoft.com) (now Microsoft Entra ID) is Microsoft's cloud-based identity and access management service. It helps organizations manage users, groups, and access to applications and resources across cloud and on-premises environments.
With the Azure AD integration in Sim, you can:
- **Manage users**: List, create, update, and delete user accounts in your directory
- **Manage groups**: Create and configure security groups and Microsoft 365 groups
- **Control group membership**: Add and remove members from groups programmatically
- **Query directory data**: Search and filter users and groups using OData expressions
- **Automate onboarding/offboarding**: Create new user accounts with initial passwords and enable/disable accounts as part of HR workflows
In Sim, the Azure AD integration enables your agents to programmatically manage your organization's identity infrastructure. This allows for automation scenarios such as provisioning new employees, updating user profiles in bulk, managing team group memberships, and auditing directory data. By connecting Sim with Azure AD, you can streamline identity lifecycle management and ensure your directory stays in sync with your organization's needs.
## Need Help?
If you encounter issues with the Azure AD integration, contact us at [help@sim.ai](mailto:help@sim.ai)
{/* MANUAL-CONTENT-END */}
## Usage Instructions
Integrate Azure Active Directory into your workflows. List, create, update, and delete users and groups. Manage group memberships programmatically.
## Tools
### `microsoft_ad_list_users`
List users in Azure AD (Microsoft Entra ID)
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `top` | number | No | Maximum number of users to return \(default 100, max 999\) |
| `filter` | string | No | OData filter expression \(e.g., "department eq \'Sales\'"\) |
| `search` | string | No | Search string to filter users by displayName or mail |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `users` | array | List of users |
| `userCount` | number | Number of users returned |
### `microsoft_ad_get_user`
Get a user by ID or user principal name from Azure AD
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `userId` | string | Yes | User ID or user principal name \(e.g., "user@example.com"\) |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `user` | object | User details |
| ↳ `id` | string | User ID |
| ↳ `displayName` | string | Display name |
| ↳ `givenName` | string | First name |
| ↳ `surname` | string | Last name |
| ↳ `userPrincipalName` | string | User principal name \(email\) |
| ↳ `mail` | string | Email address |
| ↳ `jobTitle` | string | Job title |
| ↳ `department` | string | Department |
| ↳ `officeLocation` | string | Office location |
| ↳ `mobilePhone` | string | Mobile phone number |
| ↳ `accountEnabled` | boolean | Whether the account is enabled |
### `microsoft_ad_create_user`
Create a new user in Azure AD (Microsoft Entra ID)
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `displayName` | string | Yes | Display name for the user |
| `mailNickname` | string | Yes | Mail alias for the user |
| `userPrincipalName` | string | Yes | User principal name \(e.g., "user@example.com"\) |
| `password` | string | Yes | Initial password for the user |
| `accountEnabled` | boolean | Yes | Whether the account is enabled |
| `givenName` | string | No | First name |
| `surname` | string | No | Last name |
| `jobTitle` | string | No | Job title |
| `department` | string | No | Department |
| `officeLocation` | string | No | Office location |
| `mobilePhone` | string | No | Mobile phone number |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `user` | object | Created user details |
| ↳ `id` | string | User ID |
| ↳ `displayName` | string | Display name |
| ↳ `givenName` | string | First name |
| ↳ `surname` | string | Last name |
| ↳ `userPrincipalName` | string | User principal name \(email\) |
| ↳ `mail` | string | Email address |
| ↳ `jobTitle` | string | Job title |
| ↳ `department` | string | Department |
| ↳ `officeLocation` | string | Office location |
| ↳ `mobilePhone` | string | Mobile phone number |
| ↳ `accountEnabled` | boolean | Whether the account is enabled |
### `microsoft_ad_update_user`
Update user properties in Azure AD (Microsoft Entra ID)
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `userId` | string | Yes | User ID or user principal name |
| `displayName` | string | No | Display name |
| `givenName` | string | No | First name |
| `surname` | string | No | Last name |
| `jobTitle` | string | No | Job title |
| `department` | string | No | Department |
| `officeLocation` | string | No | Office location |
| `mobilePhone` | string | No | Mobile phone number |
| `accountEnabled` | boolean | No | Whether the account is enabled |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `updated` | boolean | Whether the update was successful |
| `userId` | string | ID of the updated user |
### `microsoft_ad_delete_user`
Delete a user from Azure AD (Microsoft Entra ID). The user is moved to a temporary container and can be restored within 30 days.
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `userId` | string | Yes | User ID or user principal name |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `deleted` | boolean | Whether the deletion was successful |
| `userId` | string | ID of the deleted user |
### `microsoft_ad_list_groups`
List groups in Azure AD (Microsoft Entra ID)
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `top` | number | No | Maximum number of groups to return \(default 100, max 999\) |
| `filter` | string | No | OData filter expression \(e.g., "securityEnabled eq true"\) |
| `search` | string | No | Search string to filter groups by displayName or description |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `groups` | array | List of groups |
| `groupCount` | number | Number of groups returned |
### `microsoft_ad_get_group`
Get a group by ID from Azure AD (Microsoft Entra ID)
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `groupId` | string | Yes | Group ID |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `group` | object | Group details |
| ↳ `id` | string | Group ID |
| ↳ `displayName` | string | Display name |
| ↳ `description` | string | Group description |
| ↳ `mail` | string | Email address |
| ↳ `mailEnabled` | boolean | Whether mail is enabled |
| ↳ `mailNickname` | string | Mail nickname |
| ↳ `securityEnabled` | boolean | Whether security is enabled |
| ↳ `groupTypes` | array | Group types |
| ↳ `visibility` | string | Group visibility |
| ↳ `createdDateTime` | string | Creation date |
### `microsoft_ad_create_group`
Create a new group in Azure AD (Microsoft Entra ID)
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `displayName` | string | Yes | Display name for the group |
| `mailNickname` | string | Yes | Mail alias for the group \(ASCII only, max 64 characters\) |
| `description` | string | No | Group description |
| `mailEnabled` | boolean | Yes | Whether mail is enabled \(true for Microsoft 365 groups\) |
| `securityEnabled` | boolean | Yes | Whether security is enabled \(true for security groups\) |
| `groupTypes` | string | No | Group type: "Unified" for Microsoft 365 group, leave empty for security group |
| `visibility` | string | No | Group visibility: "Private" or "Public" |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `group` | object | Created group details |
| ↳ `id` | string | Group ID |
| ↳ `displayName` | string | Display name |
| ↳ `description` | string | Group description |
| ↳ `mail` | string | Email address |
| ↳ `mailEnabled` | boolean | Whether mail is enabled |
| ↳ `mailNickname` | string | Mail nickname |
| ↳ `securityEnabled` | boolean | Whether security is enabled |
| ↳ `groupTypes` | array | Group types |
| ↳ `visibility` | string | Group visibility |
| ↳ `createdDateTime` | string | Creation date |
### `microsoft_ad_update_group`
Update group properties in Azure AD (Microsoft Entra ID)
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `groupId` | string | Yes | Group ID |
| `displayName` | string | No | Display name |
| `description` | string | No | Group description |
| `mailNickname` | string | No | Mail alias |
| `visibility` | string | No | Group visibility: "Private" or "Public" |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `updated` | boolean | Whether the update was successful |
| `groupId` | string | ID of the updated group |
### `microsoft_ad_delete_group`
Delete a group from Azure AD (Microsoft Entra ID). Microsoft 365 and security groups can be restored within 30 days.
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `groupId` | string | Yes | Group ID |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `deleted` | boolean | Whether the deletion was successful |
| `groupId` | string | ID of the deleted group |
### `microsoft_ad_list_group_members`
List members of a group in Azure AD (Microsoft Entra ID)
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `groupId` | string | Yes | Group ID |
| `top` | number | No | Maximum number of members to return \(default 100, max 999\) |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `members` | array | List of group members |
| `memberCount` | number | Number of members returned |
### `microsoft_ad_add_group_member`
Add a member to a group in Azure AD (Microsoft Entra ID)
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `groupId` | string | Yes | Group ID |
| `memberId` | string | Yes | User ID of the member to add |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `added` | boolean | Whether the member was added successfully |
| `groupId` | string | Group ID |
| `memberId` | string | Member ID that was added |
### `microsoft_ad_remove_group_member`
Remove a member from a group in Azure AD (Microsoft Entra ID)
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `groupId` | string | Yes | Group ID |
| `memberId` | string | Yes | User ID of the member to remove |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `removed` | boolean | Whether the member was removed successfully |
| `groupId` | string | Group ID |
| `memberId` | string | Member ID that was removed |

View File

@@ -1,517 +0,0 @@
---
title: Okta
description: Manage users and groups in Okta
---
import { BlockInfoCard } from "@/components/ui/block-info-card"
<BlockInfoCard
type="okta"
color="#191919"
/>
{/* MANUAL-CONTENT-START:intro */}
[Okta](https://www.okta.com/) is an identity and access management platform that provides secure authentication, authorization, and user management for organizations.
With the Okta integration in Sim, you can:
- **List and search users**: Retrieve users from your Okta org with SCIM search expressions and filters
- **Manage user lifecycle**: Create, activate, deactivate, suspend, unsuspend, and delete users
- **Update user profiles**: Modify user attributes like name, email, phone, title, and department
- **Reset passwords**: Trigger password reset flows with optional email notification
- **Manage groups**: Create, update, delete, and list groups in your organization
- **Manage group membership**: Add or remove users from groups, and list group members
In Sim, the Okta integration enables your agents to automate identity management tasks as part of their workflows. This allows for scenarios such as onboarding new employees, offboarding departing users, managing group-based access, auditing user status, and responding to security events by suspending or deactivating accounts.
## Need Help?
If you encounter issues with the Okta integration, contact us at [help@sim.ai](mailto:help@sim.ai)
{/* MANUAL-CONTENT-END */}
## Usage Instructions
Integrate Okta identity management into your workflow. List, create, update, activate, suspend, and delete users. Reset passwords. Manage groups and group membership.
## Tools
### `okta_list_users`
List all users in your Okta organization with optional search and filtering
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `apiKey` | string | Yes | Okta API token for authentication |
| `domain` | string | Yes | Okta domain \(e.g., dev-123456.okta.com\) |
| `search` | string | No | Okta search expression \(e.g., profile.firstName eq "John" or profile.email co "example.com"\) |
| `filter` | string | No | Okta filter expression \(e.g., status eq "ACTIVE"\) |
| `limit` | number | No | Maximum number of users to return \(default: 200, max: 200\) |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `users` | array | Array of Okta user objects |
| ↳ `id` | string | User ID |
| ↳ `status` | string | User status \(ACTIVE, STAGED, PROVISIONED, etc.\) |
| ↳ `firstName` | string | First name |
| ↳ `lastName` | string | Last name |
| ↳ `email` | string | Email address |
| ↳ `login` | string | Login \(usually email\) |
| ↳ `mobilePhone` | string | Mobile phone |
| ↳ `title` | string | Job title |
| ↳ `department` | string | Department |
| ↳ `created` | string | Creation timestamp |
| ↳ `lastLogin` | string | Last login timestamp |
| ↳ `lastUpdated` | string | Last update timestamp |
| ↳ `activated` | string | Activation timestamp |
| ↳ `statusChanged` | string | Status change timestamp |
| `count` | number | Number of users returned |
| `success` | boolean | Operation success status |
### `okta_get_user`
Get a specific user by ID or login from your Okta organization
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `apiKey` | string | Yes | Okta API token for authentication |
| `domain` | string | Yes | Okta domain \(e.g., dev-123456.okta.com\) |
| `userId` | string | Yes | User ID or login \(email\) to look up |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `id` | string | User ID |
| `status` | string | User status |
| `firstName` | string | First name |
| `lastName` | string | Last name |
| `email` | string | Email address |
| `login` | string | Login \(usually email\) |
| `mobilePhone` | string | Mobile phone |
| `secondEmail` | string | Secondary email |
| `displayName` | string | Display name |
| `title` | string | Job title |
| `department` | string | Department |
| `organization` | string | Organization |
| `manager` | string | Manager name |
| `managerId` | string | Manager ID |
| `division` | string | Division |
| `employeeNumber` | string | Employee number |
| `userType` | string | User type |
| `created` | string | Creation timestamp |
| `activated` | string | Activation timestamp |
| `lastLogin` | string | Last login timestamp |
| `lastUpdated` | string | Last update timestamp |
| `statusChanged` | string | Status change timestamp |
| `passwordChanged` | string | Password change timestamp |
| `success` | boolean | Operation success status |
### `okta_create_user`
Create a new user in your Okta organization
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `apiKey` | string | Yes | Okta API token for authentication |
| `domain` | string | Yes | Okta domain \(e.g., dev-123456.okta.com\) |
| `firstName` | string | Yes | First name of the user |
| `lastName` | string | Yes | Last name of the user |
| `email` | string | Yes | Email address of the user |
| `login` | string | No | Login for the user \(defaults to email if not provided\) |
| `password` | string | No | Password for the user \(if not set, user will be emailed to set password\) |
| `mobilePhone` | string | No | Mobile phone number |
| `title` | string | No | Job title |
| `department` | string | No | Department |
| `activate` | boolean | No | Whether to activate the user immediately \(default: true\) |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `id` | string | Created user ID |
| `status` | string | User status |
| `firstName` | string | First name |
| `lastName` | string | Last name |
| `email` | string | Email address |
| `login` | string | Login |
| `created` | string | Creation timestamp |
| `lastUpdated` | string | Last update timestamp |
| `success` | boolean | Operation success status |
### `okta_update_user`
Update a user profile in your Okta organization
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `apiKey` | string | Yes | Okta API token for authentication |
| `domain` | string | Yes | Okta domain \(e.g., dev-123456.okta.com\) |
| `userId` | string | Yes | User ID or login to update |
| `firstName` | string | No | Updated first name |
| `lastName` | string | No | Updated last name |
| `email` | string | No | Updated email address |
| `login` | string | No | Updated login |
| `mobilePhone` | string | No | Updated mobile phone number |
| `title` | string | No | Updated job title |
| `department` | string | No | Updated department |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `id` | string | User ID |
| `status` | string | User status |
| `firstName` | string | First name |
| `lastName` | string | Last name |
| `email` | string | Email address |
| `login` | string | Login |
| `created` | string | Creation timestamp |
| `lastUpdated` | string | Last update timestamp |
| `success` | boolean | Operation success status |
### `okta_activate_user`
Activate a user in your Okta organization. Can only be performed on users with STAGED or DEPROVISIONED status. Optionally sends an activation email.
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `apiKey` | string | Yes | Okta API token for authentication |
| `domain` | string | Yes | Okta domain \(e.g., dev-123456.okta.com\) |
| `userId` | string | Yes | User ID or login to activate |
| `sendEmail` | boolean | No | Send activation email to the user \(default: true\) |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `userId` | string | Activated user ID |
| `activated` | boolean | Whether the user was activated |
| `activationUrl` | string | Activation URL \(only returned when sendEmail is false\) |
| `activationToken` | string | Activation token \(only returned when sendEmail is false\) |
| `success` | boolean | Operation success status |
### `okta_deactivate_user`
Deactivate a user in your Okta organization. This transitions the user to DEPROVISIONED status.
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `apiKey` | string | Yes | Okta API token for authentication |
| `domain` | string | Yes | Okta domain \(e.g., dev-123456.okta.com\) |
| `userId` | string | Yes | User ID or login to deactivate |
| `sendEmail` | boolean | No | Send deactivation email to admin \(default: false\) |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `userId` | string | Deactivated user ID |
| `deactivated` | boolean | Whether the user was deactivated |
| `success` | boolean | Operation success status |
### `okta_suspend_user`
Suspend a user in your Okta organization. Only users with ACTIVE status can be suspended. Suspended users cannot log in but retain group and app assignments.
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `apiKey` | string | Yes | Okta API token for authentication |
| `domain` | string | Yes | Okta domain \(e.g., dev-123456.okta.com\) |
| `userId` | string | Yes | User ID or login to suspend |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `userId` | string | Suspended user ID |
| `suspended` | boolean | Whether the user was suspended |
| `success` | boolean | Operation success status |
### `okta_unsuspend_user`
Unsuspend a previously suspended user in your Okta organization. Returns the user to ACTIVE status.
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `apiKey` | string | Yes | Okta API token for authentication |
| `domain` | string | Yes | Okta domain \(e.g., dev-123456.okta.com\) |
| `userId` | string | Yes | User ID or login to unsuspend |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `userId` | string | Unsuspended user ID |
| `unsuspended` | boolean | Whether the user was unsuspended |
| `success` | boolean | Operation success status |
### `okta_reset_password`
Generate a one-time token to reset a user password. Can email the reset link to the user or return it directly. Transitions the user to RECOVERY status.
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `apiKey` | string | Yes | Okta API token for authentication |
| `domain` | string | Yes | Okta domain \(e.g., dev-123456.okta.com\) |
| `userId` | string | Yes | User ID or login to reset password for |
| `sendEmail` | boolean | No | Send password reset email to the user \(default: true\) |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `userId` | string | User ID |
| `resetPasswordUrl` | string | Password reset URL \(only returned when sendEmail is false\) |
| `success` | boolean | Operation success status |
### `okta_delete_user`
Permanently delete a user from your Okta organization. Can only be performed on DEPROVISIONED users. If the user is active, this will first deactivate them and a second call is needed to delete.
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `apiKey` | string | Yes | Okta API token for authentication |
| `domain` | string | Yes | Okta domain \(e.g., dev-123456.okta.com\) |
| `userId` | string | Yes | User ID to delete |
| `sendEmail` | boolean | No | Send deactivation email to admin \(default: false\) |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `userId` | string | Deleted user ID |
| `deleted` | boolean | Whether the user was deleted |
| `success` | boolean | Operation success status |
### `okta_list_groups`
List all groups in your Okta organization with optional search and filtering
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `apiKey` | string | Yes | Okta API token for authentication |
| `domain` | string | Yes | Okta domain \(e.g., dev-123456.okta.com\) |
| `search` | string | No | Okta search expression for groups \(e.g., profile.name sw "Engineering" or type eq "OKTA_GROUP"\) |
| `filter` | string | No | Okta filter expression \(e.g., type eq "OKTA_GROUP"\) |
| `limit` | number | No | Maximum number of groups to return \(default: 10000, max: 10000\) |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `groups` | array | Array of Okta group objects |
| ↳ `id` | string | Group ID |
| ↳ `name` | string | Group name |
| ↳ `description` | string | Group description |
| ↳ `type` | string | Group type \(OKTA_GROUP, APP_GROUP, BUILT_IN\) |
| ↳ `created` | string | Creation timestamp |
| ↳ `lastUpdated` | string | Last update timestamp |
| ↳ `lastMembershipUpdated` | string | Last membership change timestamp |
| `count` | number | Number of groups returned |
| `success` | boolean | Operation success status |
### `okta_get_group`
Get a specific group by ID from your Okta organization
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `apiKey` | string | Yes | Okta API token for authentication |
| `domain` | string | Yes | Okta domain \(e.g., dev-123456.okta.com\) |
| `groupId` | string | Yes | Group ID to look up |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `id` | string | Group ID |
| `name` | string | Group name |
| `description` | string | Group description |
| `type` | string | Group type |
| `created` | string | Creation timestamp |
| `lastUpdated` | string | Last update timestamp |
| `lastMembershipUpdated` | string | Last membership change timestamp |
| `success` | boolean | Operation success status |
### `okta_create_group`
Create a new group in your Okta organization
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `apiKey` | string | Yes | Okta API token for authentication |
| `domain` | string | Yes | Okta domain \(e.g., dev-123456.okta.com\) |
| `name` | string | Yes | Name of the group |
| `description` | string | No | Description of the group |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `id` | string | Created group ID |
| `name` | string | Group name |
| `description` | string | Group description |
| `type` | string | Group type |
| `created` | string | Creation timestamp |
| `lastUpdated` | string | Last update timestamp |
| `lastMembershipUpdated` | string | Last membership change timestamp |
| `success` | boolean | Operation success status |
### `okta_update_group`
Update a group profile in your Okta organization. Only groups of OKTA_GROUP type can be updated. All profile properties must be specified (full replacement).
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `apiKey` | string | Yes | Okta API token for authentication |
| `domain` | string | Yes | Okta domain \(e.g., dev-123456.okta.com\) |
| `groupId` | string | Yes | Group ID to update |
| `name` | string | Yes | Updated group name |
| `description` | string | No | Updated group description |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `id` | string | Group ID |
| `name` | string | Group name |
| `description` | string | Group description |
| `type` | string | Group type |
| `created` | string | Creation timestamp |
| `lastUpdated` | string | Last update timestamp |
| `lastMembershipUpdated` | string | Last membership change timestamp |
| `success` | boolean | Operation success status |
### `okta_delete_group`
Delete a group from your Okta organization. Groups of OKTA_GROUP or APP_GROUP type can be removed.
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `apiKey` | string | Yes | Okta API token for authentication |
| `domain` | string | Yes | Okta domain \(e.g., dev-123456.okta.com\) |
| `groupId` | string | Yes | Group ID to delete |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `groupId` | string | Deleted group ID |
| `deleted` | boolean | Whether the group was deleted |
| `success` | boolean | Operation success status |
### `okta_add_user_to_group`
Add a user to a group in your Okta organization
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `apiKey` | string | Yes | Okta API token for authentication |
| `domain` | string | Yes | Okta domain \(e.g., dev-123456.okta.com\) |
| `groupId` | string | Yes | Group ID to add the user to |
| `userId` | string | Yes | User ID to add to the group |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `groupId` | string | Group ID |
| `userId` | string | User ID added to the group |
| `added` | boolean | Whether the user was added |
| `success` | boolean | Operation success status |
### `okta_remove_user_from_group`
Remove a user from a group in your Okta organization
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `apiKey` | string | Yes | Okta API token for authentication |
| `domain` | string | Yes | Okta domain \(e.g., dev-123456.okta.com\) |
| `groupId` | string | Yes | Group ID to remove the user from |
| `userId` | string | Yes | User ID to remove from the group |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `groupId` | string | Group ID |
| `userId` | string | User ID removed from the group |
| `removed` | boolean | Whether the user was removed |
| `success` | boolean | Operation success status |
### `okta_list_group_members`
List all members of a specific group in your Okta organization
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `apiKey` | string | Yes | Okta API token for authentication |
| `domain` | string | Yes | Okta domain \(e.g., dev-123456.okta.com\) |
| `groupId` | string | Yes | Group ID to list members for |
| `limit` | number | No | Maximum number of members to return \(default: 1000, max: 1000\) |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `members` | array | Array of group member user objects |
| ↳ `id` | string | User ID |
| ↳ `status` | string | User status |
| ↳ `firstName` | string | First name |
| ↳ `lastName` | string | Last name |
| ↳ `email` | string | Email address |
| ↳ `login` | string | Login |
| ↳ `mobilePhone` | string | Mobile phone |
| ↳ `title` | string | Job title |
| ↳ `department` | string | Department |
| ↳ `created` | string | Creation timestamp |
| ↳ `lastLogin` | string | Last login timestamp |
| ↳ `lastUpdated` | string | Last update timestamp |
| ↳ `activated` | string | Activation timestamp |
| ↳ `statusChanged` | string | Status change timestamp |
| `count` | number | Number of members returned |
| `success` | boolean | Operation success status |

View File

@@ -49,9 +49,6 @@ Generate completions using Perplexity AI chat models
| `max_tokens` | number | No | Maximum number of tokens to generate \(e.g., 1024, 2048, 4096\) |
| `temperature` | number | No | Sampling temperature between 0 and 1 \(e.g., 0.0 for deterministic, 0.7 for creative\) |
| `apiKey` | string | Yes | Perplexity API key |
| `pricing` | custom | No | No description |
| `metadata` | string | No | No description |
| `rateLimit` | string | No | No description |
#### Output
@@ -81,8 +78,6 @@ Get ranked search results from Perplexity
| `search_after_date` | string | No | Include only content published after this date \(format: MM/DD/YYYY\) |
| `search_before_date` | string | No | Include only content published before this date \(format: MM/DD/YYYY\) |
| `apiKey` | string | Yes | Perplexity API key |
| `pricing` | per_request | No | No description |
| `rateLimit` | string | No | No description |
#### Output

View File

@@ -1,131 +0,0 @@
---
title: Quiver
description: Generate and vectorize SVGs
---
import { BlockInfoCard } from "@/components/ui/block-info-card"
<BlockInfoCard
type="quiver"
color="#000000"
/>
{/* MANUAL-CONTENT-START:intro */}
[QuiverAI](https://quiver.ai/) is an AI-powered SVG generation platform that creates high-quality, scalable vector graphics from text descriptions or by vectorizing raster images. It produces clean, resolution-independent SVGs that are ideal for icons, illustrations, logos, and UI elements.
With Quiver, you can:
- **Generate SVGs from text prompts**: Describe the vector graphic you need and get production-ready SVG output
- **Vectorize raster images**: Convert PNG, JPG, and other raster images into clean SVG vector format
- **Provide reference images**: Upload up to 4 reference images to guide the style and composition of generated SVGs
- **Control generation parameters**: Adjust temperature, number of outputs, and token limits to fine-tune results
- **List available models**: Query available QuiverAI models to discover supported operations and capabilities
- **Get clean SVG markup**: Receive raw SVG content alongside downloadable files for easy embedding
In Sim, the Quiver integration enables your workflows to generate and vectorize graphics on demand. This is useful for creating dynamic illustrations, converting raster assets to scalable vectors, generating icons for applications, producing visual assets for content pipelines, or building design automation workflows. The generated SVGs are returned as files that can be passed to downstream blocks for further processing, storage, or delivery.
{/* MANUAL-CONTENT-END */}
## Usage Instructions
Generate SVG images from text prompts or vectorize raster images into SVGs using QuiverAI. Supports reference images, style instructions, and multiple output generation.
## Tools
### `quiver_text_to_svg`
Generate SVG images from text prompts using QuiverAI
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `apiKey` | string | Yes | QuiverAI API key |
| `prompt` | string | Yes | A text description of the desired SVG |
| `model` | string | Yes | The model to use for SVG generation \(e.g., "arrow-preview"\) |
| `instructions` | string | No | Style or formatting guidance for the SVG output |
| `references` | file | No | Reference images to guide SVG generation \(up to 4\) |
| `n` | number | No | Number of SVGs to generate \(1-16, default 1\) |
| `temperature` | number | No | Sampling temperature \(0-2, default 1\) |
| `top_p` | number | No | Nucleus sampling probability \(0-1, default 1\) |
| `max_output_tokens` | number | No | Maximum output tokens \(1-131072\) |
| `presence_penalty` | number | No | Token penalty for prior output \(-2 to 2, default 0\) |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `success` | boolean | Whether the SVG generation succeeded |
| `output` | object | Generated SVG output |
| ↳ `file` | file | Generated SVG file |
| ↳ `svgContent` | string | Raw SVG markup content |
| ↳ `id` | string | Generation request ID |
| ↳ `usage` | json | Token usage statistics |
| ↳ `totalTokens` | number | Total tokens used |
| ↳ `inputTokens` | number | Input tokens used |
| ↳ `outputTokens` | number | Output tokens used |
### `quiver_image_to_svg`
Convert raster images into vector SVG format using QuiverAI
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `apiKey` | string | Yes | QuiverAI API key |
| `model` | string | Yes | The model to use for vectorization \(e.g., "arrow-preview"\) |
| `image` | file | Yes | The raster image to vectorize into SVG |
| `temperature` | number | No | Sampling temperature \(0-2, default 1\) |
| `top_p` | number | No | Nucleus sampling probability \(0-1, default 1\) |
| `max_output_tokens` | number | No | Maximum output tokens \(1-131072\) |
| `presence_penalty` | number | No | Token penalty for prior output \(-2 to 2, default 0\) |
| `auto_crop` | boolean | No | Automatically crop the image before vectorizing |
| `target_size` | number | No | Square resize target in pixels \(128-4096\) |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `success` | boolean | Whether the vectorization succeeded |
| `output` | object | Vectorized SVG output |
| ↳ `file` | file | Generated SVG file |
| ↳ `svgContent` | string | Raw SVG markup content |
| ↳ `id` | string | Vectorization request ID |
| ↳ `usage` | json | Token usage statistics |
| ↳ `totalTokens` | number | Total tokens used |
| ↳ `inputTokens` | number | Input tokens used |
| ↳ `outputTokens` | number | Output tokens used |
### `quiver_list_models`
List all available QuiverAI models
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `apiKey` | string | Yes | QuiverAI API key |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `success` | boolean | Whether the request succeeded |
| `output` | object | Available models |
| ↳ `models` | json | List of available QuiverAI models |
| ↳ `id` | string | Model identifier |
| ↳ `name` | string | Human-readable model name |
| ↳ `description` | string | Model capabilities summary |
| ↳ `created` | number | Unix timestamp of creation |
| ↳ `ownedBy` | string | Organization that owns the model |
| ↳ `inputModalities` | json | Supported input types \(text, image, svg\) |
| ↳ `outputModalities` | json | Supported output types \(text, image, svg\) |
| ↳ `contextLength` | number | Maximum context window |
| ↳ `maxOutputLength` | number | Maximum generation length |
| ↳ `supportedOperations` | json | Available operations \(svg_generate, svg_edit, svg_animate, svg_vectorize, chat_completions\) |
| ↳ `supportedSamplingParameters` | json | Supported sampling parameters \(temperature, top_p, top_k, repetition_penalty, presence_penalty, stop\) |

View File

@@ -47,9 +47,6 @@ A powerful web search tool that provides access to Google search results through
| `hl` | string | No | Language code for search results \(e.g., "en", "es", "de", "fr"\) |
| `type` | string | No | Type of search to perform \(e.g., "search", "news", "images", "videos", "places", "shopping"\) |
| `apiKey` | string | Yes | Serper API Key |
| `pricing` | custom | No | No description |
| `metadata` | string | No | No description |
| `rateLimit` | string | No | No description |
#### Output

View File

@@ -925,82 +925,6 @@ Create a canvas pinned to a Slack channel as its resource hub
| --------- | ---- | ----------- |
| `canvas_id` | string | ID of the created channel canvas |
### `slack_create_conversation`
Create a new public or private channel in a Slack workspace.
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `authMethod` | string | No | Authentication method: oauth or bot_token |
| `botToken` | string | No | Bot token for Custom Bot |
| `name` | string | Yes | Name of the channel to create \(lowercase, numbers, hyphens, underscores only; max 80 characters\) |
| `isPrivate` | boolean | No | Create a private channel instead of a public one \(default: false\) |
| `teamId` | string | No | Encoded team ID to create the channel in \(required if using an org token\) |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `channelInfo` | object | The newly created channel object |
| ↳ `id` | string | Channel ID \(e.g., C1234567890\) |
| ↳ `name` | string | Channel name without # prefix |
| ↳ `is_channel` | boolean | Whether this is a channel |
| ↳ `is_private` | boolean | Whether channel is private |
| ↳ `is_archived` | boolean | Whether channel is archived |
| ↳ `is_general` | boolean | Whether this is the general channel |
| ↳ `is_member` | boolean | Whether the bot/user is a member |
| ↳ `is_shared` | boolean | Whether channel is shared across workspaces |
| ↳ `is_ext_shared` | boolean | Whether channel is externally shared |
| ↳ `is_org_shared` | boolean | Whether channel is org-wide shared |
| ↳ `num_members` | number | Number of members in the channel |
| ↳ `topic` | string | Channel topic |
| ↳ `purpose` | string | Channel purpose/description |
| ↳ `created` | number | Unix timestamp when channel was created |
| ↳ `creator` | string | User ID of channel creator |
| ↳ `updated` | number | Unix timestamp of last update |
### `slack_invite_to_conversation`
Invite one or more users to a Slack channel. Supports up to 100 users at a time.
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `authMethod` | string | No | Authentication method: oauth or bot_token |
| `botToken` | string | No | Bot token for Custom Bot |
| `channel` | string | Yes | The ID of the channel to invite users to |
| `users` | string | Yes | Comma-separated list of user IDs to invite \(up to 100\) |
| `force` | boolean | No | When true, continues inviting valid users while skipping invalid ones \(default: false\) |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `channelInfo` | object | The channel object after inviting users |
| ↳ `id` | string | Channel ID \(e.g., C1234567890\) |
| ↳ `name` | string | Channel name without # prefix |
| ↳ `is_channel` | boolean | Whether this is a channel |
| ↳ `is_private` | boolean | Whether channel is private |
| ↳ `is_archived` | boolean | Whether channel is archived |
| ↳ `is_general` | boolean | Whether this is the general channel |
| ↳ `is_member` | boolean | Whether the bot/user is a member |
| ↳ `is_shared` | boolean | Whether channel is shared across workspaces |
| ↳ `is_ext_shared` | boolean | Whether channel is externally shared |
| ↳ `is_org_shared` | boolean | Whether channel is org-wide shared |
| ↳ `num_members` | number | Number of members in the channel |
| ↳ `topic` | string | Channel topic |
| ↳ `purpose` | string | Channel purpose/description |
| ↳ `created` | number | Unix timestamp when channel was created |
| ↳ `creator` | string | User ID of channel creator |
| ↳ `updated` | number | Unix timestamp of last update |
| `errors` | array | Per-user errors when force is true and some invitations failed |
| ↳ `user` | string | User ID that failed |
| ↳ `ok` | boolean | Always false for error entries |
| ↳ `error` | string | Error code for this user |
### `slack_open_view`
Open a modal view in Slack using a trigger_id from an interaction payload. Used to display forms, confirmations, and other interactive modals.

View File

@@ -1,262 +0,0 @@
---
title: Workday
description: Manage workers, hiring, onboarding, and HR operations in Workday
---
import { BlockInfoCard } from "@/components/ui/block-info-card"
<BlockInfoCard
type="workday"
color="#F5F0EB"
/>
## Usage Instructions
Integrate Workday HRIS into your workflow. Create pre-hires, hire employees, manage worker profiles, assign onboarding plans, handle job changes, retrieve compensation data, and process terminations.
## Tools
### `workday_get_worker`
Retrieve a specific worker profile including personal, employment, and organization data.
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `tenantUrl` | string | Yes | Workday instance URL \(e.g., https://wd5-impl-services1.workday.com\) |
| `tenant` | string | Yes | Workday tenant name |
| `username` | string | Yes | Integration System User username |
| `password` | string | Yes | Integration System User password |
| `workerId` | string | Yes | Worker ID to retrieve \(e.g., 3aa5550b7fe348b98d7b5741afc65534\) |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `worker` | json | Worker profile with personal, employment, and organization data |
### `workday_list_workers`
List or search workers with optional filtering and pagination.
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `tenantUrl` | string | Yes | Workday instance URL \(e.g., https://wd5-impl-services1.workday.com\) |
| `tenant` | string | Yes | Workday tenant name |
| `username` | string | Yes | Integration System User username |
| `password` | string | Yes | Integration System User password |
| `limit` | number | No | Maximum number of workers to return \(default: 20\) |
| `offset` | number | No | Number of records to skip for pagination |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `workers` | array | Array of worker profiles |
| `total` | number | Total number of matching workers |
### `workday_create_prehire`
Create a new pre-hire (applicant) record in Workday. This is typically the first step before hiring an employee.
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `tenantUrl` | string | Yes | Workday instance URL \(e.g., https://wd5-impl-services1.workday.com\) |
| `tenant` | string | Yes | Workday tenant name |
| `username` | string | Yes | Integration System User username |
| `password` | string | Yes | Integration System User password |
| `legalName` | string | Yes | Full legal name of the pre-hire \(e.g., "Jane Doe"\) |
| `email` | string | No | Email address of the pre-hire |
| `phoneNumber` | string | No | Phone number of the pre-hire |
| `address` | string | No | Address of the pre-hire |
| `countryCode` | string | No | ISO 3166-1 Alpha-2 country code \(defaults to US\) |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `preHireId` | string | ID of the created pre-hire record |
| `descriptor` | string | Display name of the pre-hire |
### `workday_hire_employee`
Hire a pre-hire into an employee position. Converts an applicant into an active employee record with position, start date, and manager assignment.
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `tenantUrl` | string | Yes | Workday instance URL \(e.g., https://wd5-impl-services1.workday.com\) |
| `tenant` | string | Yes | Workday tenant name |
| `username` | string | Yes | Integration System User username |
| `password` | string | Yes | Integration System User password |
| `preHireId` | string | Yes | Pre-hire \(applicant\) ID to convert into an employee |
| `positionId` | string | Yes | Position ID to assign the new hire to |
| `hireDate` | string | Yes | Hire date in ISO 8601 format \(e.g., 2025-06-01\) |
| `employeeType` | string | No | Employee type \(e.g., Regular, Temporary, Contractor\) |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `workerId` | string | Worker ID of the newly hired employee |
| `employeeId` | string | Employee ID assigned to the new hire |
| `eventId` | string | Event ID of the hire business process |
| `hireDate` | string | Effective hire date |
### `workday_update_worker`
Update fields on an existing worker record in Workday.
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `tenantUrl` | string | Yes | Workday instance URL \(e.g., https://wd5-impl-services1.workday.com\) |
| `tenant` | string | Yes | Workday tenant name |
| `username` | string | Yes | Integration System User username |
| `password` | string | Yes | Integration System User password |
| `workerId` | string | Yes | Worker ID to update |
| `fields` | json | Yes | Fields to update as JSON \(e.g., \{"businessTitle": "Senior Engineer", "primaryWorkEmail": "new@company.com"\}\) |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `eventId` | string | Event ID of the change personal information business process |
| `workerId` | string | Worker ID that was updated |
### `workday_assign_onboarding`
Create or update an onboarding plan assignment for a worker. Sets up onboarding stages and manages the assignment lifecycle.
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `tenantUrl` | string | Yes | Workday instance URL \(e.g., https://wd5-impl-services1.workday.com\) |
| `tenant` | string | Yes | Workday tenant name |
| `username` | string | Yes | Integration System User username |
| `password` | string | Yes | Integration System User password |
| `workerId` | string | Yes | Worker ID to assign the onboarding plan to |
| `onboardingPlanId` | string | Yes | Onboarding plan ID to assign |
| `actionEventId` | string | Yes | Action event ID that enables the onboarding plan \(e.g., the hiring event ID\) |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `assignmentId` | string | Onboarding plan assignment ID |
| `workerId` | string | Worker ID the plan was assigned to |
| `planId` | string | Onboarding plan ID that was assigned |
### `workday_get_organizations`
Retrieve organizations, departments, and cost centers from Workday.
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `tenantUrl` | string | Yes | Workday instance URL \(e.g., https://wd5-impl-services1.workday.com\) |
| `tenant` | string | Yes | Workday tenant name |
| `username` | string | Yes | Integration System User username |
| `password` | string | Yes | Integration System User password |
| `type` | string | No | Organization type filter \(e.g., Supervisory, Cost_Center, Company, Region\) |
| `limit` | number | No | Maximum number of organizations to return \(default: 20\) |
| `offset` | number | No | Number of records to skip for pagination |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `organizations` | array | Array of organization records |
| `total` | number | Total number of matching organizations |
### `workday_change_job`
Perform a job change for a worker including transfers, promotions, demotions, and lateral moves.
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `tenantUrl` | string | Yes | Workday instance URL \(e.g., https://wd5-impl-services1.workday.com\) |
| `tenant` | string | Yes | Workday tenant name |
| `username` | string | Yes | Integration System User username |
| `password` | string | Yes | Integration System User password |
| `workerId` | string | Yes | Worker ID for the job change |
| `effectiveDate` | string | Yes | Effective date for the job change in ISO 8601 format \(e.g., 2025-06-01\) |
| `newPositionId` | string | No | New position ID \(for transfers\) |
| `newJobProfileId` | string | No | New job profile ID \(for role changes\) |
| `newLocationId` | string | No | New work location ID \(for relocations\) |
| `newSupervisoryOrgId` | string | No | Target supervisory organization ID \(for org transfers\) |
| `reason` | string | Yes | Reason for the job change \(e.g., Promotion, Transfer, Reorganization\) |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `eventId` | string | Job change event ID |
| `workerId` | string | Worker ID the job change was applied to |
| `effectiveDate` | string | Effective date of the job change |
### `workday_get_compensation`
Retrieve compensation plan details for a specific worker.
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `tenantUrl` | string | Yes | Workday instance URL \(e.g., https://wd5-impl-services1.workday.com\) |
| `tenant` | string | Yes | Workday tenant name |
| `username` | string | Yes | Integration System User username |
| `password` | string | Yes | Integration System User password |
| `workerId` | string | Yes | Worker ID to retrieve compensation data for |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `compensationPlans` | array | Array of compensation plan details |
| ↳ `id` | string | Compensation plan ID |
| ↳ `planName` | string | Name of the compensation plan |
| ↳ `amount` | number | Compensation amount |
| ↳ `currency` | string | Currency code |
| ↳ `frequency` | string | Pay frequency |
### `workday_terminate_worker`
Initiate a worker termination in Workday. Triggers the Terminate Employee business process.
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `tenantUrl` | string | Yes | Workday instance URL \(e.g., https://wd5-impl-services1.workday.com\) |
| `tenant` | string | Yes | Workday tenant name |
| `username` | string | Yes | Integration System User username |
| `password` | string | Yes | Integration System User password |
| `workerId` | string | Yes | Worker ID to terminate |
| `terminationDate` | string | Yes | Termination date in ISO 8601 format \(e.g., 2025-06-01\) |
| `reason` | string | Yes | Termination reason \(e.g., Resignation, End_of_Contract, Retirement\) |
| `notificationDate` | string | No | Date the termination was communicated in ISO 8601 format |
| `lastDayOfWork` | string | No | Last day of work in ISO 8601 format \(defaults to termination date\) |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `eventId` | string | Termination event ID |
| `workerId` | string | Worker ID that was terminated |
| `terminationDate` | string | Effective termination date |

View File

@@ -29,8 +29,8 @@
"next": "16.1.6",
"next-themes": "^0.4.6",
"postgres": "^3.4.5",
"react": "19.2.4",
"react-dom": "19.2.4",
"react": "19.2.1",
"react-dom": "19.2.1",
"shiki": "4.0.0",
"tailwind-merge": "^3.0.2"
},

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.6 KiB

After

Width:  |  Height:  |  Size: 5.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.7 KiB

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.2 KiB

After

Width:  |  Height:  |  Size: 7.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 425 B

After

Width:  |  Height:  |  Size: 521 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 814 B

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.2 KiB

After

Width:  |  Height:  |  Size: 3.6 KiB

View File

@@ -1,42 +1,21 @@
{
"name": "Sim Documentation — Build AI Agents & Run Your Agentic Workforce",
"short_name": "Sim Docs",
"description": "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.",
"start_url": "/",
"scope": "/",
"name": "MyWebSite",
"short_name": "MySite",
"icons": [
{
"src": "/favicon/web-app-manifest-192x192.png",
"src": "/web-app-manifest-192x192.png",
"sizes": "192x192",
"type": "image/png",
"purpose": "maskable"
},
{
"src": "/favicon/web-app-manifest-512x512.png",
"src": "/web-app-manifest-512x512.png",
"sizes": "512x512",
"type": "image/png",
"purpose": "maskable"
},
{
"src": "/favicon/android-chrome-192x192.png",
"sizes": "192x192",
"type": "image/png"
},
{
"src": "/favicon/android-chrome-512x512.png",
"sizes": "512x512",
"type": "image/png"
},
{
"src": "/favicon/apple-touch-icon.png",
"sizes": "180x180",
"type": "image/png"
}
],
"theme_color": "#33C482",
"theme_color": "#ffffff",
"background_color": "#ffffff",
"display": "standalone",
"categories": ["productivity", "developer", "business"],
"lang": "en-US",
"dir": "ltr"
"display": "standalone"
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.4 KiB

After

Width:  |  Height:  |  Size: 7.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

After

Width:  |  Height:  |  Size: 23 KiB

View File

@@ -1 +0,0 @@
<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><linearGradient id="a" gradientUnits="userSpaceOnUse" x1="129.434" x2="185.629" y1="129.266" y2="185.33"><stop offset="0"/><stop offset="1" stop-opacity="0"/></linearGradient><rect fill="#0b0b0b" height="16" rx="3" width="16"/><g transform="matrix(.0473 0 0 .0473 2.75 2.75)"><path clip-rule="evenodd" d="m107.822 93.7612c0 3.5869-1.419 7.0308-3.938 9.5668l-.361.364c-2.517 2.544-5.9375 3.966-9.4994 3.966h-80.5781c-7.42094 0-13.4455 6.06-13.4455 13.533v87.141c0 7.474 6.02456 13.534 13.4455 13.534h86.5167c7.4208 0 13.4378-6.06 13.4378-13.534v-81.587c0-3.326 1.31-6.517 3.647-8.871 2.33-2.347 5.499-3.667 8.802-3.667h81.928c7.421 0 13.437-6.059 13.437-13.533v-87.1407c0-7.47374-6.016-13.5333-13.437-13.5333h-86.517c-7.421 0-13.438 6.05956-13.438 13.5333zm26.256-75.2112h60.874c4.337 0 7.844 3.5393 7.844 7.9003v61.3071c0 4.3604-3.507 7.9003-7.844 7.9003h-60.874c-4.33 0-7.845-3.5399-7.845-7.9003v-61.3071c0-4.361 3.515-7.9003 7.845-7.9003z" fill="#33c482" fill-rule="evenodd"/><path d="m207.878 129.57h-64.324c-7.798 0-14.12 6.367-14.12 14.221v63.993c0 7.854 6.322 14.221 14.12 14.221h64.324c7.799 0 14.121-6.367 14.121-14.221v-63.993c0-7.854-6.322-14.221-14.121-14.221z" fill="#33c482"/><path d="m207.878 129.266h-64.324c-7.798 0-14.12 6.366-14.12 14.221v63.992c0 7.854 6.322 14.22 14.12 14.22h64.324c7.799 0 14.121-6.366 14.121-14.22v-63.992c0-7.855-6.322-14.221-14.121-14.221z" fill="url(#a)" fill-opacity=".2"/></g></svg>

Before

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 30 KiB

After

Width:  |  Height:  |  Size: 55 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 27 KiB

After

Width:  |  Height:  |  Size: 51 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 19 KiB

After

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 22 KiB

After

Width:  |  Height:  |  Size: 43 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 94 KiB

After

Width:  |  Height:  |  Size: 209 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 32 KiB

After

Width:  |  Height:  |  Size: 59 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

After

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 86 KiB

After

Width:  |  Height:  |  Size: 192 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 31 KiB

After

Width:  |  Height:  |  Size: 58 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 66 KiB

After

Width:  |  Height:  |  Size: 172 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 68 KiB

After

Width:  |  Height:  |  Size: 176 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 76 KiB

After

Width:  |  Height:  |  Size: 185 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 77 KiB

After

Width:  |  Height:  |  Size: 185 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 80 KiB

After

Width:  |  Height:  |  Size: 206 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 132 KiB

After

Width:  |  Height:  |  Size: 302 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 72 KiB

After

Width:  |  Height:  |  Size: 166 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 20 KiB

After

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 63 KiB

After

Width:  |  Height:  |  Size: 149 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 60 KiB

After

Width:  |  Height:  |  Size: 139 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 27 KiB

After

Width:  |  Height:  |  Size: 50 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.2 KiB

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.3 KiB

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 28 KiB

After

Width:  |  Height:  |  Size: 56 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 19 KiB

After

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 55 KiB

After

Width:  |  Height:  |  Size: 107 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 27 KiB

After

Width:  |  Height:  |  Size: 55 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.3 KiB

After

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 103 KiB

After

Width:  |  Height:  |  Size: 236 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 22 KiB

After

Width:  |  Height:  |  Size: 47 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 44 KiB

After

Width:  |  Height:  |  Size: 96 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 40 KiB

After

Width:  |  Height:  |  Size: 84 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 53 KiB

After

Width:  |  Height:  |  Size: 108 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 32 KiB

After

Width:  |  Height:  |  Size: 83 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 33 KiB

After

Width:  |  Height:  |  Size: 84 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

After

Width:  |  Height:  |  Size: 48 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.8 KiB

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 32 KiB

After

Width:  |  Height:  |  Size: 72 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 105 KiB

After

Width:  |  Height:  |  Size: 218 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 114 KiB

After

Width:  |  Height:  |  Size: 229 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 105 KiB

After

Width:  |  Height:  |  Size: 217 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 72 KiB

After

Width:  |  Height:  |  Size: 156 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 98 KiB

After

Width:  |  Height:  |  Size: 210 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 74 KiB

After

Width:  |  Height:  |  Size: 159 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

After

Width:  |  Height:  |  Size: 71 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 91 KiB

After

Width:  |  Height:  |  Size: 182 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 53 KiB

After

Width:  |  Height:  |  Size: 104 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 67 KiB

After

Width:  |  Height:  |  Size: 144 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 70 KiB

After

Width:  |  Height:  |  Size: 158 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 72 KiB

After

Width:  |  Height:  |  Size: 155 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 17 KiB

After

Width:  |  Height:  |  Size: 43 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 120 KiB

After

Width:  |  Height:  |  Size: 248 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 20 KiB

After

Width:  |  Height:  |  Size: 80 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 97 KiB

After

Width:  |  Height:  |  Size: 269 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 249 KiB

After

Width:  |  Height:  |  Size: 610 KiB

Some files were not shown because too many files have changed in this diff Show More