Compare commits

...

36 Commits

Author SHA1 Message Date
Waleed
0ce0f98aa5 v0.5.65: gemini updates, textract integration, ui updates (#2909)
* fix(google): wrap primitive tool responses for Gemini API compatibility (#2900)

* fix(canonical): copilot path + update parent (#2901)

* fix(rss): add top-level title, link, pubDate fields to RSS trigger output (#2902)

* fix(rss): add top-level title, link, pubDate fields to RSS trigger output

* fix(imap): add top-level fields to IMAP trigger output

* improvement(browseruse): add profile id param (#2903)

* improvement(browseruse): add profile id param

* make request a stub since we have directExec

* improvement(executor): upgraded abort controller to handle aborts for loops and parallels (#2880)

* improvement(executor): upgraded abort controller to handle aborts for loops and parallels

* comments

* improvement(files): update execution for passing base64 strings (#2906)

* progress

* improvement(execution): update execution for passing base64 strings

* fix types

* cleanup comments

* path security vuln

* reject promise correctly

* fix redirect case

* remove proxy routes

* fix tests

* use ipaddr

* feat(tools): added textract, added v2 for mistral, updated tag dropdown (#2904)

* feat(tools): added textract

* cleanup

* ack pr comments

* reorder

* removed upload for textract async version

* fix additional fields dropdown in editor, update parser to leave validation to be done on the server

* added mistral v2, files v2, and finalized textract

* updated the rest of the old file patterns, updated mistral outputs for v2

* updated tag dropdown to parse non-operation fields as well

* updated extension finder

* cleanup

* added description for inputs to workflow

* use helper for internal route check

* fix tag dropdown merge conflict change

* remove duplicate code

---------

Co-authored-by: Vikhyath Mondreti <vikhyath@simstudio.ai>

* fix(ui): change add inputs button to match output selector (#2907)

* fix(canvas): removed invite to workspace from canvas popover (#2908)

* fix(canvas): removed invite to workspace

* removed unused props

* fix(copilot): legacy tool display names (#2911)

* fix(a2a): canonical merge  (#2912)

* fix canonical merge

* fix empty array case

* fix(change-detection): copilot diffs have extra field (#2913)

* improvement(logs): improved logs ui bugs, added subflow disable UI (#2910)

* improvement(logs): improved logs ui bugs, added subflow disable UI

* added duplicate to action bar for subflows

* feat(broadcast): email v0.5 (#2905)

---------

Co-authored-by: Vikhyath Mondreti <vikhyathvikku@gmail.com>
Co-authored-by: Vikhyath Mondreti <vikhyath@simstudio.ai>
Co-authored-by: Emir Karabeg <78010029+emir-karabeg@users.noreply.github.com>
2026-01-20 23:54:55 -08:00
Emir Karabeg
294b168ed9 feat(broadcast): email v0.5 (#2905) 2026-01-20 23:42:48 -08:00
Waleed
0dc2c1fe0d improvement(logs): improved logs ui bugs, added subflow disable UI (#2910)
* improvement(logs): improved logs ui bugs, added subflow disable UI

* added duplicate to action bar for subflows
2026-01-20 23:13:05 -08:00
Vikhyath Mondreti
fb90c4e9b1 fix(change-detection): copilot diffs have extra field (#2913) 2026-01-20 22:04:08 -08:00
Vikhyath Mondreti
0af96d06c6 fix(a2a): canonical merge (#2912)
* fix canonical merge

* fix empty array case
2026-01-20 21:58:13 -08:00
Waleed
dff1c9d083 v0.5.64: unsubscribe, search improvements, metrics, additional SSO configuration 2026-01-20 00:34:11 -08:00
Vikhyath Mondreti
b09f683072 v0.5.63: ui and performance improvements, more google tools 2026-01-18 15:22:42 -08:00
Vikhyath Mondreti
a8bb0db660 v0.5.62: webhook bug fixes, seeding default subblock values, block selection fixes 2026-01-16 20:27:06 -08:00
Waleed
af82820a28 v0.5.61: webhook improvements, workflow controls, react query for deployment status, chat fixes, reducto and pulse OCR, linear fixes 2026-01-16 18:06:23 -08:00
Waleed
4372841797 v0.5.60: invitation flow improvements, chat fixes, a2a improvements, additional copilot actions 2026-01-15 00:02:18 -08:00
Waleed
5e8c843241 v0.5.59: a2a support, documentation 2026-01-13 13:21:21 -08:00
Waleed
7bf3d73ee6 v0.5.58: export folders, new tools, permissions groups enhancements 2026-01-13 00:56:59 -08:00
Vikhyath Mondreti
7ffc11a738 v0.5.57: subagents, context menu improvements, bug fixes 2026-01-11 11:38:40 -08:00
Waleed
be578e2ed7 v0.5.56: batch operations, access control and permission groups, billing fixes 2026-01-10 00:31:34 -08:00
Waleed
f415e5edc4 v0.5.55: polling groups, bedrock provider, devcontainer fixes, workflow preview enhancements 2026-01-08 23:36:56 -08:00
Waleed
13a6e6c3fa v0.5.54: seo, model blacklist, helm chart updates, fireflies integration, autoconnect improvements, billing fixes 2026-01-07 16:09:45 -08:00
Waleed
f5ab7f21ae v0.5.53: hotkey improvements, added redis fallback, fixes for workflow tool 2026-01-06 23:34:52 -08:00
Waleed
bfb6fffe38 v0.5.52: new port-based router block, combobox expression and variable support 2026-01-06 16:14:10 -08:00
Waleed
4fbec0a43f v0.5.51: triggers, kb, condition block improvements, supabase and grain integration updates 2026-01-06 14:26:46 -08:00
Waleed
585f5e365b v0.5.50: import improvements, ui upgrades, kb styling and performance improvements 2026-01-05 00:35:55 -08:00
Waleed
3792bdd252 v0.5.49: hitl improvements, new email styles, imap trigger, logs context menu (#2672)
* feat(logs-context-menu): consolidated logs utils and types, added logs record context menu (#2659)

* feat(email): welcome email; improvement(emails): ui/ux (#2658)

* feat(email): welcome email; improvement(emails): ui/ux

* improvement(emails): links, accounts, preview

* refactor(emails): file structure and wrapper components

* added envvar for personal emails sent, added isHosted gate

* fixed failing tests, added env mock

* fix: removed comment

---------

Co-authored-by: waleed <walif6@gmail.com>

* fix(logging): hitl + trigger dev crash protection (#2664)

* hitl gaps

* deal with trigger worker crashes

* cleanup import strcuture

* feat(imap): added support for imap trigger (#2663)

* feat(tools): added support for imap trigger

* feat(imap): added parity, tested

* ack PR comments

* final cleanup

* feat(i18n): update translations (#2665)

Co-authored-by: waleedlatif1 <waleedlatif1@users.noreply.github.com>

* fix(grain): updated grain trigger to auto-establish trigger (#2666)

Co-authored-by: aadamgough <adam@sim.ai>

* feat(admin): routes to manage deployments (#2667)

* feat(admin): routes to manage deployments

* fix naming fo deployed by

* feat(time-picker): added timepicker emcn component, added to playground, added searchable prop for dropdown, added more timezones for schedule, updated license and notice date (#2668)

* feat(time-picker): added timepicker emcn component, added to playground, added searchable prop for dropdown, added more timezones for schedule, updated license and notice date

* removed unused params, cleaned up redundant utils

* improvement(invite): aligned styling (#2669)

* improvement(invite): aligned with rest of app

* fix(invite): error handling

* fix: addressed comments

---------

Co-authored-by: Emir Karabeg <78010029+emir-karabeg@users.noreply.github.com>
Co-authored-by: Vikhyath Mondreti <vikhyathvikku@gmail.com>
Co-authored-by: waleedlatif1 <waleedlatif1@users.noreply.github.com>
Co-authored-by: Adam Gough <77861281+aadamgough@users.noreply.github.com>
Co-authored-by: aadamgough <adam@sim.ai>
2026-01-03 13:19:18 -08:00
Waleed
eb5d1f3e5b v0.5.48: copy-paste workflow blocks, docs updates, mcp tool fixes 2025-12-31 18:00:04 -08:00
Waleed
54ab82c8dd v0.5.47: deploy workflow as mcp, kb chunks tokenizer, UI improvements, jira service management tools 2025-12-30 23:18:58 -08:00
Waleed
f895bf469b v0.5.46: build improvements, greptile, light mode improvements 2025-12-29 02:17:52 -08:00
Waleed
dd3209af06 v0.5.45: light mode fixes, realtime usage indicator, docker build improvements 2025-12-27 19:57:42 -08:00
Waleed
b6ba3b50a7 v0.5.44: keyboard shortcuts, autolayout, light mode, byok, testing improvements 2025-12-26 21:25:19 -08:00
Waleed
b304233062 v0.5.43: export logs, circleback, grain, vertex, code hygiene, schedule improvements 2025-12-23 19:19:18 -08:00
Vikhyath Mondreti
57e4b49bd6 v0.5.42: fix memory migration 2025-12-23 01:24:54 -08:00
Vikhyath Mondreti
e12dd204ed v0.5.41: memory fixes, copilot improvements, knowledgebase improvements, LLM providers standardization 2025-12-23 00:15:18 -08:00
Vikhyath Mondreti
3d9d9cbc54 v0.5.40: supabase ops to allow non-public schemas, jira uuid 2025-12-21 22:28:05 -08:00
Waleed
0f4ec962ad v0.5.39: notion, workflow variables fixes 2025-12-20 20:44:00 -08:00
Waleed
4827866f9a v0.5.38: snap to grid, copilot ux improvements, billing line items 2025-12-20 17:24:38 -08:00
Waleed
3e697d9ed9 v0.5.37: redaction utils consolidation, logs updates, autoconnect improvements, additional kb tag types 2025-12-19 22:31:55 -08:00
Martin Yankov
4431a1a484 fix(helm): add custom egress rules to realtime network policy (#2481)
The realtime service network policy was missing the custom egress rules section
that allows configuration of additional egress rules via values.yaml. This caused
the realtime pods to be unable to connect to external databases (e.g., PostgreSQL
on port 5432) when using external database configurations.

The app network policy already had this section, but the realtime network policy
was missing it, creating an inconsistency and preventing the realtime service
from accessing external databases configured via networkPolicy.egress values.

This fix adds the same custom egress rules template section to the realtime
network policy, matching the app network policy behavior and allowing users to
configure database connectivity via values.yaml.
2025-12-19 18:59:08 -08:00
Waleed
4d1a9a3f22 v0.5.36: hitl improvements, opengraph, slack fixes, one-click unsubscribe, auth checks, new db indexes 2025-12-19 01:27:49 -08:00
Vikhyath Mondreti
eb07a080fb v0.5.35: helm updates, copilot improvements, 404 for docs, salesforce fixes, subflow resize clamping 2025-12-18 16:23:19 -08:00
20 changed files with 402 additions and 45 deletions

View File

@@ -234,7 +234,7 @@ function ProgressBar({
{segments.map((segment, index) => (
<div
key={index}
className='absolute h-full'
className='absolute h-full opacity-70'
style={{
left: `${segment.startPercent}%`,
width: `${segment.widthPercent}%`,

View File

@@ -257,7 +257,7 @@ export const LogDetails = memo(function LogDetails({
Version
</span>
<div className='flex w-0 flex-1 justify-end'>
<span className='max-w-full truncate rounded-[6px] bg-[#14291B] px-[9px] py-[2px] font-medium text-[#86EFAC] text-[12px]'>
<span className='max-w-full truncate rounded-[6px] bg-[#bbf7d0] px-[9px] py-[2px] font-medium text-[#15803d] text-[12px] dark:bg-[#14291B] dark:text-[#86EFAC]'>
{log.deploymentVersionName || `v${log.deploymentVersion}`}
</span>
</div>

View File

@@ -19,6 +19,7 @@ import { DatePicker } from '@/components/emcn/components/date-picker/date-picker
import { cn } from '@/lib/core/utils/cn'
import { hasActiveFilters } from '@/lib/logs/filters'
import { getTriggerOptions } from '@/lib/logs/get-trigger-options'
import { type LogStatus, STATUS_CONFIG } from '@/app/workspace/[workspaceId]/logs/utils'
import { getBlock } from '@/blocks/registry'
import { useFolderStore } from '@/stores/folders/store'
import { useFilterStore } from '@/stores/logs/filters/store'
@@ -211,12 +212,12 @@ export function LogsToolbar({
}, [level])
const statusOptions: ComboboxOption[] = useMemo(
() => [
{ value: 'error', label: 'Error', icon: getColorIcon('var(--text-error)') },
{ value: 'info', label: 'Info', icon: getColorIcon('var(--terminal-status-info-color)') },
{ value: 'running', label: 'Running', icon: getColorIcon('#22c55e') },
{ value: 'pending', label: 'Pending', icon: getColorIcon('#f59e0b') },
],
() =>
(Object.keys(STATUS_CONFIG) as LogStatus[]).map((status) => ({
value: status,
label: STATUS_CONFIG[status].label,
icon: getColorIcon(STATUS_CONFIG[status].color),
})),
[]
)
@@ -242,12 +243,8 @@ export function LogsToolbar({
const selectedStatusColor = useMemo(() => {
if (selectedStatuses.length !== 1) return null
const status = selectedStatuses[0]
if (status === 'error') return 'var(--text-error)'
if (status === 'info') return 'var(--terminal-status-info-color)'
if (status === 'running') return '#22c55e'
if (status === 'pending') return '#f59e0b'
return null
const status = selectedStatuses[0] as LogStatus
return STATUS_CONFIG[status]?.color ?? null
}, [selectedStatuses])
const workflowOptions: ComboboxOption[] = useMemo(

View File

@@ -5,7 +5,6 @@ import { getIntegrationMetadata } from '@/lib/logs/get-trigger-options'
import { getBlock } from '@/blocks/registry'
import { CORE_TRIGGER_TYPES } from '@/stores/logs/filters/types'
/** Column configuration for logs table - shared between header and rows */
export const LOG_COLUMNS = {
date: { width: 'w-[8%]', minWidth: 'min-w-[70px]', label: 'Date' },
time: { width: 'w-[12%]', minWidth: 'min-w-[90px]', label: 'Time' },
@@ -16,10 +15,8 @@ export const LOG_COLUMNS = {
duration: { width: 'w-[20%]', minWidth: 'min-w-[100px]', label: 'Duration' },
} as const
/** Type-safe column key derived from LOG_COLUMNS */
export type LogColumnKey = keyof typeof LOG_COLUMNS
/** Ordered list of column keys for rendering table headers */
export const LOG_COLUMN_ORDER: readonly LogColumnKey[] = [
'date',
'time',
@@ -30,7 +27,6 @@ export const LOG_COLUMN_ORDER: readonly LogColumnKey[] = [
'duration',
] as const
/** Possible execution status values for workflow logs */
export type LogStatus = 'error' | 'pending' | 'running' | 'info' | 'cancelled'
/**
@@ -53,30 +49,28 @@ export function getDisplayStatus(status: string | null | undefined): LogStatus {
}
}
/** Configuration mapping log status to Badge variant and display label */
const STATUS_VARIANT_MAP: Record<
export const STATUS_CONFIG: Record<
LogStatus,
{ variant: React.ComponentProps<typeof Badge>['variant']; label: string }
{ variant: React.ComponentProps<typeof Badge>['variant']; label: string; color: string }
> = {
error: { variant: 'red', label: 'Error' },
pending: { variant: 'amber', label: 'Pending' },
running: { variant: 'green', label: 'Running' },
cancelled: { variant: 'gray', label: 'Cancelled' },
info: { variant: 'gray', label: 'Info' },
error: { variant: 'red', label: 'Error', color: 'var(--text-error)' },
pending: { variant: 'amber', label: 'Pending', color: '#f59e0b' },
running: { variant: 'green', label: 'Running', color: '#22c55e' },
cancelled: { variant: 'orange', label: 'Cancelled', color: '#f97316' },
info: { variant: 'gray', label: 'Info', color: 'var(--terminal-status-info-color)' },
}
/** Configuration mapping core trigger types to Badge color variants */
const TRIGGER_VARIANT_MAP: Record<string, React.ComponentProps<typeof Badge>['variant']> = {
manual: 'gray-secondary',
api: 'blue',
schedule: 'green',
chat: 'purple',
webhook: 'orange',
mcp: 'cyan',
a2a: 'teal',
}
interface StatusBadgeProps {
/** The execution status to display */
status: LogStatus
}
@@ -86,14 +80,13 @@ interface StatusBadgeProps {
* @returns A Badge with dot indicator and status label
*/
export const StatusBadge = React.memo(({ status }: StatusBadgeProps) => {
const config = STATUS_VARIANT_MAP[status]
const config = STATUS_CONFIG[status]
return React.createElement(Badge, { variant: config.variant, dot: true }, config.label)
})
StatusBadge.displayName = 'StatusBadge'
interface TriggerBadgeProps {
/** The trigger type identifier (e.g., 'manual', 'api', or integration block type) */
trigger: string
}

View File

@@ -142,7 +142,7 @@ export const ActionBar = memo(
</Tooltip.Root>
)}
{!isStartBlock && !isResponseBlock && !isSubflowBlock && (
{!isStartBlock && !isResponseBlock && (
<Tooltip.Root>
<Tooltip.Trigger asChild>
<Button
@@ -213,6 +213,29 @@ export const ActionBar = memo(
</Tooltip.Root>
)}
{isSubflowBlock && (
<Tooltip.Root>
<Tooltip.Trigger asChild>
<Button
variant='ghost'
onClick={(e) => {
e.stopPropagation()
if (!disabled) {
collaborativeBatchToggleBlockEnabled([blockId])
}
}}
className={ACTION_BUTTON_STYLES}
disabled={disabled}
>
{isEnabled ? <Circle className={ICON_SIZE} /> : <CircleOff className={ICON_SIZE} />}
</Button>
</Tooltip.Trigger>
<Tooltip.Content side='top'>
{getTooltipMessage(isEnabled ? 'Disable Block' : 'Enable Block')}
</Tooltip.Content>
</Tooltip.Root>
)}
<Tooltip.Root>
<Tooltip.Trigger asChild>
<Button

View File

@@ -1,6 +1,7 @@
import { memo, useMemo, useRef } from 'react'
import { RepeatIcon, SplitIcon } from 'lucide-react'
import { Handle, type NodeProps, Position, useReactFlow } from 'reactflow'
import { Badge } from '@/components/emcn'
import { cn } from '@/lib/core/utils/cn'
import { HANDLE_POSITIONS } from '@/lib/workflows/blocks/block-dimensions'
import { type DiffStatus, hasDiffStatus } from '@/lib/workflows/diff/types'
@@ -78,6 +79,7 @@ export const SubflowNodeComponent = memo(({ data, id, selected }: NodeProps<Subf
? currentBlock.is_diff
: undefined
const isEnabled = currentBlock?.enabled ?? true
const isPreview = data?.isPreview || false
// Focus state
@@ -184,14 +186,21 @@ export const SubflowNodeComponent = memo(({ data, id, selected }: NodeProps<Subf
<div className='flex min-w-0 flex-1 items-center gap-[10px]'>
<div
className='flex h-[24px] w-[24px] flex-shrink-0 items-center justify-center rounded-[6px]'
style={{ backgroundColor: blockIconBg }}
style={{ backgroundColor: isEnabled ? blockIconBg : 'gray' }}
>
<BlockIcon className='h-[16px] w-[16px] text-white' />
</div>
<span className='font-medium text-[16px]' title={blockName}>
<span
className={cn(
'truncate font-medium text-[16px]',
!isEnabled && 'text-[var(--text-muted)]'
)}
title={blockName}
>
{blockName}
</span>
</div>
{!isEnabled && <Badge variant='gray-secondary'>disabled</Badge>}
</div>
{!isPreview && (

View File

@@ -214,6 +214,15 @@ export const A2ABlock: BlockConfig<A2AResponse> = {
],
config: {
tool: (params) => params.operation as string,
params: (params) => {
const { fileUpload, fileReference, ...rest } = params
const hasFileUpload = Array.isArray(fileUpload) ? fileUpload.length > 0 : !!fileUpload
const files = hasFileUpload ? fileUpload : fileReference
return {
...rest,
...(files ? { files } : {}),
}
},
},
},
inputs: {

View File

@@ -25,7 +25,7 @@ const badgeVariants = cva(
orange: `${STATUS_BASE} bg-[#fed7aa] text-[#c2410c] dark:bg-[rgba(249,115,22,0.2)] dark:text-[#fdba74]`,
amber: `${STATUS_BASE} bg-[#fde68a] text-[#a16207] dark:bg-[rgba(245,158,11,0.2)] dark:text-[#fcd34d]`,
teal: `${STATUS_BASE} bg-[#99f6e4] text-[#0f766e] dark:bg-[rgba(20,184,166,0.2)] dark:text-[#5eead4]`,
cyan: `${STATUS_BASE} bg-[#a5f3fc] text-[#0e7490] dark:bg-[rgba(14,165,233,0.2)] dark:text-[#7dd3fc]`,
cyan: `${STATUS_BASE} bg-[var(--surface-4)] text-[#0891b2] dark:bg-[rgba(14,165,233,0.2)] dark:text-[#7dd3fc]`,
'gray-secondary': `${STATUS_BASE} bg-[var(--surface-4)] text-[var(--text-secondary)]`,
},
size: {

View File

@@ -0,0 +1,287 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>What's New at Sim</title>
</head>
<body style="margin:0;padding:0;background-color:#ffffff;">
<table width="100%" cellspacing="0" cellpadding="0" border="0" role="presentation" style="background-color:#ffffff;">
<tr>
<td align="center" style="padding:0 16px;">
<table width="600" cellspacing="0" cellpadding="0" border="0" role="presentation" style="max-width:600px;width:100%;">
<!-- Logo -->
<tr>
<td align="center" style="padding-top:32px;padding-bottom:16px;">
<a href="https://sim.ai" style="color:#000;text-decoration:none;" target="_blank">
<img src="https://sim.ai/email/broadcast/v0.5/logo.png" width="79" alt="Sim Logo" style="display:block;width:79px;" border="0">
</a>
</td>
</tr>
<!-- Intro Paragraph -->
<tr>
<td align="left" style="color:#404040;font-family:-apple-system,'SF Pro Display','SF Pro Text','Helvetica',sans-serif;font-size:16px;line-height:24px;word-break:break-word;padding-bottom:20px;padding-top:8px;text-align:left;">
<p style="margin:0;">We're excited to introduce <strong>Sim v0.5</strong>, the next evolution of our agent workflow platform—built for teams who need <strong>context-aware AI assistance</strong>, <strong>seamless tool deployment</strong>, and <strong>full execution observability</strong> in production.</p>
</td>
</tr>
<!-- CTA Button -->
<tr>
<td align="center" style="padding-bottom:25px;padding-top:5px;">
<table cellspacing="0" cellpadding="0" border="0" role="presentation">
<tr>
<td align="center" style="background-color:#32bd7e;border-radius:5px;">
<a href="https://sim.ai" style="display:inline-block;font-weight:500;font-size:14px;padding:7px 16px;text-decoration:none;color:#ffffff;font-family:-apple-system,'SF Pro Display','SF Pro Text','Helvetica',sans-serif;" target="_blank">Try Sim</a>
</td>
</tr>
</table>
</td>
</tr>
<!-- Header Text -->
<tr>
<td align="left" valign="top" style="color:#2d2d2d;font-family:-apple-system,'SF Pro Display','SF Pro Text','Helvetica',sans-serif;word-break:break-word;padding-top:10px;padding-bottom:8px;text-align:left;">
<h2 style="margin:0;color:#2d2d2d;font-family:-apple-system,'SF Pro Display','SF Pro Text','Helvetica',sans-serif;font-size:28px;font-weight:600;word-break:break-word;">Get things done <em>faster</em></h2>
</td>
</tr>
<tr>
<td align="left" style="color:#404040;font-family:-apple-system,'SF Pro Display','SF Pro Text','Helvetica',sans-serif;font-size:16px;line-height:24px;word-break:break-word;padding-bottom:30px;text-align:left;">
<p style="margin:0;">You're focused on the most critical tasks, let agents handle the rest.</p>
</td>
</tr>
<!-- FEATURE 1: Copilot -->
<tr>
<td align="left" style="color:#2d2d2d;font-family:-apple-system,'SF Pro Display','SF Pro Text','Helvetica',sans-serif;font-size:18px;word-break:break-word;padding-top:10px;padding-bottom:12px;text-align:left;">
<strong>Copilot</strong>
</td>
</tr>
<tr>
<td align="center" style="border-radius:8px;font-size:0;line-height:0;">
<a href="https://sim.ai" style="color:#000;text-decoration:none;" target="_blank">
<img src="https://sim.ai/email/broadcast/v0.5/copilot.jpg" width="570" alt="Sim Copilot" style="display:block;width:100%;border-radius:8px;" border="0">
</a>
</td>
</tr>
<tr>
<td align="left" style="color:#404040;font-family:-apple-system,'SF Pro Display','SF Pro Text','Helvetica',sans-serif;font-size:16px;line-height:24px;word-break:break-word;padding-bottom:25px;padding-top:12px;text-align:left;">
<p style="margin:0;">Copilot is a context-aware assistant embedded directly into the Sim editor. It has first-class access to your workflows, blocks, execution logs, and documentation—helping you build, debug, and optimize without leaving the canvas. Ask it to explain a workflow, propose changes, or execute actions. All writes are gated behind explicit approval, so you stay in control.</p>
</td>
</tr>
<!-- FEATURE 2: MCP Deployment -->
<tr>
<td align="left" style="color:#2d2d2d;font-family:-apple-system,'SF Pro Display','SF Pro Text','Helvetica',sans-serif;font-size:18px;word-break:break-word;padding-top:20px;padding-bottom:12px;text-align:left;">
<strong>MCP Deployment</strong>
</td>
</tr>
<tr>
<td align="center">
<a href="https://sim.ai" style="text-decoration:none;display:block;" target="_blank">
<table cellspacing="0" cellpadding="0" border="0" role="presentation" width="100%" style="background-color:#181C1E;border-radius:8px;">
<tr>
<td align="center" style="padding:40px 30px;">
<table cellspacing="0" cellpadding="0" border="0" role="presentation">
<tr>
<td align="center" style="padding-bottom:16px;">
<img src="https://sim.ai/email/broadcast/v0.5/mcp.png" width="48" height="48" alt="MCP" style="display:block;" border="0">
</td>
</tr>
<tr>
<td align="center">
<p style="margin:0;color:#ffffff;font-family:-apple-system,'SF Pro Display','SF Pro Text','Helvetica',sans-serif;font-size:20px;font-weight:500;">Expose workflows as tools for any agent</p>
</td>
</tr>
</table>
</td>
</tr>
</table>
</a>
</td>
</tr>
<tr>
<td align="left" style="color:#404040;font-family:-apple-system,'SF Pro Display','SF Pro Text','Helvetica',sans-serif;font-size:16px;line-height:24px;word-break:break-word;padding-bottom:25px;padding-top:12px;text-align:left;">
<p style="margin:0;">Deploy any workflow as an MCP tool and expose it to any MCP-compatible agent—Claude Desktop, Cursor, or your own applications. Define custom tool names, descriptions, and parameter schemas. Your workflows become reusable building blocks that other agents can invoke, turning Sim into the backend for your agentic systems.</p>
</td>
</tr>
<!-- FEATURE 3: Logs & Dashboard -->
<tr>
<td align="left" style="color:#2d2d2d;font-family:-apple-system,'SF Pro Display','SF Pro Text','Helvetica',sans-serif;font-size:18px;word-break:break-word;padding-top:20px;padding-bottom:12px;text-align:left;">
<strong>Logs & Dashboard</strong>
</td>
</tr>
<tr>
<td align="center" style="border-radius:8px;font-size:0;line-height:0;">
<a href="https://sim.ai" style="color:#000;text-decoration:none;" target="_blank">
<img src="https://sim.ai/email/broadcast/v0.5/dashboard.jpg" width="570" alt="Logs & Dashboard" style="display:block;width:100%;border-radius:8px;" border="0">
</a>
</td>
</tr>
<tr>
<td align="left" style="color:#404040;font-family:-apple-system,'SF Pro Display','SF Pro Text','Helvetica',sans-serif;font-size:16px;line-height:24px;word-break:break-word;padding-bottom:25px;padding-top:12px;text-align:left;">
<p style="margin:0;">Full observability for every execution. Trace spans show you exactly what happened at each step—durations, token usage, cost breakdowns by model, and error details when things go wrong. Filter by time range, trigger type, or workflow. Live mode auto-refreshes every 5 seconds. Restore any previous workflow state with execution snapshots.</p>
</td>
</tr>
<!-- FEATURE 4: Collaboration -->
<tr>
<td align="left" style="color:#2d2d2d;font-family:-apple-system,'SF Pro Display','SF Pro Text','Helvetica',sans-serif;font-size:18px;word-break:break-word;padding-top:20px;padding-bottom:12px;text-align:left;">
<strong>Realtime Collaboration</strong>
</td>
</tr>
<tr>
<td align="center" style="border-radius:8px;font-size:0;line-height:0;">
<a href="https://sim.ai" style="color:#000;text-decoration:none;" target="_blank">
<img src="https://sim.ai/email/broadcast/v0.5/collaboration.jpg" width="570" alt="Realtime Collaboration" style="display:block;width:100%;border-radius:8px;" border="0">
</a>
</td>
</tr>
<tr>
<td align="left" style="color:#404040;font-family:-apple-system,'SF Pro Display','SF Pro Text','Helvetica',sans-serif;font-size:16px;line-height:24px;word-break:break-word;padding-bottom:25px;padding-top:12px;text-align:left;">
<p style="margin:0;">Invite teammates to your workspace and build workflows together in realtime—like Figma for AI agents. See cursors move, blocks added, and configurations updated as they happen. The operation queue ensures reliability even under poor network conditions. Undo/redo works per-user, so your changes stay separate from your collaborators'.</p>
</td>
</tr>
<!-- Divider -->
<tr>
<td align="center" style="padding-bottom:10px;padding-top:10px;">
<table width="100%" cellspacing="0" cellpadding="0" border="0" role="presentation" height="1" style="border-top:1px solid #ededed;">
<tr>
<td height="0" style="font-size:0;line-height:0;">&#173;</td>
</tr>
</table>
</td>
</tr>
<!-- Final CTA -->
<tr>
<td align="left" style="color:#404040;font-family:-apple-system,'SF Pro Display','SF Pro Text','Helvetica',sans-serif;font-size:16px;line-height:24px;word-break:break-word;padding-bottom:15px;padding-top:15px;text-align:left;">
<p style="margin:0;">Ready to build? These features are available now in Sim.</p>
</td>
</tr>
<tr>
<td align="center" style="padding-bottom:30px;padding-top:15px;">
<table cellspacing="0" cellpadding="0" border="0" role="presentation">
<tr>
<td align="center" style="background-color:#32bd7e;border-radius:5px;">
<a href="https://sim.ai" style="display:inline-block;font-weight:500;font-size:14px;padding:7px 16px;text-decoration:none;color:#ffffff;font-family:-apple-system,'SF Pro Display','SF Pro Text','Helvetica',sans-serif;" target="_blank">Get Started</a>
</td>
</tr>
</table>
</td>
</tr>
<!-- Footer Divider -->
<tr>
<td align="center" style="padding-top:20px;padding-bottom:20px;">
<table width="100%" cellspacing="0" cellpadding="0" border="0" role="presentation" height="1" style="border-top:1px solid #ededed;">
<tr>
<td height="0" style="font-size:0;line-height:0;">&#173;</td>
</tr>
</table>
</td>
</tr>
<!-- Social links row -->
<tr>
<td align="center">
<table cellspacing="0" cellpadding="0" border="0" role="presentation">
<tbody>
<tr>
<td align="center" style="padding:0 8px 0 0;">
<a href="https://sim.ai/x" rel="noopener noreferrer" target="_blank">
<img src="https://sim.ai/static/x-icon.png" width="20" height="20" alt="X" style="display:block;" border="0">
</a>
</td>
<td align="center" style="padding:0 8px;">
<a href="https://sim.ai/discord" rel="noopener noreferrer" target="_blank">
<img src="https://sim.ai/static/discord-icon.png" width="20" height="20" alt="Discord" style="display:block;" border="0">
</a>
</td>
<td align="center" style="padding:0 8px;">
<a href="https://sim.ai/github" rel="noopener noreferrer" target="_blank">
<img src="https://sim.ai/static/github-icon.png" width="20" height="20" alt="GitHub" style="display:block;" border="0">
</a>
</td>
</tr>
</tbody>
</table>
</td>
</tr>
<!-- Spacer -->
<tr>
<td height="16" style="font-size:1px;line-height:1px;">&nbsp;</td>
</tr>
<!-- Address row -->
<tr>
<td align="center" style="font-size:12px;line-height:20px;color:#737373;font-family:-apple-system,'SF Pro Display','SF Pro Text','Helvetica',sans-serif;margin:0;">
Sim, 80 Langton St, San Francisco, CA 94103, USA
</td>
</tr>
<!-- Spacer -->
<tr>
<td height="8" style="font-size:1px;line-height:1px;">&nbsp;</td>
</tr>
<!-- Contact row -->
<tr>
<td align="center" style="font-size:12px;line-height:20px;color:#737373;font-family:-apple-system,'SF Pro Display','SF Pro Text','Helvetica',sans-serif;margin:0;">
Questions? <a href="mailto:support@sim.ai" style="color:#737373;text-decoration:underline;font-weight:normal;">support@sim.ai</a>
</td>
</tr>
<!-- Spacer -->
<tr>
<td height="8" style="font-size:1px;line-height:1px;">&nbsp;</td>
</tr>
<!-- Links row -->
<tr>
<td align="center" style="font-size:12px;line-height:20px;color:#737373;font-family:-apple-system,'SF Pro Display','SF Pro Text','Helvetica',sans-serif;margin:0;">
<a href="https://sim.ai/privacy" style="color:#737373;text-decoration:underline;font-weight:normal;" rel="noopener noreferrer" target="_blank">Privacy Policy</a>
&nbsp;&nbsp;
<a href="https://sim.ai/terms" style="color:#737373;text-decoration:underline;font-weight:normal;" rel="noopener noreferrer" target="_blank">Terms of Service</a>
&nbsp;&nbsp;
<a href="{{{RESEND_UNSUBSCRIBE_URL}}}" style="color:#737373;text-decoration:underline;font-weight:normal;" rel="noopener noreferrer" target="_blank">Unsubscribe</a>
</td>
</tr>
<!-- Spacer -->
<tr>
<td height="16" style="font-size:1px;line-height:1px;">&nbsp;</td>
</tr>
<!-- Copyright row -->
<tr>
<td align="center" style="font-size:12px;line-height:20px;color:#737373;font-family:-apple-system,'SF Pro Display','SF Pro Text','Helvetica',sans-serif;margin:0;">
© 2026 Sim, All Rights Reserved
</td>
</tr>
<!-- Bottom spacer -->
<tr>
<td height="32" style="font-size:1px;line-height:1px;">&nbsp;</td>
</tr>
</table>
</td>
</tr>
</table>
</body>
</html>

View File

@@ -1,4 +1,4 @@
import type { WorkflowState } from '@/stores/workflows/workflow/types'
import type { BlockState, WorkflowState } from '@/stores/workflows/workflow/types'
import { SYSTEM_SUBBLOCK_IDS, TRIGGER_RUNTIME_SUBBLOCK_IDS } from '@/triggers/constants'
import {
normalizedStringify,
@@ -13,6 +13,20 @@ import {
sortEdges,
} from './normalize'
/** Block with optional diff markers added by copilot */
type BlockWithDiffMarkers = BlockState & {
is_diff?: string
field_diffs?: Record<string, unknown>
}
/** SubBlock with optional diff marker */
type SubBlockWithDiffMarker = {
id: string
type: string
value: unknown
is_diff?: string
}
/**
* Compare the current workflow state with the deployed state to detect meaningful changes
* @param currentState - The current workflow state
@@ -63,21 +77,32 @@ export function hasWorkflowChanged(
// - subBlocks: handled separately below
// - layout: contains measuredWidth/measuredHeight from autolayout
// - height: block height measurement from autolayout
// - outputs: derived from subBlocks (e.g., inputFormat), already compared via subBlocks
// - is_diff, field_diffs: diff markers from copilot edits
const currentBlockWithDiff = currentBlock as BlockWithDiffMarkers
const deployedBlockWithDiff = deployedBlock as BlockWithDiffMarkers
const {
position: _currentPos,
subBlocks: currentSubBlocks = {},
layout: _currentLayout,
height: _currentHeight,
outputs: _currentOutputs,
is_diff: _currentIsDiff,
field_diffs: _currentFieldDiffs,
...currentRest
} = currentBlock
} = currentBlockWithDiff
const {
position: _deployedPos,
subBlocks: deployedSubBlocks = {},
layout: _deployedLayout,
height: _deployedHeight,
outputs: _deployedOutputs,
is_diff: _deployedIsDiff,
field_diffs: _deployedFieldDiffs,
...deployedRest
} = deployedBlock
} = deployedBlockWithDiff
// Also exclude width/height from data object (container dimensions from autolayout)
const {
@@ -156,14 +181,13 @@ export function hasWorkflowChanged(
}
}
// Compare type and other properties
const currentSubBlockWithoutValue = { ...currentSubBlocks[subBlockId], value: undefined }
const deployedSubBlockWithoutValue = { ...deployedSubBlocks[subBlockId], value: undefined }
// Compare type and other properties (excluding diff markers and value)
const currentSubBlockWithDiff = currentSubBlocks[subBlockId] as SubBlockWithDiffMarker
const deployedSubBlockWithDiff = deployedSubBlocks[subBlockId] as SubBlockWithDiffMarker
const { value: _cv, is_diff: _cd, ...currentSubBlockRest } = currentSubBlockWithDiff
const { value: _dv, is_diff: _dd, ...deployedSubBlockRest } = deployedSubBlockWithDiff
if (
normalizedStringify(currentSubBlockWithoutValue) !==
normalizedStringify(deployedSubBlockWithoutValue)
) {
if (normalizedStringify(currentSubBlockRest) !== normalizedStringify(deployedSubBlockRest)) {
return true
}
}

View File

@@ -376,6 +376,7 @@ describe('Database Helpers', () => {
forEachItems: '',
doWhileCondition: '',
whileCondition: '',
enabled: true,
})
expect(result?.parallels['parallel-1']).toEqual({
@@ -384,6 +385,7 @@ describe('Database Helpers', () => {
count: 5,
distribution: ['item1', 'item2'],
parallelType: 'count',
enabled: true,
})
})

View File

@@ -273,6 +273,7 @@ export async function loadWorkflowFromNormalizedTables(
forEachItems: (config as Loop).forEachItems ?? '',
whileCondition: (config as Loop).whileCondition ?? '',
doWhileCondition: (config as Loop).doWhileCondition ?? '',
enabled: migratedBlocks[subflow.id]?.enabled ?? true,
}
loops[subflow.id] = loop
@@ -301,6 +302,7 @@ export async function loadWorkflowFromNormalizedTables(
(config as Parallel).parallelType === 'collection'
? (config as Parallel).parallelType
: 'count',
enabled: migratedBlocks[subflow.id]?.enabled ?? true,
}
parallels[subflow.id] = parallel
} else {

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 108 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

View File

@@ -172,7 +172,14 @@ export type TimeRange =
| 'All time'
| 'Custom range'
export type LogLevel = 'error' | 'info' | 'running' | 'pending' | 'all' | (string & {})
export type LogLevel =
| 'error'
| 'info'
| 'running'
| 'pending'
| 'cancelled'
| 'all'
| (string & {})
/** Core trigger types for workflow execution */
export const CORE_TRIGGER_TYPES = [
'manual',

View File

@@ -130,6 +130,7 @@ export interface Loop {
forEachItems?: any[] | Record<string, any> | string // Items or expression
whileCondition?: string // JS expression that evaluates to boolean (for while loops)
doWhileCondition?: string // JS expression that evaluates to boolean (for do-while loops)
enabled: boolean
}
export interface Parallel {
@@ -138,6 +139,7 @@ export interface Parallel {
distribution?: any[] | Record<string, any> | string // Items or expression
count?: number // Number of parallel executions for count-based parallel
parallelType?: 'count' | 'collection' // Explicit parallel type to avoid inference bugs
enabled: boolean
}
export interface Variable {

View File

@@ -72,6 +72,7 @@ export function convertLoopBlockToLoop(
nodes: findChildNodes(loopBlockId, blocks),
iterations: loopBlock.data?.count || DEFAULT_LOOP_ITERATIONS,
loopType,
enabled: loopBlock.enabled,
}
loop.forEachItems = loopBlock.data?.collection || ''
@@ -113,6 +114,7 @@ export function convertParallelBlockToParallel(
distribution,
count,
parallelType: validatedParallelType,
enabled: parallelBlock.enabled,
}
}