Compare commits

..

94 Commits

Author SHA1 Message Date
waleed
b03d1f5d58 styling 2026-01-21 20:14:30 -08:00
Vikhyath Mondreti
be757a4f1e adhere to size limits for tables 2026-01-21 17:20:33 -08:00
Vikhyath Mondreti
1938818027 address bugbot concerns 2026-01-21 17:13:58 -08:00
Vikhyath Mondreti
2818b745d1 migrate enrichment logic to general abstraction 2026-01-21 17:08:20 -08:00
Vikhyath Mondreti
2d49de76ea add back missed code 2026-01-21 16:37:28 -08:00
Vikhyath Mondreti
1f682eb343 readd migrations 2026-01-21 16:34:32 -08:00
Vikhyath Mondreti
8d43947eb5 Merge staging into lakees/db
- Resolve merge conflicts in input-format.tsx, workflow-block.tsx, providers/utils.ts
- Fix tests to use blockData/blockNameMapping for tag variable resolution
- Add getBlockOutputs mock to block.test.ts for schema validation tests
- Fix normalizeName import path in utils.test.ts
- Add sql.raw and sql.join to drizzle-orm mock for sql.test.ts
- Add new subBlock types (table-selector, filter-builder, sort-builder) to blocks.test.ts
2026-01-21 16:33:31 -08:00
Vikhyath Mondreti
107679bf41 prepare merge 2026-01-21 16:25:13 -08:00
Lakee Sivaraya
a8e413a999 fix 2026-01-17 13:04:07 -08:00
Lakee Sivaraya
f05f5bbc6d fix 2026-01-17 12:57:37 -08:00
Lakee Sivaraya
87f8fcdbf2 fix 2026-01-17 12:49:36 -08:00
Lakee Sivaraya
6e8dc771fe fix 2026-01-17 10:16:45 -08:00
Lakee Sivaraya
d0c3c6aec7 updates 2026-01-17 10:02:52 -08:00
Lakee Sivaraya
8574d66aac uncook 2026-01-17 09:58:48 -08:00
Lakee Sivaraya
e79e9e7367 Merge origin/main into lakees/db
Resolved conflicts:
- workflow-block.tsx: Kept both table types and schedule hooks
- types.ts: Kept both filter-builder/sort-builder and deprecated comment
- icons.tsx (both apps): Kept TableIcon and added ReductoIcon/PulseIcon
- Migration files: Accepted main branch versions
2026-01-17 09:11:51 -08:00
Lakee Sivaraya
4b6de03a62 revert 2026-01-16 18:40:03 -08:00
Lakee Sivaraya
37b50cbce6 dedupe 2026-01-16 18:40:03 -08:00
Lakee Sivaraya
7ca628db13 rename 2026-01-16 18:40:03 -08:00
Lakee Sivaraya
118e4f65f0 updates 2026-01-16 18:40:02 -08:00
Lakee Sivaraya
292cd39cfb docs 2026-01-16 18:40:02 -08:00
Lakee Sivaraya
ea77790484 docs 2026-01-16 18:40:02 -08:00
Lakee Sivaraya
895591514a updates 2026-01-16 18:40:02 -08:00
Lakee Sivaraya
0e1133fc42 fix error handling 2026-01-16 18:40:02 -08:00
Lakee Sivaraya
4357230a9d fix 2026-01-16 18:40:02 -08:00
Lakee Sivaraya
e7f45166af type fix 2026-01-16 18:40:02 -08:00
Lakee Sivaraya
c662a31ac8 db updates 2026-01-16 18:40:02 -08:00
Lakee Sivaraya
51d1b958e2 updates 2026-01-16 18:39:17 -08:00
Lakee Sivaraya
3d81c1cc14 revert 2026-01-16 18:38:51 -08:00
Lakee Sivaraya
94c6795efc updates 2026-01-16 18:38:51 -08:00
Lakee Sivaraya
86c5e1b4ff updates 2026-01-16 18:38:51 -08:00
Lakee Sivaraya
cca1772ae1 simplify 2026-01-16 18:38:51 -08:00
Lakee Sivaraya
e4dd14df7a undo 2026-01-16 18:38:51 -08:00
Lakee Sivaraya
448b8f056c undo changes 2026-01-16 18:38:51 -08:00
Lakee Sivaraya
abb671e61b rename 2026-01-16 18:38:51 -08:00
Lakee Sivaraya
f90c9c7593 undo 2026-01-16 18:38:51 -08:00
Lakee Sivaraya
2e624c20b5 reduced type confusion 2026-01-16 18:38:51 -08:00
Lakee Sivaraya
7093209bce refactor 2026-01-16 18:38:51 -08:00
Lakee Sivaraya
897891ee1e updates 2026-01-16 18:38:50 -08:00
Lakee Sivaraya
42aa794713 updates 2026-01-16 18:38:50 -08:00
Lakee Sivaraya
ea72ab5aa9 simplicifcaiton 2026-01-16 18:38:50 -08:00
Lakee Sivaraya
5173320bb5 clean comments 2026-01-16 18:38:50 -08:00
Lakee Sivaraya
26d96624af comments 2026-01-16 18:38:50 -08:00
Lakee Sivaraya
271375df9b rename 2026-01-16 18:38:50 -08:00
Lakee Sivaraya
a940dd6351 updates 2026-01-16 18:38:50 -08:00
Lakee Sivaraya
e69500726b rm 2026-01-16 18:38:50 -08:00
Lakee Sivaraya
c94bb5acda updating prompt to make it user sort 2026-01-16 18:38:50 -08:00
Lakee Sivaraya
fef2d2cc82 fix appearnce 2026-01-16 18:38:50 -08:00
Lakee Sivaraya
44909964b7 fix sorting 2026-01-16 18:38:50 -08:00
Lakee Sivaraya
1a13762617 updates 2026-01-16 18:38:50 -08:00
Lakee Sivaraya
cfffd050a2 updates 2026-01-16 18:38:50 -08:00
Lakee Sivaraya
d00997c5ea updates 2026-01-16 18:38:50 -08:00
Lakee Sivaraya
466559578e validation 2026-01-16 18:38:50 -08:00
Lakee Sivaraya
0a6312dbac better comments 2026-01-16 18:38:50 -08:00
Lakee Sivaraya
e503408825 renames 2026-01-16 18:38:50 -08:00
Lakee Sivaraya
ed543a71f9 u[dates 2026-01-16 18:38:50 -08:00
Lakee Sivaraya
7f894ec023 simplify comments 2026-01-16 18:38:50 -08:00
Lakee Sivaraya
57fbd2aa1c fixes 2026-01-16 18:38:49 -08:00
Lakee Sivaraya
80270ce7b2 fix comments 2026-01-16 18:38:49 -08:00
Lakee Sivaraya
fdc3af994c updates 2026-01-16 18:38:49 -08:00
Lakee Sivaraya
5a69d16e65 wand 2026-01-16 18:38:49 -08:00
Lakee Sivaraya
c3afbaebce update db 2026-01-16 18:38:49 -08:00
Lakee Sivaraya
793c888808 undo 2026-01-16 18:37:59 -08:00
Lakee Sivaraya
ffad20efc5 updates 2026-01-16 18:37:59 -08:00
Lakee Sivaraya
b08ce03409 refactoring 2026-01-16 18:37:58 -08:00
Lakee Sivaraya
c9373c7b3e renames & refactors 2026-01-16 18:37:58 -08:00
Lakee Sivaraya
cbb93c65b6 refactoring 2026-01-16 18:37:58 -08:00
Lakee Sivaraya
96a3fe59ff updates 2026-01-16 18:37:57 -08:00
Lakee Sivaraya
df3e869f22 updates 2026-01-16 18:37:57 -08:00
Lakee Sivaraya
b3ca0c947c updates 2026-01-16 18:37:54 -08:00
Lakee Sivaraya
cfbc8d7211 dedupe 2026-01-16 18:37:54 -08:00
Lakee Sivaraya
15bef489f2 updates 2026-01-16 18:37:53 -08:00
Lakee Sivaraya
4422a69a17 revert 2026-01-16 18:37:52 -08:00
Lakee Sivaraya
8f9cf93231 changes 2026-01-16 18:37:51 -08:00
Lakee Sivaraya
22f89cf67d comments 2026-01-16 18:37:51 -08:00
Lakee Sivaraya
dfa018f2d4 updates 2026-01-16 18:37:51 -08:00
Lakee Sivaraya
e287388b03 update comments with ai 2026-01-16 18:37:51 -08:00
Lakee Sivaraya
4d176c0717 breaking down file 2026-01-16 18:37:51 -08:00
Lakee Sivaraya
c155d8ac6c doc strings 2026-01-16 18:37:50 -08:00
Lakee Sivaraya
48250f5ed8 chages 2026-01-16 18:37:50 -08:00
Lakee Sivaraya
fc6dbcf066 updates 2026-01-16 18:37:50 -08:00
Lakee Sivaraya
a537ca7ebe updates 2026-01-16 18:37:50 -08:00
Lakee Sivaraya
c1eef30578 improved errors 2026-01-16 18:37:50 -08:00
Lakee Sivaraya
6605c887ed fix lints 2026-01-16 18:37:49 -08:00
Lakee Sivaraya
a919816bff format 2026-01-16 18:37:49 -08:00
Lakee Sivaraya
8a8589e18d one input mode 2026-01-16 18:37:49 -08:00
Lakee Sivaraya
ed807bebf2 updates 2026-01-16 18:37:49 -08:00
Lakee Sivaraya
48ecb19af7 updates 2026-01-16 18:37:49 -08:00
Lakee Sivaraya
9a3d5631f2 updates 2026-01-16 18:37:47 -08:00
Lakee Sivaraya
0872314fbf filtering ui 2026-01-16 18:37:45 -08:00
Lakee Sivaraya
7e4fc32d82 updates 2026-01-16 18:37:45 -08:00
Lakee Sivaraya
4316f45175 updates 2026-01-16 18:37:45 -08:00
Lakee Sivaraya
e80660f218 trashy table viewer 2026-01-16 18:37:45 -08:00
Lakee Sivaraya
5dddb03eac required 2026-01-16 18:37:44 -08:00
Lakee Sivaraya
6386e6b437 updates 2026-01-16 18:37:44 -08:00
679 changed files with 21598 additions and 24487 deletions

View File

@@ -44,7 +44,7 @@ services:
deploy:
resources:
limits:
memory: 1G
memory: 4G
environment:
- NODE_ENV=development
- DATABASE_URL=postgresql://postgres:postgres@db:5432/simstudio

View File

@@ -10,9 +10,6 @@ concurrency:
group: ci-${{ github.ref }}
cancel-in-progress: false
permissions:
contents: read
jobs:
test-build:
name: Test and Build
@@ -30,11 +27,10 @@ jobs:
steps:
- name: Extract version from commit message
id: extract
env:
COMMIT_MSG: ${{ github.event.head_commit.message }}
run: |
COMMIT_MSG="${{ github.event.head_commit.message }}"
# Only tag versions on main branch
if [ "$GITHUB_REF" = "refs/heads/main" ] && [[ "$COMMIT_MSG" =~ ^(v[0-9]+\.[0-9]+\.[0-9]+): ]]; then
if [ "${{ github.ref }}" = "refs/heads/main" ] && [[ "$COMMIT_MSG" =~ ^(v[0-9]+\.[0-9]+\.[0-9]+): ]]; then
VERSION="${BASH_REMATCH[1]}"
echo "version=${VERSION}" >> $GITHUB_OUTPUT
echo "is_release=true" >> $GITHUB_OUTPUT
@@ -281,30 +277,3 @@ jobs:
if: needs.check-docs-changes.outputs.docs_changed == 'true'
uses: ./.github/workflows/docs-embeddings.yml
secrets: inherit
# Create GitHub Release (only for version commits on main, after all builds complete)
create-release:
name: Create GitHub Release
runs-on: blacksmith-4vcpu-ubuntu-2404
needs: [create-ghcr-manifests, detect-version]
if: needs.detect-version.outputs.is_release == 'true'
permissions:
contents: write
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Setup Bun
uses: oven-sh/setup-bun@v2
with:
bun-version: latest
- name: Install dependencies
run: bun install --frozen-lockfile
- name: Create release
env:
GH_PAT: ${{ secrets.GITHUB_TOKEN }}
run: bun run scripts/create-single-release.ts ${{ needs.detect-version.outputs.version }}

View File

@@ -4,9 +4,6 @@ on:
workflow_call:
workflow_dispatch: # Allow manual triggering
permissions:
contents: read
jobs:
process-docs-embeddings:
name: Process Documentation Embeddings

View File

@@ -4,9 +4,6 @@ on:
workflow_call:
workflow_dispatch:
permissions:
contents: read
jobs:
migrate:
name: Apply Database Migrations

View File

@@ -6,9 +6,6 @@ on:
paths:
- 'packages/cli/**'
permissions:
contents: read
jobs:
publish-npm:
runs-on: blacksmith-4vcpu-ubuntu-2404

View File

@@ -6,9 +6,6 @@ on:
paths:
- 'packages/python-sdk/**'
permissions:
contents: write
jobs:
publish-pypi:
runs-on: blacksmith-4vcpu-ubuntu-2404

View File

@@ -6,9 +6,6 @@ on:
paths:
- 'packages/ts-sdk/**'
permissions:
contents: write
jobs:
publish-npm:
runs-on: blacksmith-4vcpu-ubuntu-2404

View File

@@ -4,9 +4,6 @@ on:
workflow_call:
workflow_dispatch:
permissions:
contents: read
jobs:
test-build:
name: Test and Build

View File

@@ -185,6 +185,11 @@ export default async function Page(props: { params: Promise<{ slug?: string[]; l
tableOfContent={{
style: 'clerk',
enabled: true,
header: (
<div key='toc-header' className='mb-2 font-medium text-sm'>
On this page
</div>
),
footer: <TOCFooter />,
single: false,
}}

View File

@@ -3,13 +3,13 @@ import { defineI18nUI } from 'fumadocs-ui/i18n'
import { DocsLayout } from 'fumadocs-ui/layouts/docs'
import { RootProvider } from 'fumadocs-ui/provider/next'
import { Geist_Mono, Inter } from 'next/font/google'
import Image from 'next/image'
import {
SidebarFolder,
SidebarItem,
SidebarSeparator,
} from '@/components/docs-layout/sidebar-components'
import { Navbar } from '@/components/navbar/navbar'
import { SimLogoFull } from '@/components/ui/sim-logo'
import { i18n } from '@/lib/i18n'
import { source } from '@/lib/source'
import '../global.css'
@@ -102,7 +102,16 @@ export default async function Layout({ children, params }: LayoutProps) {
<DocsLayout
tree={source.pageTree[lang]}
nav={{
title: <SimLogoFull className='h-7 w-auto' />,
title: (
<Image
src='/static/logo.png'
alt='Sim'
width={72}
height={28}
className='h-7 w-auto'
priority
/>
),
}}
sidebar={{
defaultOpenLevel: 0,

View File

@@ -33,41 +33,15 @@ async function loadGoogleFont(font: string, weights: string, text: string): Prom
throw new Error('Failed to load font data')
}
/**
* Sim logo with icon and "Sim" text for OG image.
*/
function SimLogoFull() {
return (
<svg height='28' viewBox='720 440 1020 320' fill='none'>
{/* Green icon - top left shape with cutout */}
<path
fillRule='evenodd'
clipRule='evenodd'
d='M875.791 577.171C875.791 581.922 873.911 586.483 870.576 589.842L870.098 590.323C866.764 593.692 862.234 595.575 857.517 595.575H750.806C740.978 595.575 733 603.6 733 613.498V728.902C733 738.799 740.978 746.826 750.806 746.826H865.382C875.209 746.826 883.177 738.799 883.177 728.902V620.853C883.177 616.448 884.912 612.222 888.008 609.104C891.093 605.997 895.29 604.249 899.664 604.249H1008.16C1017.99 604.249 1025.96 596.224 1025.96 586.327V470.923C1025.96 461.025 1017.99 453 1008.16 453H893.586C883.759 453 875.791 461.025 875.791 470.923V577.171ZM910.562 477.566H991.178C996.922 477.566 1001.57 482.254 1001.57 488.029V569.22C1001.57 574.995 996.922 579.683 991.178 579.683H910.562C904.828 579.683 900.173 574.995 900.173 569.22V488.029C900.173 482.254 904.828 477.566 910.562 477.566Z'
fill='#33C482'
/>
{/* Green icon - bottom right square */}
<path
d='M1008.3 624.59H923.113C912.786 624.59 904.414 633.022 904.414 643.423V728.171C904.414 738.572 912.786 747.004 923.113 747.004H1008.3C1018.63 747.004 1027 738.572 1027 728.171V643.423C1027 633.022 1018.63 624.59 1008.3 624.59Z'
fill='#33C482'
/>
{/* "Sim" text - white for dark background */}
<path
d='M1210.54 515.657C1226.65 515.657 1240.59 518.51 1252.31 524.257H1252.31C1264.3 529.995 1273.63 538.014 1280.26 548.319H1280.26C1287.19 558.635 1290.78 570.899 1291.08 585.068L1291.1 586.089H1249.11L1249.09 585.115C1248.8 574.003 1245.18 565.493 1238.32 559.451C1231.45 553.399 1221.79 550.308 1209.21 550.308C1196.3 550.308 1186.48 553.113 1179.61 558.588C1172.76 564.046 1169.33 571.499 1169.33 581.063C1169.33 588.092 1171.88 593.978 1177.01 598.783C1182.17 603.618 1189.99 607.399 1200.56 610.061H1200.56L1238.77 619.451C1257.24 623.65 1271.21 630.571 1280.57 640.293L1281.01 640.739C1290.13 650.171 1294.64 662.97 1294.64 679.016C1294.64 692.923 1290.88 705.205 1283.34 715.822L1283.33 715.834C1275.81 726.134 1265.44 734.14 1252.26 739.866L1252.25 739.871C1239.36 745.302 1224.12 748 1206.54 748C1180.9 748 1160.36 741.696 1145.02 728.984C1129.67 716.258 1122 699.269 1122 678.121V677.121H1163.99V678.121C1163.99 688.869 1167.87 697.367 1175.61 703.722L1176.34 704.284C1184.04 709.997 1194.37 712.902 1207.43 712.902C1222.13 712.902 1233.3 710.087 1241.07 704.588C1248.8 698.812 1252.64 691.21 1252.64 681.699C1252.64 674.769 1250.5 669.057 1246.25 664.49L1246.23 664.478L1246.22 664.464C1242.28 659.929 1234.83 656.119 1223.64 653.152L1185.43 644.208L1185.42 644.204C1166.05 639.407 1151.49 632.035 1141.83 622.012L1141.83 622.006L1141.82 622C1132.43 611.94 1127.78 598.707 1127.78 582.405C1127.78 568.81 1131.23 556.976 1138.17 546.949L1138.18 546.941L1138.19 546.933C1145.41 536.936 1155.18 529.225 1167.48 523.793L1167.48 523.79C1180.07 518.36 1194.43 515.657 1210.54 515.657ZM1323.39 521.979C1331.68 525.008 1337.55 526.482 1343.51 526.482C1349.48 526.482 1355.64 525.005 1364.49 521.973L1365.82 521.52V742.633H1322.05V521.489L1323.39 521.979ZM1642.01 515.657C1667.11 515.657 1686.94 523.031 1701.39 537.876C1715.83 552.716 1723 572.968 1723 598.507V742.633H1680.12V608.794C1680.12 591.666 1675.72 578.681 1667.07 569.681L1667.06 569.669L1667.04 569.656C1658.67 560.359 1647.26 555.675 1632.68 555.675C1622.47 555.675 1613.47 558.022 1605.64 562.69L1605.63 562.696C1598.11 567.064 1592.17 573.475 1587.8 581.968C1583.44 590.448 1581.25 600.424 1581.25 611.925V742.633H1537.92V608.347C1537.92 591.208 1533.67 578.376 1525.31 569.68L1525.31 569.674L1525.3 569.668C1516.93 560.664 1505.52 556.122 1490.93 556.122C1480.72 556.122 1471.72 558.469 1463.89 563.138L1463.88 563.144C1456.36 567.511 1450.41 573.922 1446.05 582.415L1446.05 582.422L1446.04 582.428C1441.69 590.602 1439.5 600.423 1439.5 611.925V742.633H1395.72V521.919H1435.05V554.803C1439.92 544.379 1447.91 535.465 1458.37 528.356C1470.71 519.875 1485.58 515.657 1502.93 515.657C1522.37 515.657 1538.61 520.931 1551.55 531.538C1560.38 538.771 1567.1 547.628 1571.72 558.091C1576.05 547.619 1582.83 538.757 1592.07 531.524C1605.61 520.93 1622.28 515.657 1642.01 515.657ZM1343.49 452C1351.45 452 1358.23 454.786 1363.75 460.346C1369.27 465.905 1372.04 472.721 1372.04 480.73C1372.04 488.452 1369.27 495.254 1363.77 501.096L1363.76 501.105L1363.75 501.115C1358.23 506.675 1351.45 509.461 1343.49 509.461C1335.81 509.461 1329.05 506.669 1323.25 501.134L1323.23 501.115L1323.21 501.096C1317.71 495.254 1314.94 488.452 1314.94 480.73C1314.94 472.721 1317.7 465.905 1323.23 460.346L1323.24 460.337L1323.25 460.327C1329.05 454.792 1335.81 452 1343.49 452Z'
fill='#fafafa'
/>
</svg>
)
}
/**
* Generates dynamic Open Graph images for documentation pages.
* Style matches Cursor docs: dark background, title at top, logo bottom-left, domain bottom-right.
*/
export async function GET(request: NextRequest) {
const { searchParams } = new URL(request.url)
const title = searchParams.get('title') || 'Documentation'
const baseUrl = new URL(request.url).origin
const allText = `${title}docs.sim.ai`
const fontData = await loadGoogleFont('Geist', '400;500;600', allText)
@@ -78,39 +52,84 @@ export async function GET(request: NextRequest) {
width: '100%',
display: 'flex',
flexDirection: 'column',
justifyContent: 'space-between',
padding: '56px 64px',
background: '#121212', // Dark mode background matching docs (hsla 0, 0%, 7%)
background: '#0c0c0c',
position: 'relative',
fontFamily: 'Geist',
}}
>
{/* Title at top */}
<span
{/* Base gradient layer - subtle purple tint across the entire image */}
<div
style={{
fontSize: getTitleFontSize(title),
fontWeight: 500,
color: '#fafafa', // Light text matching docs
lineHeight: 1.2,
letterSpacing: '-0.02em',
position: 'absolute',
top: 0,
left: 0,
width: '100%',
height: '100%',
background:
'radial-gradient(ellipse 150% 100% at 50% 100%, rgba(88, 28, 135, 0.15) 0%, rgba(88, 28, 135, 0.08) 25%, rgba(88, 28, 135, 0.03) 50%, transparent 80%)',
display: 'flex',
}}
>
{title}
</span>
/>
{/* Footer: icon left, domain right */}
{/* Secondary glow - adds depth without harsh edges */}
<div
style={{
position: 'absolute',
top: 0,
left: 0,
width: '100%',
height: '100%',
background:
'radial-gradient(ellipse 100% 80% at 80% 90%, rgba(112, 31, 252, 0.12) 0%, rgba(112, 31, 252, 0.04) 40%, transparent 70%)',
display: 'flex',
}}
/>
{/* Top darkening - creates natural vignette */}
<div
style={{
position: 'absolute',
top: 0,
left: 0,
width: '100%',
height: '100%',
background:
'linear-gradient(180deg, rgba(0, 0, 0, 0.3) 0%, transparent 40%, transparent 100%)',
display: 'flex',
}}
/>
{/* Content */}
<div
style={{
display: 'flex',
flexDirection: 'column',
padding: '56px 72px',
height: '100%',
justifyContent: 'space-between',
alignItems: 'center',
width: '100%',
}}
>
<SimLogoFull />
{/* Logo */}
<img src={`${baseUrl}/static/logo.png`} alt='sim' height={32} />
{/* Title */}
<span
style={{
fontSize: getTitleFontSize(title),
fontWeight: 600,
color: '#ffffff',
lineHeight: 1.1,
letterSpacing: '-0.02em',
}}
>
{title}
</span>
{/* Footer */}
<span
style={{
fontSize: 20,
fontWeight: 400,
fontWeight: 500,
color: '#71717a',
}}
>

View File

@@ -9,20 +9,11 @@ body {
}
@theme {
--color-fd-primary: #33c482; /* Green from Sim logo */
--color-fd-primary: #802fff; /* Purple from control-bar component */
--font-geist-sans: var(--font-geist-sans);
--font-geist-mono: var(--font-geist-mono);
}
/* Ensure primary color is set in both light and dark modes */
:root {
--color-fd-primary: #33c482;
}
.dark {
--color-fd-primary: #33c482;
}
/* Font family utilities */
.font-sans {
font-family: var(--font-geist-sans), ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont,
@@ -43,7 +34,7 @@ body {
:root {
--fd-border: transparent !important;
--fd-border-sidebar: transparent !important;
--fd-nav-height: 65px; /* Custom navbar height (h-16 = 64px + 1px border) */
--fd-nav-height: 64px; /* Custom navbar height (h-16 = 4rem = 64px) */
/* Content container width used to center main content */
--spacing-fd-container: 1400px;
/* Edge gutter = leftover space on each side of centered container */
@@ -128,28 +119,15 @@ aside#nd-sidebar {
}
}
/* Hide TOC popover on tablet/medium screens (768px - 1279px) */
/* Keeps it visible on mobile (<768px) for easy navigation */
/* Desktop (>=1280px) already hides it via fumadocs xl:hidden */
@media (min-width: 768px) and (max-width: 1279px) {
#nd-docs-layout {
--fd-toc-popover-height: 0px !important;
}
[data-toc-popover] {
display: none !important;
}
}
/* Desktop only: Apply custom navbar offset, sidebar width and margin offsets */
/* On mobile, let fumadocs handle the layout natively */
@media (min-width: 1024px) {
:root {
--fd-banner-height: 65px !important; /* 64px navbar + 1px border */
--fd-banner-height: 64px !important;
}
#nd-docs-layout {
--fd-docs-height: calc(100dvh - 65px) !important; /* 64px navbar + 1px border */
--fd-docs-height: calc(100dvh - 64px) !important;
--fd-sidebar-width: 300px !important;
margin-left: var(--sidebar-offset) !important;
margin-right: var(--toc-offset) !important;
@@ -236,19 +214,19 @@ html:not(.dark) #nd-sidebar button:not([aria-label*="ollapse"]):not([aria-label*
letter-spacing: 0.05em !important;
}
/* Override active state */
/* Override active state (NO PURPLE) */
#nd-sidebar a[data-active="true"],
#nd-sidebar button[data-active="true"],
#nd-sidebar a.bg-fd-primary\/10,
#nd-sidebar a.text-fd-primary,
#nd-sidebar a[class*="bg-fd-primary"],
#nd-sidebar a[class*="text-fd-primary"],
/* Override custom sidebar green classes */
/* Override custom sidebar purple classes */
#nd-sidebar
a.bg-emerald-50\/80,
#nd-sidebar a.text-emerald-600,
#nd-sidebar a[class*="bg-emerald"],
#nd-sidebar a[class*="text-emerald"] {
a.bg-purple-50\/80,
#nd-sidebar a.text-purple-600,
#nd-sidebar a[class*="bg-purple"],
#nd-sidebar a[class*="text-purple"] {
background-image: none !important;
}
@@ -259,10 +237,10 @@ html.dark #nd-sidebar a.bg-fd-primary\/10,
html.dark #nd-sidebar a.text-fd-primary,
html.dark #nd-sidebar a[class*="bg-fd-primary"],
html.dark #nd-sidebar a[class*="text-fd-primary"],
html.dark #nd-sidebar a.bg-emerald-50\/80,
html.dark #nd-sidebar a.text-emerald-600,
html.dark #nd-sidebar a[class*="bg-emerald"],
html.dark #nd-sidebar a[class*="text-emerald"] {
html.dark #nd-sidebar a.bg-purple-50\/80,
html.dark #nd-sidebar a.text-purple-600,
html.dark #nd-sidebar a[class*="bg-purple"],
html.dark #nd-sidebar a[class*="text-purple"] {
background-color: rgba(255, 255, 255, 0.15) !important;
color: rgba(255, 255, 255, 1) !important;
}
@@ -274,10 +252,10 @@ html:not(.dark) #nd-sidebar a.bg-fd-primary\/10,
html:not(.dark) #nd-sidebar a.text-fd-primary,
html:not(.dark) #nd-sidebar a[class*="bg-fd-primary"],
html:not(.dark) #nd-sidebar a[class*="text-fd-primary"],
html:not(.dark) #nd-sidebar a.bg-emerald-50\/80,
html:not(.dark) #nd-sidebar a.text-emerald-600,
html:not(.dark) #nd-sidebar a[class*="bg-emerald"],
html:not(.dark) #nd-sidebar a[class*="text-emerald"] {
html:not(.dark) #nd-sidebar a.bg-purple-50\/80,
html:not(.dark) #nd-sidebar a.text-purple-600,
html:not(.dark) #nd-sidebar a[class*="bg-purple"],
html:not(.dark) #nd-sidebar a[class*="text-purple"] {
background-color: rgba(0, 0, 0, 0.07) !important;
color: rgba(0, 0, 0, 0.9) !important;
}
@@ -295,8 +273,8 @@ html:not(.dark) #nd-sidebar button:hover:not([data-active="true"]) {
}
/* Dark mode - ensure active/selected items don't change on hover */
html.dark #nd-sidebar a.bg-emerald-50\/80:hover,
html.dark #nd-sidebar a[class*="bg-emerald"]:hover,
html.dark #nd-sidebar a.bg-purple-50\/80:hover,
html.dark #nd-sidebar a[class*="bg-purple"]:hover,
html.dark #nd-sidebar a[data-active="true"]:hover,
html.dark #nd-sidebar button[data-active="true"]:hover {
background-color: rgba(255, 255, 255, 0.15) !important;
@@ -304,8 +282,8 @@ html.dark #nd-sidebar button[data-active="true"]:hover {
}
/* Light mode - ensure active/selected items don't change on hover */
html:not(.dark) #nd-sidebar a.bg-emerald-50\/80:hover,
html:not(.dark) #nd-sidebar a[class*="bg-emerald"]:hover,
html:not(.dark) #nd-sidebar a.bg-purple-50\/80:hover,
html:not(.dark) #nd-sidebar a[class*="bg-purple"]:hover,
html:not(.dark) #nd-sidebar a[data-active="true"]:hover,
html:not(.dark) #nd-sidebar button[data-active="true"]:hover {
background-color: rgba(0, 0, 0, 0.07) !important;
@@ -377,24 +355,16 @@ aside[data-sidebar] > *:not([data-sidebar-viewport]) {
button[aria-label="Toggle Sidebar"],
button[aria-label="Collapse Sidebar"],
/* Hide nav title/logo in sidebar on desktop - target all possible locations */
/* Lower specificity selectors first (attribute selectors) */
[data-sidebar-header],
[data-sidebar] [data-title],
aside[data-sidebar] a[href="/"],
aside[data-sidebar] a[href="/"] img,
aside[data-sidebar] > a:first-child,
aside[data-sidebar] > div > a:first-child,
aside[data-sidebar] img[alt="Sim"],
aside[data-sidebar] svg[aria-label="Sim"],
/* Higher specificity selectors (ID selectors) */
#nd-sidebar
a[href="/"],
#nd-sidebar a[href="/"] img,
#nd-sidebar a[href="/"] svg,
[data-sidebar-header],
[data-sidebar] [data-title],
#nd-sidebar > a:first-child,
#nd-sidebar > div:first-child > a:first-child,
#nd-sidebar img[alt="Sim"],
#nd-sidebar svg[aria-label="Sim"],
/* Hide theme toggle at bottom of sidebar on desktop */
#nd-sidebar
> footer,
@@ -532,15 +502,6 @@ pre code .line {
color: var(--color-fd-primary);
}
/* ============================================
TOC (Table of Contents) Styling
============================================ */
/* Remove the thin border-left on nested TOC items (keeps main indicator only) */
#nd-toc a[style*="padding-inline-start"] {
border-left: none !important;
}
/* Add bottom spacing to prevent abrupt page endings */
[data-content] {
padding-top: 1.5rem !important;

View File

@@ -44,7 +44,7 @@ export function SidebarItem({ item }: { item: Item }) {
'lg:text-gray-600 lg:dark:text-gray-400',
!active && 'lg:hover:bg-gray-100/60 lg:dark:hover:bg-gray-800/40',
active &&
'lg:bg-emerald-50/80 lg:font-normal lg:text-emerald-600 lg:dark:bg-emerald-900/15 lg:dark:text-emerald-400'
'lg:bg-purple-50/80 lg:font-normal lg:text-purple-600 lg:dark:bg-purple-900/15 lg:dark:text-purple-400'
)}
>
{item.name}
@@ -79,7 +79,7 @@ export function SidebarFolder({ item, children }: { item: Folder; children: Reac
'lg:text-gray-600 lg:dark:text-gray-400',
!active && 'lg:hover:bg-gray-100/60 lg:dark:hover:bg-gray-800/40',
active &&
'lg:bg-emerald-50/80 lg:font-normal lg:text-emerald-600 lg:dark:bg-emerald-900/15 lg:dark:text-emerald-400'
'lg:bg-purple-50/80 lg:font-normal lg:text-purple-600 lg:dark:bg-purple-900/15 lg:dark:text-purple-400'
)}
>
{item.name}
@@ -104,7 +104,7 @@ export function SidebarFolder({ item, children }: { item: Folder; children: Reac
'lg:text-gray-800 lg:dark:text-gray-200',
!active && 'lg:hover:bg-gray-100/60 lg:dark:hover:bg-gray-800/40',
active &&
'lg:bg-emerald-50/80 lg:text-emerald-600 lg:dark:bg-emerald-900/15 lg:dark:text-emerald-400'
'lg:bg-purple-50/80 lg:text-purple-600 lg:dark:bg-purple-900/15 lg:dark:text-purple-400'
)}
>
{item.name}

View File

@@ -23,7 +23,7 @@ export function TOCFooter() {
rel='noopener noreferrer'
onMouseEnter={() => setIsHovered(true)}
onMouseLeave={() => setIsHovered(false)}
className='group mt-2 inline-flex h-8 w-fit items-center justify-center gap-1 whitespace-nowrap rounded-[10px] border border-[#2AAD6C] bg-gradient-to-b from-[#3ED990] to-[#2AAD6C] px-3 pr-[10px] pl-[12px] font-medium text-sm text-white shadow-[inset_0_2px_4px_0_#5EE8A8] outline-none transition-all hover:shadow-lg focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50'
className='group mt-2 inline-flex h-8 w-fit items-center justify-center gap-1 whitespace-nowrap rounded-[10px] border border-[#6F3DFA] bg-gradient-to-b from-[#8357FF] to-[#6F3DFA] px-3 pr-[10px] pl-[12px] font-medium text-sm text-white shadow-[inset_0_2px_4px_0_#9B77FF] outline-none transition-all hover:shadow-lg focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50'
aria-label='Get started with Sim - Sign up for free'
>
<span>Get started</span>

View File

@@ -4696,6 +4696,26 @@ export function BedrockIcon(props: SVGProps<SVGSVGElement>) {
)
}
export function TableIcon(props: SVGProps<SVGSVGElement>) {
return (
<svg
xmlns='http://www.w3.org/2000/svg'
viewBox='0 0 24 24'
fill='none'
stroke='currentColor'
strokeWidth={2}
strokeLinecap='round'
strokeLinejoin='round'
{...props}
>
<rect width='18' height='18' x='3' y='3' rx='2' />
<path d='M3 9h18' />
<path d='M3 15h18' />
<path d='M9 3v18' />
<path d='M15 3v18' />
</svg>
)
}
export function ReductoIcon(props: SVGProps<SVGSVGElement>) {
return (
<svg

View File

@@ -1,9 +1,9 @@
'use client'
import Image from 'next/image'
import Link from 'next/link'
import { LanguageDropdown } from '@/components/ui/language-dropdown'
import { SearchTrigger } from '@/components/ui/search-trigger'
import { SimLogoFull } from '@/components/ui/sim-logo'
import { ThemeToggle } from '@/components/ui/theme-toggle'
export function Navbar() {
@@ -27,7 +27,13 @@ export function Navbar() {
{/* Left cluster: logo */}
<div className='flex items-center'>
<Link href='/' className='flex min-w-[100px] items-center'>
<SimLogoFull className='h-7 w-auto' />
<Image
src='/static/logo.png'
alt='Sim'
width={72}
height={28}
className='h-7 w-auto'
/>
</Link>
</div>

View File

@@ -1,87 +0,0 @@
'use client'
import { useState } from 'react'
import { cn, getAssetUrl } from '@/lib/utils'
import { Lightbox } from './lightbox'
interface ActionImageProps {
src: string
alt: string
enableLightbox?: boolean
}
interface ActionVideoProps {
src: string
alt: string
enableLightbox?: boolean
}
export function ActionImage({ src, alt, enableLightbox = true }: ActionImageProps) {
const [isLightboxOpen, setIsLightboxOpen] = useState(false)
const handleClick = () => {
if (enableLightbox) {
setIsLightboxOpen(true)
}
}
return (
<>
<img
src={src}
alt={alt}
onClick={handleClick}
className={cn(
'inline-block w-full max-w-[200px] rounded border border-neutral-200 dark:border-neutral-700',
enableLightbox && 'cursor-pointer transition-opacity hover:opacity-90'
)}
/>
{enableLightbox && (
<Lightbox
isOpen={isLightboxOpen}
onClose={() => setIsLightboxOpen(false)}
src={src}
alt={alt}
type='image'
/>
)}
</>
)
}
export function ActionVideo({ src, alt, enableLightbox = true }: ActionVideoProps) {
const [isLightboxOpen, setIsLightboxOpen] = useState(false)
const resolvedSrc = getAssetUrl(src)
const handleClick = () => {
if (enableLightbox) {
setIsLightboxOpen(true)
}
}
return (
<>
<video
src={resolvedSrc}
autoPlay
loop
muted
playsInline
onClick={handleClick}
className={cn(
'inline-block w-full max-w-[200px] rounded border border-neutral-200 dark:border-neutral-700',
enableLightbox && 'cursor-pointer transition-opacity hover:opacity-90'
)}
/>
{enableLightbox && (
<Lightbox
isOpen={isLightboxOpen}
onClose={() => setIsLightboxOpen(false)}
src={src}
alt={alt}
type='video'
/>
)}
</>
)
}

View File

@@ -101,12 +101,14 @@ import {
ShopifyIcon,
SlackIcon,
SmtpIcon,
SpotifyIcon,
SQSIcon,
SshIcon,
STTIcon,
StagehandIcon,
StripeIcon,
SupabaseIcon,
TableIcon,
TavilyIcon,
TelegramIcon,
TextractIcon,
@@ -181,7 +183,7 @@ export const blockTypeToIconMap: Record<string, IconComponent> = {
jina: JinaAIIcon,
jira: JiraIcon,
jira_service_management: JiraServiceManagementIcon,
kalshi_v2: KalshiIcon,
kalshi: KalshiIcon,
knowledge: PackageSearchIcon,
langsmith: LangsmithIcon,
lemlist: LemlistIcon,
@@ -228,12 +230,14 @@ export const blockTypeToIconMap: Record<string, IconComponent> = {
shopify: ShopifyIcon,
slack: SlackIcon,
smtp: SmtpIcon,
spotify: SpotifyIcon,
sqs: SQSIcon,
ssh: SshIcon,
stagehand: StagehandIcon,
stripe: StripeIcon,
stt: STTIcon,
supabase: SupabaseIcon,
table: TableIcon,
tavily: TavilyIcon,
telegram: TelegramIcon,
textract: TextractIcon,

View File

@@ -1,9 +1,8 @@
'use client'
import { useEffect, useState } from 'react'
import { Check, ChevronDown } from 'lucide-react'
import { Check, ChevronRight } from 'lucide-react'
import { useParams, usePathname, useRouter } from 'next/navigation'
import { cn } from '@/lib/utils'
const languages = {
en: { name: 'English', flag: '🇺🇸' },
@@ -16,7 +15,6 @@ const languages = {
export function LanguageDropdown() {
const [isOpen, setIsOpen] = useState(false)
const [hoveredIndex, setHoveredIndex] = useState<number>(-1)
const pathname = usePathname()
const params = useParams()
const router = useRouter()
@@ -73,15 +71,6 @@ export function LanguageDropdown() {
return () => window.removeEventListener('keydown', onKey)
}, [isOpen])
// Reset hovered index when popover closes
useEffect(() => {
if (!isOpen) {
setHoveredIndex(-1)
}
}, [isOpen])
const languageEntries = Object.entries(languages)
return (
<div className='relative'>
<button
@@ -93,14 +82,14 @@ export function LanguageDropdown() {
aria-haspopup='listbox'
aria-expanded={isOpen}
aria-controls='language-menu'
className='flex cursor-pointer items-center gap-1.5 rounded-[6px] px-3 py-2 font-normal text-[0.9375rem] text-foreground/60 leading-[1.4] transition-colors hover:bg-foreground/8 hover:text-foreground focus:outline-none focus-visible:ring-2 focus-visible:ring-ring'
className='flex cursor-pointer items-center gap-1.5 rounded-xl px-3 py-2 font-normal text-[0.9375rem] text-foreground/60 leading-[1.4] transition-colors hover:bg-foreground/8 hover:text-foreground focus:outline-none focus-visible:ring-2 focus-visible:ring-ring'
style={{
fontFamily:
'-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif',
}}
>
<span>{languages[currentLang as keyof typeof languages]?.name}</span>
<ChevronDown className={cn('h-3.5 w-3.5 transition-transform', isOpen && 'rotate-180')} />
<ChevronRight className='h-3.5 w-3.5' />
</button>
{isOpen && (
@@ -109,37 +98,29 @@ export function LanguageDropdown() {
<div
id='language-menu'
role='listbox'
className='absolute top-full right-0 z-[1001] mt-2 max-h-[400px] min-w-[160px] overflow-auto rounded-[6px] bg-white px-[6px] py-[6px] shadow-lg dark:bg-neutral-900'
className='absolute top-full right-0 z-[1001] mt-1 max-h-[75vh] w-56 overflow-auto rounded-xl border border-border/50 bg-white shadow-2xl md:w-44 md:bg-background/95 md:backdrop-blur-md dark:bg-neutral-950 md:dark:bg-background/95'
>
{languageEntries.map(([code, lang], index) => {
const isSelected = currentLang === code
const isHovered = hoveredIndex === index
return (
<button
key={code}
onClick={(e) => {
e.preventDefault()
e.stopPropagation()
handleLanguageChange(code)
}}
onMouseEnter={() => setHoveredIndex(index)}
onMouseLeave={() => setHoveredIndex(-1)}
role='option'
aria-selected={isSelected}
className={cn(
'flex h-[26px] w-full min-w-0 cursor-pointer items-center gap-[8px] rounded-[6px] px-[6px] text-[13px] transition-colors',
'text-neutral-700 dark:text-neutral-200',
isHovered && 'bg-neutral-100 dark:bg-neutral-800',
'focus:outline-none'
)}
>
<span className='text-[13px]'>{lang.flag}</span>
<span className='flex-1 text-left leading-none'>{lang.name}</span>
{isSelected && <Check className='ml-auto h-3.5 w-3.5' />}
</button>
)
})}
{Object.entries(languages).map(([code, lang]) => (
<button
key={code}
onClick={(e) => {
e.preventDefault()
e.stopPropagation()
handleLanguageChange(code)
}}
role='option'
aria-selected={currentLang === code}
className={`flex w-full cursor-pointer items-center gap-3 px-3 py-3 text-base transition-colors first:rounded-t-xl last:rounded-b-xl hover:bg-muted/80 focus:outline-none focus-visible:ring-2 focus-visible:ring-ring md:gap-2 md:px-2.5 md:py-2 md:text-sm ${
currentLang === code ? 'bg-muted/60 font-medium text-primary' : 'text-foreground'
}`}
>
<span className='text-base md:text-sm'>{lang.flag}</span>
<span className='leading-none'>{lang.name}</span>
{currentLang === code && (
<Check className='ml-auto h-4 w-4 text-primary md:h-3.5 md:w-3.5' />
)}
</button>
))}
</div>
</>
)}

View File

@@ -1,108 +0,0 @@
'use client'
import { cn } from '@/lib/utils'
interface SimLogoProps {
className?: string
}
/**
* Sim logo with icon and text.
* The icon stays green (#33C482), text adapts to light/dark mode.
*/
export function SimLogo({ className }: SimLogoProps) {
return (
<svg
viewBox='720 440 320 320'
fill='none'
xmlns='http://www.w3.org/2000/svg'
className={cn('h-7 w-auto', className)}
aria-label='Sim'
>
{/* Green icon - top left shape with cutout */}
<path
fillRule='evenodd'
clipRule='evenodd'
d='M875.791 577.171C875.791 581.922 873.911 586.483 870.576 589.842L870.098 590.323C866.764 593.692 862.234 595.575 857.517 595.575H750.806C740.978 595.575 733 603.6 733 613.498V728.902C733 738.799 740.978 746.826 750.806 746.826H865.382C875.209 746.826 883.177 738.799 883.177 728.902V620.853C883.177 616.448 884.912 612.222 888.008 609.104C891.093 605.997 895.29 604.249 899.664 604.249H1008.16C1017.99 604.249 1025.96 596.224 1025.96 586.327V470.923C1025.96 461.025 1017.99 453 1008.16 453H893.586C883.759 453 875.791 461.025 875.791 470.923V577.171ZM910.562 477.566H991.178C996.922 477.566 1001.57 482.254 1001.57 488.029V569.22C1001.57 574.995 996.922 579.683 991.178 579.683H910.562C904.828 579.683 900.173 574.995 900.173 569.22V488.029C900.173 482.254 904.828 477.566 910.562 477.566Z'
fill='#33C482'
/>
{/* Green icon - bottom right square */}
<path
d='M1008.3 624.59H923.113C912.786 624.59 904.414 633.022 904.414 643.423V728.171C904.414 738.572 912.786 747.004 923.113 747.004H1008.3C1018.63 747.004 1027 738.572 1027 728.171V643.423C1027 633.022 1018.63 624.59 1008.3 624.59Z'
fill='#33C482'
/>
{/* Gradient overlay on bottom right square */}
<path
d='M1008.3 624.199H923.113C912.786 624.199 904.414 632.631 904.414 643.033V727.78C904.414 738.181 912.786 746.612 923.113 746.612H1008.3C1018.63 746.612 1027 738.181 1027 727.78V643.033C1027 632.631 1018.63 624.199 1008.3 624.199Z'
fill='url(#sim-logo-gradient)'
fillOpacity='0.2'
/>
<defs>
<linearGradient
id='sim-logo-gradient'
x1='904.414'
y1='624.199'
x2='978.836'
y2='698.447'
gradientUnits='userSpaceOnUse'
>
<stop />
<stop offset='1' stopOpacity='0' />
</linearGradient>
</defs>
</svg>
)
}
/**
* Full Sim logo with icon and "Sim" text.
* The icon stays green (#33C482), text adapts to light/dark mode.
*/
export function SimLogoFull({ className }: SimLogoProps) {
return (
<svg
viewBox='720 440 1020 320'
fill='none'
xmlns='http://www.w3.org/2000/svg'
className={cn('h-7 w-auto', className)}
aria-label='Sim'
>
{/* Green icon - top left shape with cutout */}
<path
fillRule='evenodd'
clipRule='evenodd'
d='M875.791 577.171C875.791 581.922 873.911 586.483 870.576 589.842L870.098 590.323C866.764 593.692 862.234 595.575 857.517 595.575H750.806C740.978 595.575 733 603.6 733 613.498V728.902C733 738.799 740.978 746.826 750.806 746.826H865.382C875.209 746.826 883.177 738.799 883.177 728.902V620.853C883.177 616.448 884.912 612.222 888.008 609.104C891.093 605.997 895.29 604.249 899.664 604.249H1008.16C1017.99 604.249 1025.96 596.224 1025.96 586.327V470.923C1025.96 461.025 1017.99 453 1008.16 453H893.586C883.759 453 875.791 461.025 875.791 470.923V577.171ZM910.562 477.566H991.178C996.922 477.566 1001.57 482.254 1001.57 488.029V569.22C1001.57 574.995 996.922 579.683 991.178 579.683H910.562C904.828 579.683 900.173 574.995 900.173 569.22V488.029C900.173 482.254 904.828 477.566 910.562 477.566Z'
fill='#33C482'
/>
{/* Green icon - bottom right square */}
<path
d='M1008.3 624.59H923.113C912.786 624.59 904.414 633.022 904.414 643.423V728.171C904.414 738.572 912.786 747.004 923.113 747.004H1008.3C1018.63 747.004 1027 738.572 1027 728.171V643.423C1027 633.022 1018.63 624.59 1008.3 624.59Z'
fill='#33C482'
/>
{/* Gradient overlay on bottom right square */}
<path
d='M1008.3 624.199H923.113C912.786 624.199 904.414 632.631 904.414 643.033V727.78C904.414 738.181 912.786 746.612 923.113 746.612H1008.3C1018.63 746.612 1027 738.181 1027 727.78V643.033C1027 632.631 1018.63 624.199 1008.3 624.199Z'
fill='url(#sim-logo-full-gradient)'
fillOpacity='0.2'
/>
{/* "Sim" text - adapts to light/dark mode via currentColor */}
<path
d='M1210.54 515.657C1226.65 515.657 1240.59 518.51 1252.31 524.257H1252.31C1264.3 529.995 1273.63 538.014 1280.26 548.319H1280.26C1287.19 558.635 1290.78 570.899 1291.08 585.068L1291.1 586.089H1249.11L1249.09 585.115C1248.8 574.003 1245.18 565.493 1238.32 559.451C1231.45 553.399 1221.79 550.308 1209.21 550.308C1196.3 550.308 1186.48 553.113 1179.61 558.588C1172.76 564.046 1169.33 571.499 1169.33 581.063C1169.33 588.092 1171.88 593.978 1177.01 598.783C1182.17 603.618 1189.99 607.399 1200.56 610.061H1200.56L1238.77 619.451C1257.24 623.65 1271.21 630.571 1280.57 640.293L1281.01 640.739C1290.13 650.171 1294.64 662.97 1294.64 679.016C1294.64 692.923 1290.88 705.205 1283.34 715.822L1283.33 715.834C1275.81 726.134 1265.44 734.14 1252.26 739.866L1252.25 739.871C1239.36 745.302 1224.12 748 1206.54 748C1180.9 748 1160.36 741.696 1145.02 728.984C1129.67 716.258 1122 699.269 1122 678.121V677.121H1163.99V678.121C1163.99 688.869 1167.87 697.367 1175.61 703.722L1176.34 704.284C1184.04 709.997 1194.37 712.902 1207.43 712.902C1222.13 712.902 1233.3 710.087 1241.07 704.588C1248.8 698.812 1252.64 691.21 1252.64 681.699C1252.64 674.769 1250.5 669.057 1246.25 664.49L1246.23 664.478L1246.22 664.464C1242.28 659.929 1234.83 656.119 1223.64 653.152L1185.43 644.208L1185.42 644.204C1166.05 639.407 1151.49 632.035 1141.83 622.012L1141.83 622.006L1141.82 622C1132.43 611.94 1127.78 598.707 1127.78 582.405C1127.78 568.81 1131.23 556.976 1138.17 546.949L1138.18 546.941L1138.19 546.933C1145.41 536.936 1155.18 529.225 1167.48 523.793L1167.48 523.79C1180.07 518.36 1194.43 515.657 1210.54 515.657ZM1323.39 521.979C1331.68 525.008 1337.55 526.482 1343.51 526.482C1349.48 526.482 1355.64 525.005 1364.49 521.973L1365.82 521.52V742.633H1322.05V521.489L1323.39 521.979ZM1642.01 515.657C1667.11 515.657 1686.94 523.031 1701.39 537.876C1715.83 552.716 1723 572.968 1723 598.507V742.633H1680.12V608.794C1680.12 591.666 1675.72 578.681 1667.07 569.681L1667.06 569.669L1667.04 569.656C1658.67 560.359 1647.26 555.675 1632.68 555.675C1622.47 555.675 1613.47 558.022 1605.64 562.69L1605.63 562.696C1598.11 567.064 1592.17 573.475 1587.8 581.968C1583.44 590.448 1581.25 600.424 1581.25 611.925V742.633H1537.92V608.347C1537.92 591.208 1533.67 578.376 1525.31 569.68L1525.31 569.674L1525.3 569.668C1516.93 560.664 1505.52 556.122 1490.93 556.122C1480.72 556.122 1471.72 558.469 1463.89 563.138L1463.88 563.144C1456.36 567.511 1450.41 573.922 1446.05 582.415L1446.05 582.422L1446.04 582.428C1441.69 590.602 1439.5 600.423 1439.5 611.925V742.633H1395.72V521.919H1435.05V554.803C1439.92 544.379 1447.91 535.465 1458.37 528.356C1470.71 519.875 1485.58 515.657 1502.93 515.657C1522.37 515.657 1538.61 520.931 1551.55 531.538C1560.38 538.771 1567.1 547.628 1571.72 558.091C1576.05 547.619 1582.83 538.757 1592.07 531.524C1605.61 520.93 1622.28 515.657 1642.01 515.657ZM1343.49 452C1351.45 452 1358.23 454.786 1363.75 460.346C1369.27 465.905 1372.04 472.721 1372.04 480.73C1372.04 488.452 1369.27 495.254 1363.77 501.096L1363.76 501.105L1363.75 501.115C1358.23 506.675 1351.45 509.461 1343.49 509.461C1335.81 509.461 1329.05 506.669 1323.25 501.134L1323.23 501.115L1323.21 501.096C1317.71 495.254 1314.94 488.452 1314.94 480.73C1314.94 472.721 1317.7 465.905 1323.23 460.346L1323.24 460.337L1323.25 460.327C1329.05 454.792 1335.81 452 1343.49 452Z'
className='fill-neutral-900 dark:fill-white'
/>
<defs>
<linearGradient
id='sim-logo-full-gradient'
x1='904.414'
y1='624.199'
x2='978.836'
y2='698.447'
gradientUnits='userSpaceOnUse'
>
<stop />
<stop offset='1' stopOpacity='0' />
</linearGradient>
</defs>
</svg>
)
}

View File

@@ -17,7 +17,7 @@ MCP-Server gruppieren Ihre Workflow-Tools zusammen. Erstellen und verwalten Sie
<Video src="mcp/mcp-server.mp4" width={700} height={450} />
</div>
1. Navigieren Sie zu **Einstellungen → MCP-Server**
1. Navigieren Sie zu **Einstellungen → Bereitgestellte MCPs**
2. Klicken Sie auf **Server erstellen**
3. Geben Sie einen Namen und eine optionale Beschreibung ein
4. Kopieren Sie die Server-URL zur Verwendung in Ihren MCP-Clients
@@ -79,7 +79,7 @@ Füge deinen API-Key-Header (`X-API-Key`) für authentifizierten Zugriff hinzu,
## Server-Verwaltung
In der Server-Detailansicht unter **Einstellungen → MCP-Server** können Sie:
In der Server-Detailansicht unter **Einstellungen → Bereitgestellte MCPs** können Sie:
- **Tools anzeigen**: Alle Workflows sehen, die einem Server hinzugefügt wurden
- **URL kopieren**: Die Server-URL für MCP-Clients abrufen

View File

@@ -27,7 +27,7 @@ MCP-Server stellen Sammlungen von Tools bereit, die Ihre Agenten nutzen können.
</div>
1. Navigieren Sie zu Ihren Workspace-Einstellungen
2. Gehen Sie zum Abschnitt **MCP-Server**
2. Gehen Sie zum Abschnitt **Bereitgestellte MCPs**
3. Klicken Sie auf **MCP-Server hinzufügen**
4. Geben Sie die Server-Konfigurationsdetails ein
5. Speichern Sie die Konfiguration

View File

@@ -10,20 +10,12 @@ Stellen Sie Sim auf Ihrer eigenen Infrastruktur mit Docker oder Kubernetes berei
## Anforderungen
| Ressource | Klein | Standard | Produktion |
|----------|-------|----------|------------|
| CPU | 2 Kerne | 4 Kerne | 8+ Kerne |
| RAM | 12 GB | 16 GB | 32+ GB |
| Speicher | 20 GB SSD | 50 GB SSD | 100+ GB SSD |
| Docker | 20.10+ | 20.10+ | Neueste Version |
**Klein**: Entwicklung, Tests, Einzelnutzer (1-5 Nutzer)
**Standard**: Teams (5-50 Nutzer), moderate Arbeitslasten
**Produktion**: Große Teams (50+ Nutzer), Hochverfügbarkeit, intensive Workflow-Ausführung
<Callout type="info">
Die Ressourcenanforderungen werden durch Workflow-Ausführung (isolated-vm Sandboxing), Dateiverarbeitung (In-Memory-Dokumentenparsing) und Vektoroperationen (pgvector) bestimmt. Arbeitsspeicher ist typischerweise der limitierende Faktor, nicht CPU. Produktionsdaten zeigen, dass die Hauptanwendung durchschnittlich 4-8 GB und bei hoher Last bis zu 12 GB benötigt.
</Callout>
| Ressource | Minimum | Empfohlen |
|----------|---------|-------------|
| CPU | 2 Kerne | 4+ Kerne |
| RAM | 12 GB | 16+ GB |
| Speicher | 20 GB SSD | 50+ GB SSD |
| Docker | 20.10+ | Neueste Version |
## Schnellstart

View File

@@ -56,10 +56,6 @@ Controls response randomness and creativity:
- **Medium (0.3-0.7)**: Balanced creativity and focus. Good for general use.
- **High (0.7-2.0)**: Creative and varied. Ideal for brainstorming and content generation.
### Max Output Tokens
Controls the maximum length of the model's response. For Anthropic models, Sim uses reliable defaults: streaming executions use the model's full capacity (e.g. 64,000 tokens for Claude 4.5), while non-streaming executions default to 8,192 to avoid timeout issues. For long-form content generation via API, explicitly set a higher value.
### API Key
Your API key for the selected LLM provider. This is securely stored and used for authentication.

View File

@@ -124,44 +124,11 @@ Choose between four types of loops:
3. Drag other blocks inside the loop container
4. Connect the blocks as needed
### Referencing Loop Data
### Accessing Results
There's an important distinction between referencing loop data from **inside** vs **outside** the loop:
After a loop completes, you can access aggregated results:
<Tabs items={['Inside the Loop', 'Outside the Loop']}>
<Tab>
**Inside the loop**, use `<loop.>` references to access the current iteration context:
- **`<loop.index>`**: Current iteration number (0-based)
- **`<loop.currentItem>`**: Current item being processed (forEach only)
- **`<loop.items>`**: Full collection being iterated (forEach only)
```
// Inside a Function block within the loop
const idx = <loop.index>; // 0, 1, 2, ...
const item = <loop.currentItem>; // Current item
```
<Callout type="info">
These references are only available for blocks **inside** the loop container. They give you access to the current iteration's context.
</Callout>
</Tab>
<Tab>
**Outside the loop** (after it completes), reference the loop block by its name to access aggregated results:
- **`<LoopBlockName.results>`**: Array of results from all iterations
```
// If your loop block is named "Process Items"
const allResults = <processitems.results>;
// Returns: [result1, result2, result3, ...]
```
<Callout type="info">
After the loop completes, use the loop's block name (not `loop.`) to access the collected results. The block name is normalized (lowercase, no spaces).
</Callout>
</Tab>
</Tabs>
- **`<loop.results>`**: Array of results from all loop iterations
## Example Use Cases
@@ -217,29 +184,28 @@ Variables (i=0) → Loop (While i<10) → Agent (Process) → Variables (i++)
</ul>
</Tab>
<Tab>
Available **inside** the loop only:
<ul className="list-disc space-y-2 pl-6">
<li>
<strong>{"<loop.index>"}</strong>: Current iteration number (0-based)
<strong>loop.currentItem</strong>: Current item being processed
</li>
<li>
<strong>{"<loop.currentItem>"}</strong>: Current item being processed (forEach only)
<strong>loop.index</strong>: Current iteration number (0-based)
</li>
<li>
<strong>{"<loop.items>"}</strong>: Full collection (forEach only)
<strong>loop.items</strong>: Full collection (forEach loops)
</li>
</ul>
</Tab>
<Tab>
<ul className="list-disc space-y-2 pl-6">
<li>
<strong>{"<blockname.results>"}</strong>: Array of all iteration results (accessed via block name)
<strong>loop.results</strong>: Array of all iteration results
</li>
<li>
<strong>Structure</strong>: Results maintain iteration order
</li>
<li>
<strong>Access</strong>: Available in blocks after the loop completes
<strong>Access</strong>: Available in blocks after the loop
</li>
</ul>
</Tab>

View File

@@ -76,44 +76,11 @@ Choose between two types of parallel execution:
3. Drag a single block inside the parallel container
4. Connect the block as needed
### Referencing Parallel Data
### Accessing Results
There's an important distinction between referencing parallel data from **inside** vs **outside** the parallel block:
After a parallel block completes, you can access aggregated results:
<Tabs items={['Inside the Parallel', 'Outside the Parallel']}>
<Tab>
**Inside the parallel**, use `<parallel.>` references to access the current instance context:
- **`<parallel.index>`**: Current instance number (0-based)
- **`<parallel.currentItem>`**: Item for this instance (collection-based only)
- **`<parallel.items>`**: Full collection being distributed (collection-based only)
```
// Inside a Function block within the parallel
const idx = <parallel.index>; // 0, 1, 2, ...
const item = <parallel.currentItem>; // This instance's item
```
<Callout type="info">
These references are only available for blocks **inside** the parallel container. They give you access to the current instance's context.
</Callout>
</Tab>
<Tab>
**Outside the parallel** (after it completes), reference the parallel block by its name to access aggregated results:
- **`<ParallelBlockName.results>`**: Array of results from all instances
```
// If your parallel block is named "Process Tasks"
const allResults = <processtasks.results>;
// Returns: [result1, result2, result3, ...]
```
<Callout type="info">
After the parallel completes, use the parallel's block name (not `parallel.`) to access the collected results. The block name is normalized (lowercase, no spaces).
</Callout>
</Tab>
</Tabs>
- **`<parallel.results>`**: Array of results from all parallel instances
## Example Use Cases
@@ -131,11 +98,11 @@ Parallel (["gpt-4o", "claude-3.7-sonnet", "gemini-2.5-pro"]) → Agent → Evalu
### Result Aggregation
Results from all parallel instances are automatically collected and accessible via the block name:
Results from all parallel instances are automatically collected:
```javascript
// In a Function block after a parallel named "Process Tasks"
const allResults = <processtasks.results>;
// In a Function block after the parallel
const allResults = input.parallel.results;
// Returns: [result1, result2, result3, ...]
```
@@ -191,26 +158,25 @@ Understanding when to use each:
</ul>
</Tab>
<Tab>
Available **inside** the parallel only:
<ul className="list-disc space-y-2 pl-6">
<li>
<strong>{"<parallel.index>"}</strong>: Instance number (0-based)
<strong>parallel.currentItem</strong>: Item for this instance
</li>
<li>
<strong>{"<parallel.currentItem>"}</strong>: Item for this instance (collection-based only)
<strong>parallel.index</strong>: Instance number (0-based)
</li>
<li>
<strong>{"<parallel.items>"}</strong>: Full collection (collection-based only)
<strong>parallel.items</strong>: Full collection (collection-based)
</li>
</ul>
</Tab>
<Tab>
<ul className="list-disc space-y-2 pl-6">
<li>
<strong>{"<blockname.results>"}</strong>: Array of all instance results (accessed via block name)
<strong>parallel.results</strong>: Array of all instance results
</li>
<li>
<strong>Access</strong>: Available in blocks after the parallel completes
<strong>Access</strong>: Available in blocks after the parallel
</li>
</ul>
</Tab>

View File

@@ -5,24 +5,44 @@ title: Copilot
import { Callout } from 'fumadocs-ui/components/callout'
import { Card, Cards } from 'fumadocs-ui/components/card'
import { Image } from '@/components/ui/image'
import { MessageCircle, Hammer, Zap, Globe, Paperclip, History, RotateCcw, Brain } from 'lucide-react'
import { MessageCircle, Package, Zap, Infinity as InfinityIcon, Brain, BrainCircuit } from 'lucide-react'
Copilot is your in-editor assistant that helps you build and edit workflows. It can:
Copilot is your in-editor assistant that helps you build and edit workflows with Sim Copilot, as well as understand and improve them. It can:
- **Explain**: Answer questions about Sim and your current workflow
- **Guide**: Suggest edits and best practices
- **Build**: Add blocks, wire connections, and configure settings
- **Debug**: Analyze execution issues and optimize performance
- **Edit**: Make changes to blocks, connections, and settings when you approve
<Callout type="info">
Copilot is a Sim-managed service. For self-hosted deployments:
Copilot is a Sim-managed service. For self-hosted deployments, generate a Copilot API key in the hosted app (sim.ai → Settings → Copilot)
1. Go to [sim.ai](https://sim.ai) → Settings → Copilot and generate a Copilot API key
2. Set `COPILOT_API_KEY` in your self-hosted environment
2. Set `COPILOT_API_KEY` in your self-hosted environment to that value
</Callout>
## Modes
## Context Menu (@)
Switch between modes using the mode selector at the bottom of the input area.
Use the `@` symbol to reference various resources and give Copilot more context about your workspace:
<Image
src="/static/copilot/copilot-menu.png"
alt="Copilot context menu showing available reference options"
width={600}
height={400}
/>
The `@` menu provides access to:
- **Chats**: Reference previous copilot conversations
- **All workflows**: Reference any workflow in your workspace
- **Workflow Blocks**: Reference specific blocks from workflows
- **Blocks**: Reference block types and templates
- **Knowledge**: Reference your uploaded documents and knowledgebase
- **Docs**: Reference Sim documentation
- **Templates**: Reference workflow templates
- **Logs**: Reference execution logs and results
This contextual information helps Copilot provide more accurate and relevant assistance for your specific use case.
## Modes
<Cards>
<Card
@@ -40,153 +60,113 @@ Switch between modes using the mode selector at the bottom of the input area.
<Card
title={
<span className="inline-flex items-center gap-2">
<Hammer className="h-4 w-4 text-muted-foreground" />
Build
<Package className="h-4 w-4 text-muted-foreground" />
Agent
</span>
}
>
<div className="m-0 text-sm">
Workflow building mode. Copilot can add blocks, wire connections, edit configurations, and debug issues.
Build-and-edit mode. Copilot proposes specific edits (add blocks, wire variables, tweak settings) and applies them when you approve.
</div>
</Card>
</Cards>
## Models
<div className="flex justify-center">
<Image
src="/static/copilot/copilot-mode.png"
alt="Copilot mode selection interface"
width={600}
height={400}
className="my-6"
/>
</div>
Select your preferred AI model using the model selector at the bottom right of the input area.
## Depth Levels
**Available Models:**
- Claude 4.5 Opus, Sonnet (default), Haiku
- GPT 5.2 Codex, Pro
- Gemini 3 Pro
<Cards>
<Card
title={
<span className="inline-flex items-center gap-2">
<Zap className="h-4 w-4 text-muted-foreground" />
Fast
</span>
}
>
<div className="m-0 text-sm">Quickest and cheapest. Best for small edits, simple workflows, and minor tweaks.</div>
</Card>
<Card
title={
<span className="inline-flex items-center gap-2">
<InfinityIcon className="h-4 w-4 text-muted-foreground" />
Auto
</span>
}
>
<div className="m-0 text-sm">Balanced speed and reasoning. Recommended default for most tasks.</div>
</Card>
<Card
title={
<span className="inline-flex items-center gap-2">
<Brain className="h-4 w-4 text-muted-foreground" />
Advanced
</span>
}
>
<div className="m-0 text-sm">More reasoning for larger workflows and complex edits while staying performant.</div>
</Card>
<Card
title={
<span className="inline-flex items-center gap-2">
<BrainCircuit className="h-4 w-4 text-muted-foreground" />
Behemoth
</span>
}
>
<div className="m-0 text-sm">Maximum reasoning for deep planning, debugging, and complex architectural changes.</div>
</Card>
</Cards>
Choose based on your needs: faster models for simple tasks, more capable models for complex workflows.
### Mode Selection Interface
## Context Menu (@)
You can easily switch between different reasoning modes using the mode selector in the Copilot interface:
Use the `@` symbol to reference resources and give Copilot more context:
<Image
src="/static/copilot/copilot-models.png"
alt="Copilot mode selection showing Advanced mode with MAX toggle"
width={600}
height={300}
/>
| Reference | Description |
|-----------|-------------|
| **Chats** | Previous copilot conversations |
| **Workflows** | Any workflow in your workspace |
| **Workflow Blocks** | Blocks in the current workflow |
| **Blocks** | Block types and templates |
| **Knowledge** | Uploaded documents and knowledge bases |
| **Docs** | Sim documentation |
| **Templates** | Workflow templates |
| **Logs** | Execution logs and results |
The interface allows you to:
- **Select reasoning level**: Choose from Fast, Auto, Advanced, or Behemoth
- **Enable MAX mode**: Toggle for maximum reasoning capabilities when you need the most thorough analysis
- **See mode descriptions**: Understand what each mode is optimized for
Type `@` in the input field to open the context menu, then search or browse to find what you need.
Choose your mode based on the complexity of your task - use Fast for simple questions and Behemoth for complex architectural changes.
## Slash Commands (/)
## Billing and Cost Calculation
Use slash commands for quick actions:
### How Costs Are Calculated
| Command | Description |
|---------|-------------|
| `/fast` | Fast mode execution |
| `/research` | Research and exploration mode |
| `/actions` | Execute agent actions |
Copilot usage is billed per token from the underlying LLM:
**Web Commands:**
- **Input tokens**: billed at the provider's base rate (**at-cost**)
- **Output tokens**: billed at **1.5×** the provider's base output rate
| Command | Description |
|---------|-------------|
| `/search` | Search the web |
| `/read` | Read a specific URL |
| `/scrape` | Scrape web page content |
| `/crawl` | Crawl multiple pages |
```javascript
copilotCost = (inputTokens × inputPrice + outputTokens × (outputPrice × 1.5)) / 1,000,000
```
Type `/` in the input field to see available commands.
| Component | Rate Applied |
|----------|----------------------|
| Input | inputPrice |
| Output | outputPrice × 1.5 |
## Chat Management
### Starting a New Chat
Click the **+** button in the Copilot header to start a fresh conversation.
### Chat History
Click **History** to view previous conversations grouped by date. You can:
- Click a chat to resume it
- Delete chats you no longer need
### Editing Messages
Hover over any of your messages and click **Edit** to modify and resend it. This is useful for refining your prompts.
### Message Queue
If you send a message while Copilot is still responding, it gets queued. You can:
- View queued messages in the expandable queue panel
- Send a queued message immediately (aborts current response)
- Remove messages from the queue
## File Attachments
Click the attachment icon to upload files with your message. Supported file types include:
- Images (preview thumbnails shown)
- PDFs
- Text files, JSON, XML
- Other document formats
Files are displayed as clickable thumbnails that open in a new tab.
## Checkpoints & Changes
When Copilot makes changes to your workflow, it saves checkpoints so you can revert if needed.
### Viewing Checkpoints
Hover over a Copilot message and click the checkpoints icon to see saved workflow states for that message.
### Reverting Changes
Click **Revert** on any checkpoint to restore your workflow to that state. A confirmation dialog will warn that this action cannot be undone.
### Accepting Changes
When Copilot proposes changes, you can:
- **Accept**: Apply the proposed changes (`Mod+Shift+Enter`)
- **Reject**: Dismiss the changes and keep your current workflow
## Thinking Blocks
For complex requests, Copilot may show its reasoning process in expandable thinking blocks:
- Blocks auto-expand while Copilot is thinking
- Click to manually expand/collapse
- Shows duration of the thinking process
- Helps you understand how Copilot arrived at its solution
## Options Selection
When Copilot presents multiple options, you can select using:
| Control | Action |
|---------|--------|
| **1-9** | Select option by number |
| **Arrow Up/Down** | Navigate between options |
| **Enter** | Select highlighted option |
Selected options are highlighted; unselected options appear struck through.
## Keyboard Shortcuts
| Shortcut | Action |
|----------|--------|
| `@` | Open context menu |
| `/` | Open slash commands |
| `Arrow Up/Down` | Navigate menu items |
| `Enter` | Select menu item |
| `Esc` | Close menus |
| `Mod+Shift+Enter` | Accept Copilot changes |
## Usage Limits
Copilot usage is billed per token from the underlying LLM. If you reach your usage limit, Copilot will prompt you to increase your limit. You can add usage in increments ($50, $100) from your current base.
<Callout type="warning">
Pricing shown reflects rates as of September 4, 2025. Check provider documentation for current pricing.
</Callout>
<Callout type="info">
See the [Cost Calculation page](/execution/costs) for billing details.
Model prices are per million tokens. The calculation divides by 1,000,000 to get the actual cost. See <a href="/execution/costs">the Cost Calculation page</a> for background and examples.
</Callout>

View File

@@ -34,8 +34,6 @@ Speed up your workflow building with these keyboard shortcuts and mouse controls
| `Mod` + `V` | Paste blocks |
| `Delete` or `Backspace` | Delete selected blocks or edges |
| `Shift` + `L` | Auto-layout canvas |
| `Mod` + `Shift` + `F` | Fit to view |
| `Mod` + `Shift` + `Enter` | Accept Copilot changes |
## Panel Navigation

View File

@@ -16,7 +16,7 @@ MCP servers group your workflow tools together. Create and manage them in worksp
<Video src="mcp/mcp-server.mp4" width={700} height={450} />
</div>
1. Navigate to **Settings → MCP Servers**
1. Navigate to **Settings → Deployed MCPs**
2. Click **Create Server**
3. Enter a name and optional description
4. Copy the server URL for use in your MCP clients
@@ -78,7 +78,7 @@ Include your API key header (`X-API-Key`) for authenticated access when using mc
## Server Management
From the server detail view in **Settings → MCP Servers**, you can:
From the server detail view in **Settings → Deployed MCPs**, you can:
- **View tools**: See all workflows added to a server
- **Copy URL**: Get the server URL for MCP clients

View File

@@ -27,7 +27,7 @@ MCP servers provide collections of tools that your agents can use. Configure the
</div>
1. Navigate to your workspace settings
2. Go to the **MCP Servers** section
2. Go to the **Deployed MCPs** section
3. Click **Add MCP Server**
4. Enter the server configuration details
5. Save the configuration

View File

@@ -3,7 +3,6 @@
"pages": [
"./introduction/index",
"./getting-started/index",
"./quick-reference/index",
"triggers",
"blocks",
"tools",

View File

@@ -1,375 +0,0 @@
---
title: Quick Reference
description: Essential actions for navigating and using the Sim workflow editor
---
import { Callout } from 'fumadocs-ui/components/callout'
import { ActionImage, ActionVideo } from '@/components/ui/action-media'
A quick lookup for everyday actions in the Sim workflow editor. For keyboard shortcuts, see [Keyboard Shortcuts](/keyboard-shortcuts).
<Callout type="info">
**Mod** refers to `Cmd` on macOS and `Ctrl` on Windows/Linux.
</Callout>
## Workspaces
<table>
<thead>
<tr><th>Action</th><th>How</th><th>Preview</th></tr>
</thead>
<tbody>
<tr>
<td>Create a workspace</td>
<td>Click workspace dropdown → **New Workspace**</td>
<td><ActionVideo src="quick-reference/create-workspace.mp4" alt="Create workspace" /></td>
</tr>
<tr>
<td>Switch workspaces</td>
<td>Click workspace dropdown → Select workspace</td>
<td><ActionVideo src="quick-reference/switch-workspace.mp4" alt="Switch workspaces" /></td>
</tr>
<tr>
<td>Invite team members</td>
<td>Sidebar → **Invite**</td>
<td><ActionVideo src="quick-reference/invite.mp4" alt="Invite team members" /></td>
</tr>
<tr>
<td>Rename a workspace</td>
<td>Right-click workspace → **Rename**</td>
<td rowSpan={4}><ActionImage src="/static/quick-reference/workspace-context-menu.png" alt="Workspace context menu" /></td>
</tr>
<tr>
<td>Duplicate a workspace</td>
<td>Right-click workspace → **Duplicate**</td>
</tr>
<tr>
<td>Export a workspace</td>
<td>Right-click workspace → **Export**</td>
</tr>
<tr>
<td>Delete a workspace</td>
<td>Right-click workspace → **Delete**</td>
</tr>
</tbody>
</table>
## Workflows
<table>
<thead>
<tr><th>Action</th><th>How</th><th>Preview</th></tr>
</thead>
<tbody>
<tr>
<td>Create a workflow</td>
<td>Click **+** button in sidebar</td>
<td><ActionImage src="/static/quick-reference/create-workflow.png" alt="Create workflow" /></td>
</tr>
<tr>
<td>Reorder / move workflows</td>
<td>Drag workflow up/down or onto a folder</td>
<td><ActionVideo src="quick-reference/reordering.mp4" alt="Reorder workflows" /></td>
</tr>
<tr>
<td>Import a workflow</td>
<td>Click import button in sidebar → Select file</td>
<td><ActionImage src="/static/quick-reference/import-workflow.png" alt="Import workflow" /></td>
</tr>
<tr>
<td>Multi-select workflows</td>
<td>`Mod+Click` or `Shift+Click` workflows in sidebar</td>
<td><ActionVideo src="quick-reference/multiselect.mp4" alt="Multi-select workflows" /></td>
</tr>
<tr>
<td>Open in new tab</td>
<td>Right-click workflow → **Open in New Tab**</td>
<td rowSpan={6}><ActionImage src="/static/quick-reference/workflow-context-menu.png" alt="Workflow context menu" /></td>
</tr>
<tr>
<td>Rename a workflow</td>
<td>Right-click workflow → **Rename**</td>
</tr>
<tr>
<td>Assign workflow color</td>
<td>Right-click workflow → **Change Color**</td>
</tr>
<tr>
<td>Duplicate a workflow</td>
<td>Right-click workflow → **Duplicate**</td>
</tr>
<tr>
<td>Export a workflow</td>
<td>Right-click workflow → **Export**</td>
</tr>
<tr>
<td>Delete a workflow</td>
<td>Right-click workflow → **Delete**</td>
</tr>
<tr>
<td>Rename a folder</td>
<td>Right-click folder → **Rename**</td>
<td rowSpan={6}><ActionImage src="/static/quick-reference/folder-context-menu.png" alt="Folder context menu" /></td>
</tr>
<tr>
<td>Create workflow in folder</td>
<td>Right-click folder → **Create workflow**</td>
</tr>
<tr>
<td>Create folder in folder</td>
<td>Right-click folder → **Create folder**</td>
</tr>
<tr>
<td>Duplicate a folder</td>
<td>Right-click folder → **Duplicate**</td>
</tr>
<tr>
<td>Export a folder</td>
<td>Right-click folder → **Export**</td>
</tr>
<tr>
<td>Delete a folder</td>
<td>Right-click folder → **Delete**</td>
</tr>
</tbody>
</table>
## Blocks
<table>
<thead>
<tr><th>Action</th><th>How</th><th>Preview</th></tr>
</thead>
<tbody>
<tr>
<td>Add a block</td>
<td>Drag from Toolbar panel, or right-click canvas → **Add Block**</td>
<td><ActionVideo src="quick-reference/add-block.mp4" alt="Add a block" /></td>
</tr>
<tr>
<td>Multi-select blocks</td>
<td>`Mod+Click` additional blocks, or shift-drag to draw selection box</td>
<td><ActionVideo src="quick-reference/multiselect-blocks.mp4" alt="Multi-select blocks" /></td>
</tr>
<tr>
<td>Copy blocks</td>
<td>`Mod+C` with blocks selected</td>
<td rowSpan={2}><ActionVideo src="quick-reference/copy-paste.mp4" alt="Copy and paste blocks" /></td>
</tr>
<tr>
<td>Paste blocks</td>
<td>`Mod+V` to paste copied blocks</td>
</tr>
<tr>
<td>Duplicate blocks</td>
<td>Right-click → **Duplicate**</td>
<td><ActionVideo src="quick-reference/duplicate-block.mp4" alt="Duplicate blocks" /></td>
</tr>
<tr>
<td>Delete blocks</td>
<td>`Delete` or `Backspace` key, or right-click → **Delete**</td>
<td><ActionImage src="/static/quick-reference/delete-block.png" alt="Delete block" /></td>
</tr>
<tr>
<td>Rename a block</td>
<td>Click block name in header, or edit in the Editor panel</td>
<td><ActionVideo src="quick-reference/rename-block.mp4" alt="Rename a block" /></td>
</tr>
<tr>
<td>Enable/Disable a block</td>
<td>Right-click → **Enable/Disable**</td>
<td><ActionImage src="/static/quick-reference/disable-block.png" alt="Disable block" /></td>
</tr>
<tr>
<td>Toggle handle orientation</td>
<td>Right-click → **Toggle Handles**</td>
<td><ActionVideo src="quick-reference/toggle-handles.mp4" alt="Toggle handle orientation" /></td>
</tr>
<tr>
<td>Configure a block</td>
<td>Select block → use Editor panel on right</td>
<td><ActionVideo src="quick-reference/configure-block.mp4" alt="Configure a block" /></td>
</tr>
</tbody>
</table>
## Connections
<table>
<thead>
<tr><th>Action</th><th>How</th><th>Preview</th></tr>
</thead>
<tbody>
<tr>
<td>Create a connection</td>
<td>Drag from output handle to input handle</td>
<td><ActionVideo src="quick-reference/connect-blocks.mp4" alt="Connect blocks" /></td>
</tr>
<tr>
<td>Delete a connection</td>
<td>Click edge to select → `Delete` key</td>
<td><ActionVideo src="quick-reference/delete-connection.mp4" alt="Delete connection" /></td>
</tr>
<tr>
<td>Use output in another block</td>
<td>Drag connection tag into input field</td>
<td><ActionVideo src="quick-reference/connection-tag.mp4" alt="Use connection tag" /></td>
</tr>
</tbody>
</table>
## Panels & Views
<table>
<thead>
<tr><th>Action</th><th>How</th><th>Preview</th></tr>
</thead>
<tbody>
<tr>
<td>Search toolbar</td>
<td>`Mod+F`</td>
<td><ActionVideo src="quick-reference/search-toolbar.mp4" alt="Search toolbar" /></td>
</tr>
<tr>
<td>Search everything</td>
<td>`Mod+K`</td>
<td><ActionImage src="/static/quick-reference/search-everything.png" alt="Search everything" /></td>
</tr>
<tr>
<td>Toggle manual mode</td>
<td>Click toggle button to switch between manual and selector</td>
<td><ActionImage src="/static/quick-reference/toggle-manual-mode.png" alt="Toggle manual mode" /></td>
</tr>
<tr>
<td>Collapse/expand sidebar</td>
<td>Click collapse button on sidebar</td>
<td><ActionVideo src="quick-reference/collapse-sidebar.mp4" alt="Collapse sidebar" /></td>
</tr>
</tbody>
</table>
## Running & Testing
<table>
<thead>
<tr><th>Action</th><th>How</th><th>Preview</th></tr>
</thead>
<tbody>
<tr>
<td>Run workflow</td>
<td>Click Run Workflow button or `Mod+Enter`</td>
<td><ActionImage src="/static/quick-reference/run-workflow.png" alt="Run workflow" /></td>
</tr>
<tr>
<td>Stop workflow</td>
<td>Click Stop button or `Mod+Enter` while running</td>
<td><ActionImage src="/static/quick-reference/stop-workflow.png" alt="Stop workflow" /></td>
</tr>
<tr>
<td>Test with chat</td>
<td>Use Chat panel on the right side</td>
<td><ActionImage src="/static/quick-reference/test-chat.png" alt="Test with chat" /></td>
</tr>
<tr>
<td>Select output to view</td>
<td>Click dropdown in Chat panel → Select block output</td>
<td><ActionImage src="/static/quick-reference/output-select.png" alt="Select output to view" /></td>
</tr>
<tr>
<td>Clear chat history</td>
<td>Click clear button in Chat panel</td>
<td><ActionImage src="/static/quick-reference/clear-chat.png" alt="Clear chat history" /></td>
</tr>
<tr>
<td>View execution logs</td>
<td>Open terminal panel at bottom, or `Mod+L`</td>
<td><ActionImage src="/static/quick-reference/terminal.png" alt="Execution logs terminal" /></td>
</tr>
<tr>
<td>Filter logs by block or status</td>
<td>Click block filter in terminal or right-click log entry → **Filter by Block** or **Filter by Status**</td>
<td><ActionImage src="/static/quick-reference/filter-block.png" alt="Filter logs by block" /></td>
</tr>
<tr>
<td>Search logs</td>
<td>Use search field in terminal or right-click log entry → **Search**</td>
<td><ActionImage src="/static/quick-reference/terminal-search.png" alt="Search logs" /></td>
</tr>
<tr>
<td>Copy log entry</td>
<td>Clipboard Icon or Right-click log entry → **Copy**</td>
<td><ActionImage src="/static/quick-reference/copy-log.png" alt="Copy log entry" /></td>
</tr>
<tr>
<td>Clear terminal</td>
<td>Trash icon or `Mod+D`</td>
<td><ActionImage src="/static/quick-reference/clear-terminal.png" alt="Clear terminal" /></td>
</tr>
</tbody>
</table>
## Deployment
<table>
<thead>
<tr><th>Action</th><th>How</th><th>Preview</th></tr>
</thead>
<tbody>
<tr>
<td>Deploy a workflow</td>
<td>Click **Deploy** button in panel</td>
<td><ActionImage src="/static/quick-reference/deploy.png" alt="Deploy workflow" /></td>
</tr>
<tr>
<td>Update deployment</td>
<td>Click **Update** when changes are detected</td>
<td><ActionImage src="/static/quick-reference/update-deployment.png" alt="Update deployment" /></td>
</tr>
<tr>
<td>View deployment status</td>
<td>Check status indicator (Live/Update/Deploy) in Deploy tab</td>
<td><ActionImage src="/static/quick-reference/view-deployment.png" alt="View deployment status" /></td>
</tr>
<tr>
<td>Revert deployment</td>
<td>Access previous versions in Deploy tab → **Promote to live**</td>
<td><ActionImage src="/static/quick-reference/promote-deployment.png" alt="Promote deployment to live" /></td>
</tr>
<tr>
<td>Copy API endpoint</td>
<td>Deploy tab → API → Copy API cURL</td>
<td><ActionImage src="/static/quick-reference/copy-api.png" alt="Copy API endpoint" /></td>
</tr>
</tbody>
</table>
## Variables
<table>
<thead>
<tr><th>Action</th><th>How</th><th>Preview</th></tr>
</thead>
<tbody>
<tr>
<td>Add / Edit / Delete workflow variable</td>
<td>Panel -> Variables -> **Add Variable**, click to edit, or delete icon</td>
<td><ActionImage src="/static/quick-reference/variables.png" alt="Variables panel" /></td>
</tr>
<tr>
<td>Add environment variable</td>
<td>Settings → **Environment Variables** → **Add**</td>
<td><ActionImage src="/static/quick-reference/add-env-variable.png" alt="Add environment variable" /></td>
</tr>
<tr>
<td>Reference a workflow variable</td>
<td>Use `<blockName.itemName>` syntax in block inputs</td>
<td><ActionImage src="/static/quick-reference/variable-reference.png" alt="Reference workflow variable" /></td>
</tr>
<tr>
<td>Reference an environment variable</td>
<td>Use `{{ENV_VAR}}` syntax in block inputs</td>
<td><ActionImage src="/static/quick-reference/env-variable-reference.png" alt="Reference environment variable" /></td>
</tr>
</tbody>
</table>

View File

@@ -16,20 +16,12 @@ Deploy Sim on your own infrastructure with Docker or Kubernetes.
## Requirements
| Resource | Small | Standard | Production |
|----------|-------|----------|------------|
| CPU | 2 cores | 4 cores | 8+ cores |
| RAM | 12 GB | 16 GB | 32+ GB |
| Storage | 20 GB SSD | 50 GB SSD | 100+ GB SSD |
| Docker | 20.10+ | 20.10+ | Latest |
**Small**: Development, testing, single user (1-5 users)
**Standard**: Teams (5-50 users), moderate workloads
**Production**: Large teams (50+ users), high availability, heavy workflow execution
<Callout type="info">
Resource requirements are driven by workflow execution (isolated-vm sandboxing), file processing (in-memory document parsing), and vector operations (pgvector). Memory is typically the constraining factor rather than CPU. Production telemetry shows the main app uses 4-8 GB average with peaks up to 12 GB under heavy load.
</Callout>
| Resource | Minimum | Recommended |
|----------|---------|-------------|
| CPU | 2 cores | 4+ cores |
| RAM | 12 GB | 16+ GB |
| Storage | 20 GB SSD | 50+ GB SSD |
| Docker | 20.10+ | Latest |
## Quick Start

View File

@@ -47,7 +47,6 @@ Runs a browser automation task using BrowserUse
| `save_browser_data` | boolean | No | Whether to save browser data |
| `model` | string | No | LLM model to use \(default: gpt-4o\) |
| `apiKey` | string | Yes | API key for BrowserUse API |
| `profile_id` | string | No | Browser profile ID for persistent sessions \(cookies, login state\) |
#### Output

View File

@@ -647,42 +647,6 @@ Retrieve a single ticket by ID from Intercom. Returns API-aligned fields only.
| `ticketId` | string | ID of the retrieved ticket |
| `success` | boolean | Operation success status |
### `intercom_update_ticket`
Update a ticket in Intercom (change state, assignment, attributes)
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `ticketId` | string | Yes | The ID of the ticket to update |
| `ticket_attributes` | string | No | JSON object with ticket attributes \(e.g., \{"_default_title_":"New Title","_default_description_":"Updated description"\}\) |
| `open` | boolean | No | Set to false to close the ticket, true to keep it open |
| `is_shared` | boolean | No | Whether the ticket is visible to users |
| `snoozed_until` | number | No | Unix timestamp for when the ticket should reopen |
| `admin_id` | string | No | The ID of the admin performing the update \(needed for workflows and attribution\) |
| `assignee_id` | string | No | The ID of the admin or team to assign the ticket to. Set to "0" to unassign. |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `ticket` | object | The updated ticket object |
| ↳ `id` | string | Unique identifier for the ticket |
| ↳ `type` | string | Object type \(ticket\) |
| ↳ `ticket_id` | string | Ticket ID shown in Intercom UI |
| ↳ `ticket_state` | string | State of the ticket |
| ↳ `ticket_attributes` | object | Attributes of the ticket |
| ↳ `open` | boolean | Whether the ticket is open |
| ↳ `is_shared` | boolean | Whether the ticket is visible to users |
| ↳ `snoozed_until` | number | Unix timestamp when ticket will reopen |
| ↳ `admin_assignee_id` | string | ID of assigned admin |
| ↳ `team_assignee_id` | string | ID of assigned team |
| ↳ `created_at` | number | Unix timestamp when ticket was created |
| ↳ `updated_at` | number | Unix timestamp when ticket was last updated |
| `ticketId` | string | ID of the updated ticket |
| `ticket_state` | string | Current state of the ticket |
### `intercom_create_message`
Create and send a new admin-initiated message in Intercom. Returns API-aligned fields only.
@@ -716,340 +680,4 @@ Create and send a new admin-initiated message in Intercom. Returns API-aligned f
| `messageId` | string | ID of the created message |
| `success` | boolean | Operation success status |
### `intercom_list_admins`
Fetch a list of all admins for the workspace
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `admins` | array | Array of admin objects |
| ↳ `id` | string | Unique identifier for the admin |
| ↳ `type` | string | Object type \(admin\) |
| ↳ `name` | string | Name of the admin |
| ↳ `email` | string | Email of the admin |
| ↳ `job_title` | string | Job title of the admin |
| ↳ `away_mode_enabled` | boolean | Whether admin is in away mode |
| ↳ `away_mode_reassign` | boolean | Whether to reassign conversations when away |
| ↳ `has_inbox_seat` | boolean | Whether admin has a paid inbox seat |
| ↳ `team_ids` | array | List of team IDs the admin belongs to |
| ↳ `avatar` | object | Avatar information |
| ↳ `email_verified` | boolean | Whether email is verified |
| `type` | string | Object type \(admin.list\) |
### `intercom_close_conversation`
Close a conversation in Intercom
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `conversationId` | string | Yes | The ID of the conversation to close |
| `admin_id` | string | Yes | The ID of the admin performing the action |
| `body` | string | No | Optional closing message to add to the conversation |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `conversation` | object | The closed conversation object |
| ↳ `id` | string | Unique identifier for the conversation |
| ↳ `type` | string | Object type \(conversation\) |
| ↳ `state` | string | State of the conversation \(closed\) |
| ↳ `open` | boolean | Whether the conversation is open \(false\) |
| ↳ `read` | boolean | Whether the conversation has been read |
| ↳ `created_at` | number | Unix timestamp when conversation was created |
| ↳ `updated_at` | number | Unix timestamp when conversation was last updated |
| `conversationId` | string | ID of the closed conversation |
| `state` | string | State of the conversation \(closed\) |
### `intercom_open_conversation`
Open a closed or snoozed conversation in Intercom
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `conversationId` | string | Yes | The ID of the conversation to open |
| `admin_id` | string | Yes | The ID of the admin performing the action |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `conversation` | object | The opened conversation object |
| ↳ `id` | string | Unique identifier for the conversation |
| ↳ `type` | string | Object type \(conversation\) |
| ↳ `state` | string | State of the conversation \(open\) |
| ↳ `open` | boolean | Whether the conversation is open \(true\) |
| ↳ `read` | boolean | Whether the conversation has been read |
| ↳ `created_at` | number | Unix timestamp when conversation was created |
| ↳ `updated_at` | number | Unix timestamp when conversation was last updated |
| `conversationId` | string | ID of the opened conversation |
| `state` | string | State of the conversation \(open\) |
### `intercom_snooze_conversation`
Snooze a conversation to reopen at a future time
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `conversationId` | string | Yes | The ID of the conversation to snooze |
| `admin_id` | string | Yes | The ID of the admin performing the action |
| `snoozed_until` | number | Yes | Unix timestamp for when the conversation should reopen |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `conversation` | object | The snoozed conversation object |
| ↳ `id` | string | Unique identifier for the conversation |
| ↳ `type` | string | Object type \(conversation\) |
| ↳ `state` | string | State of the conversation \(snoozed\) |
| ↳ `open` | boolean | Whether the conversation is open |
| ↳ `snoozed_until` | number | Unix timestamp when conversation will reopen |
| ↳ `created_at` | number | Unix timestamp when conversation was created |
| ↳ `updated_at` | number | Unix timestamp when conversation was last updated |
| `conversationId` | string | ID of the snoozed conversation |
| `state` | string | State of the conversation \(snoozed\) |
| `snoozed_until` | number | Unix timestamp when conversation will reopen |
### `intercom_assign_conversation`
Assign a conversation to an admin or team in Intercom
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `conversationId` | string | Yes | The ID of the conversation to assign |
| `admin_id` | string | Yes | The ID of the admin performing the assignment |
| `assignee_id` | string | Yes | The ID of the admin or team to assign the conversation to. Set to "0" to unassign. |
| `body` | string | No | Optional message to add when assigning \(e.g., "Passing to the support team"\) |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `conversation` | object | The assigned conversation object |
| ↳ `id` | string | Unique identifier for the conversation |
| ↳ `type` | string | Object type \(conversation\) |
| ↳ `state` | string | State of the conversation |
| ↳ `open` | boolean | Whether the conversation is open |
| ↳ `admin_assignee_id` | number | ID of the assigned admin |
| ↳ `team_assignee_id` | string | ID of the assigned team |
| ↳ `created_at` | number | Unix timestamp when conversation was created |
| ↳ `updated_at` | number | Unix timestamp when conversation was last updated |
| `conversationId` | string | ID of the assigned conversation |
| `admin_assignee_id` | number | ID of the assigned admin |
| `team_assignee_id` | string | ID of the assigned team |
### `intercom_list_tags`
Fetch a list of all tags in the workspace
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `tags` | array | Array of tag objects |
| ↳ `id` | string | Unique identifier for the tag |
| ↳ `type` | string | Object type \(tag\) |
| ↳ `name` | string | Name of the tag |
| `type` | string | Object type \(list\) |
### `intercom_create_tag`
Create a new tag or update an existing tag name
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `name` | string | Yes | The name of the tag. Will create a new tag if not found, or update the name if id is provided. |
| `id` | string | No | The ID of an existing tag to update. Omit to create a new tag. |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `id` | string | Unique identifier for the tag |
| `name` | string | Name of the tag |
| `type` | string | Object type \(tag\) |
### `intercom_tag_contact`
Add a tag to a specific contact
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `contactId` | string | Yes | The ID of the contact to tag |
| `tagId` | string | Yes | The ID of the tag to apply |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `id` | string | Unique identifier for the tag |
| `name` | string | Name of the tag |
| `type` | string | Object type \(tag\) |
### `intercom_untag_contact`
Remove a tag from a specific contact
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `contactId` | string | Yes | The ID of the contact to untag |
| `tagId` | string | Yes | The ID of the tag to remove |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `id` | string | Unique identifier for the tag that was removed |
| `name` | string | Name of the tag that was removed |
| `type` | string | Object type \(tag\) |
### `intercom_tag_conversation`
Add a tag to a specific conversation
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `conversationId` | string | Yes | The ID of the conversation to tag |
| `tagId` | string | Yes | The ID of the tag to apply |
| `admin_id` | string | Yes | The ID of the admin applying the tag |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `id` | string | Unique identifier for the tag |
| `name` | string | Name of the tag |
| `type` | string | Object type \(tag\) |
### `intercom_create_note`
Add a note to a specific contact
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `contactId` | string | Yes | The ID of the contact to add the note to |
| `body` | string | Yes | The text content of the note |
| `admin_id` | string | No | The ID of the admin creating the note |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `id` | string | Unique identifier for the note |
| `body` | string | The text content of the note |
| `created_at` | number | Unix timestamp when the note was created |
| `type` | string | Object type \(note\) |
| `author` | object | The admin who created the note |
| ↳ `type` | string | Author type \(admin\) |
| ↳ `id` | string | Author ID |
| ↳ `name` | string | Author name |
| ↳ `email` | string | Author email |
| `contact` | object | The contact the note was created for |
| ↳ `type` | string | Contact type |
| ↳ `id` | string | Contact ID |
### `intercom_create_event`
Track a custom event for a contact in Intercom
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `event_name` | string | Yes | The name of the event \(e.g., "order-completed"\). Use past-tense verb-noun format for readability. |
| `created_at` | number | No | Unix timestamp for when the event occurred. Strongly recommended for uniqueness. |
| `user_id` | string | No | Your identifier for the user \(external_id\) |
| `email` | string | No | Email address of the user. Use only if your app uses email to uniquely identify users. |
| `id` | string | No | The Intercom contact ID |
| `metadata` | string | No | JSON object with up to 10 metadata key-value pairs about the event \(e.g., \{"order_value": 99.99\}\) |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `accepted` | boolean | Whether the event was accepted \(202 Accepted\) |
### `intercom_attach_contact_to_company`
Attach a contact to a company in Intercom
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `contactId` | string | Yes | The ID of the contact to attach to the company |
| `companyId` | string | Yes | The ID of the company to attach the contact to |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `company` | object | The company object the contact was attached to |
| ↳ `id` | string | Unique identifier for the company |
| ↳ `type` | string | Object type \(company\) |
| ↳ `company_id` | string | The company_id you defined |
| ↳ `name` | string | Name of the company |
| ↳ `created_at` | number | Unix timestamp when company was created |
| ↳ `updated_at` | number | Unix timestamp when company was updated |
| ↳ `user_count` | number | Number of users in the company |
| ↳ `session_count` | number | Number of sessions |
| ↳ `monthly_spend` | number | Monthly spend amount |
| ↳ `plan` | object | Company plan details |
| `companyId` | string | ID of the company |
| `name` | string | Name of the company |
### `intercom_detach_contact_from_company`
Remove a contact from a company in Intercom
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `contactId` | string | Yes | The ID of the contact to detach from the company |
| `companyId` | string | Yes | The ID of the company to detach the contact from |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `company` | object | The company object the contact was detached from |
| ↳ `id` | string | Unique identifier for the company |
| ↳ `type` | string | Object type \(company\) |
| ↳ `company_id` | string | The company_id you defined |
| ↳ `name` | string | Name of the company |
| `companyId` | string | ID of the company |
| `name` | string | Name of the company |

View File

@@ -6,7 +6,7 @@ description: Access prediction markets and trade on Kalshi
import { BlockInfoCard } from "@/components/ui/block-info-card"
<BlockInfoCard
type="kalshi_v2"
type="kalshi"
color="#09C285"
/>
@@ -36,7 +36,7 @@ Integrate Kalshi prediction markets into the workflow. Can get markets, market,
### `kalshi_get_markets`
Retrieve a list of prediction markets from Kalshi with all filtering options (V2 - full API response)
Retrieve a list of prediction markets from Kalshi with optional filtering
#### Input
@@ -52,12 +52,12 @@ Retrieve a list of prediction markets from Kalshi with all filtering options (V2
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `markets` | array | Array of market objects with all API fields |
| `cursor` | string | Pagination cursor for fetching more results |
| `markets` | array | Array of market objects |
| `paging` | object | Pagination cursor for fetching more results |
### `kalshi_get_market`
Retrieve details of a specific prediction market by ticker (V2 - full API response)
Retrieve details of a specific prediction market by ticker
#### Input
@@ -69,62 +69,11 @@ Retrieve details of a specific prediction market by ticker (V2 - full API respon
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `market` | object | Market object with all API fields |
| ↳ `ticker` | string | Market ticker |
| ↳ `event_ticker` | string | Event ticker |
| ↳ `market_type` | string | Market type |
| ↳ `title` | string | Market title |
| ↳ `subtitle` | string | Market subtitle |
| ↳ `yes_sub_title` | string | Yes outcome subtitle |
| ↳ `no_sub_title` | string | No outcome subtitle |
| ↳ `open_time` | string | Market open time |
| ↳ `close_time` | string | Market close time |
| ↳ `expected_expiration_time` | string | Expected expiration time |
| ↳ `expiration_time` | string | Expiration time |
| ↳ `latest_expiration_time` | string | Latest expiration time |
| ↳ `settlement_timer_seconds` | number | Settlement timer in seconds |
| ↳ `status` | string | Market status |
| ↳ `response_price_units` | string | Response price units |
| ↳ `notional_value` | number | Notional value |
| ↳ `tick_size` | number | Tick size |
| ↳ `yes_bid` | number | Current yes bid price |
| ↳ `yes_ask` | number | Current yes ask price |
| ↳ `no_bid` | number | Current no bid price |
| ↳ `no_ask` | number | Current no ask price |
| ↳ `last_price` | number | Last trade price |
| ↳ `previous_yes_bid` | number | Previous yes bid |
| ↳ `previous_yes_ask` | number | Previous yes ask |
| ↳ `previous_price` | number | Previous price |
| ↳ `volume` | number | Total volume |
| ↳ `volume_24h` | number | 24-hour volume |
| ↳ `liquidity` | number | Market liquidity |
| ↳ `open_interest` | number | Open interest |
| ↳ `result` | string | Market result |
| ↳ `cap_strike` | number | Cap strike |
| ↳ `floor_strike` | number | Floor strike |
| ↳ `can_close_early` | boolean | Can close early |
| ↳ `expiration_value` | string | Expiration value |
| ↳ `category` | string | Market category |
| ↳ `risk_limit_cents` | number | Risk limit in cents |
| ↳ `strike_type` | string | Strike type |
| ↳ `rules_primary` | string | Primary rules |
| ↳ `rules_secondary` | string | Secondary rules |
| ↳ `settlement_source_url` | string | Settlement source URL |
| ↳ `custom_strike` | object | Custom strike object |
| ↳ `underlying` | string | Underlying asset |
| ↳ `settlement_value` | number | Settlement value |
| ↳ `cfd_contract_size` | number | CFD contract size |
| ↳ `yes_fee_fp` | number | Yes fee \(fixed-point\) |
| ↳ `no_fee_fp` | number | No fee \(fixed-point\) |
| ↳ `last_price_fp` | number | Last price \(fixed-point\) |
| ↳ `yes_bid_fp` | number | Yes bid \(fixed-point\) |
| ↳ `yes_ask_fp` | number | Yes ask \(fixed-point\) |
| ↳ `no_bid_fp` | number | No bid \(fixed-point\) |
| ↳ `no_ask_fp` | number | No ask \(fixed-point\) |
| `market` | object | Market object with details |
### `kalshi_get_events`
Retrieve a list of events from Kalshi with optional filtering (V2 - exact API response)
Retrieve a list of events from Kalshi with optional filtering
#### Input
@@ -141,12 +90,11 @@ Retrieve a list of events from Kalshi with optional filtering (V2 - exact API re
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `events` | array | Array of event objects |
| `milestones` | array | Array of milestone objects \(if requested\) |
| `cursor` | string | Pagination cursor for fetching more results |
| `paging` | object | Pagination cursor for fetching more results |
### `kalshi_get_event`
Retrieve details of a specific event by ticker (V2 - exact API response)
Retrieve details of a specific event by ticker
#### Input
@@ -159,23 +107,11 @@ Retrieve details of a specific event by ticker (V2 - exact API response)
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `event` | object | Event object with full details matching Kalshi API response |
| ↳ `event_ticker` | string | Event ticker |
| ↳ `series_ticker` | string | Series ticker |
| ↳ `title` | string | Event title |
| ↳ `sub_title` | string | Event subtitle |
| ↳ `mutually_exclusive` | boolean | Mutually exclusive markets |
| ↳ `category` | string | Event category |
| ↳ `collateral_return_type` | string | Collateral return type |
| ↳ `strike_date` | string | Strike date |
| ↳ `strike_period` | string | Strike period |
| ↳ `available_on_brokers` | boolean | Available on brokers |
| ↳ `product_metadata` | object | Product metadata |
| ↳ `markets` | array | Nested markets \(if requested\) |
| `event` | object | Event object with details |
### `kalshi_get_balance`
Retrieve your account balance and portfolio value from Kalshi (V2 - exact API response)
Retrieve your account balance and portfolio value from Kalshi
#### Input
@@ -189,12 +125,11 @@ Retrieve your account balance and portfolio value from Kalshi (V2 - exact API re
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `balance` | number | Account balance in cents |
| `portfolio_value` | number | Portfolio value in cents |
| `updated_ts` | number | Unix timestamp of last update \(milliseconds\) |
| `portfolioValue` | number | Portfolio value in cents |
### `kalshi_get_positions`
Retrieve your open positions from Kalshi (V2 - exact API response)
Retrieve your open positions from Kalshi
#### Input
@@ -212,13 +147,12 @@ Retrieve your open positions from Kalshi (V2 - exact API response)
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `market_positions` | array | Array of market position objects |
| `event_positions` | array | Array of event position objects |
| `cursor` | string | Pagination cursor for fetching more results |
| `positions` | array | Array of position objects |
| `paging` | object | Pagination cursor for fetching more results |
### `kalshi_get_orders`
Retrieve your orders from Kalshi with optional filtering (V2 with full API response)
Retrieve your orders from Kalshi with optional filtering
#### Input
@@ -236,12 +170,12 @@ Retrieve your orders from Kalshi with optional filtering (V2 with full API respo
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `orders` | array | Array of order objects with full API response fields |
| `cursor` | string | Pagination cursor for fetching more results |
| `orders` | array | Array of order objects |
| `paging` | object | Pagination cursor for fetching more results |
### `kalshi_get_order`
Retrieve details of a specific order by ID from Kalshi (V2 with full API response)
Retrieve details of a specific order by ID from Kalshi
#### Input
@@ -255,44 +189,11 @@ Retrieve details of a specific order by ID from Kalshi (V2 with full API respons
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `order` | object | Order object with full API response fields |
| ↳ `order_id` | string | Order ID |
| ↳ `user_id` | string | User ID |
| ↳ `client_order_id` | string | Client order ID |
| ↳ `ticker` | string | Market ticker |
| ↳ `side` | string | Order side \(yes/no\) |
| ↳ `action` | string | Action \(buy/sell\) |
| ↳ `type` | string | Order type \(limit/market\) |
| ↳ `status` | string | Order status \(resting/canceled/executed\) |
| ↳ `yes_price` | number | Yes price in cents |
| ↳ `no_price` | number | No price in cents |
| ↳ `yes_price_dollars` | string | Yes price in dollars |
| ↳ `no_price_dollars` | string | No price in dollars |
| ↳ `fill_count` | number | Filled contract count |
| ↳ `fill_count_fp` | string | Filled count \(fixed-point\) |
| ↳ `remaining_count` | number | Remaining contracts |
| ↳ `remaining_count_fp` | string | Remaining count \(fixed-point\) |
| ↳ `initial_count` | number | Initial contract count |
| ↳ `initial_count_fp` | string | Initial count \(fixed-point\) |
| ↳ `taker_fees` | number | Taker fees in cents |
| ↳ `maker_fees` | number | Maker fees in cents |
| ↳ `taker_fees_dollars` | string | Taker fees in dollars |
| ↳ `maker_fees_dollars` | string | Maker fees in dollars |
| ↳ `taker_fill_cost` | number | Taker fill cost in cents |
| ↳ `maker_fill_cost` | number | Maker fill cost in cents |
| ↳ `taker_fill_cost_dollars` | string | Taker fill cost in dollars |
| ↳ `maker_fill_cost_dollars` | string | Maker fill cost in dollars |
| ↳ `queue_position` | number | Queue position \(deprecated\) |
| ↳ `expiration_time` | string | Order expiration time |
| ↳ `created_time` | string | Order creation time |
| ↳ `last_update_time` | string | Last update time |
| ↳ `self_trade_prevention_type` | string | Self-trade prevention type |
| ↳ `order_group_id` | string | Order group ID |
| ↳ `cancel_order_on_pause` | boolean | Cancel on market pause |
| `order` | object | Order object with details |
### `kalshi_get_orderbook`
Retrieve the orderbook (yes and no bids) for a specific market (V2 - includes depth and fp fields)
Retrieve the orderbook (yes and no bids) for a specific market
#### Input
@@ -304,18 +205,11 @@ Retrieve the orderbook (yes and no bids) for a specific market (V2 - includes de
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `orderbook` | object | Orderbook with yes/no bids \(legacy integer counts\) |
| ↳ `yes` | array | Yes side bids as tuples \[price_cents, count\] |
| ↳ `no` | array | No side bids as tuples \[price_cents, count\] |
| ↳ `yes_dollars` | array | Yes side bids as tuples \[dollars_string, count\] |
| ↳ `no_dollars` | array | No side bids as tuples \[dollars_string, count\] |
| `orderbook_fp` | object | Orderbook with fixed-point counts \(preferred\) |
| ↳ `yes_dollars` | array | Yes side bids as tuples \[dollars_string, fp_count_string\] |
| ↳ `no_dollars` | array | No side bids as tuples \[dollars_string, fp_count_string\] |
| `orderbook` | object | Orderbook with yes/no bids and asks |
### `kalshi_get_trades`
Retrieve recent trades with additional filtering options (V2 - includes trade_id and count_fp)
Retrieve recent trades across all markets
#### Input
@@ -328,12 +222,12 @@ Retrieve recent trades with additional filtering options (V2 - includes trade_id
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `trades` | array | Array of trade objects with trade_id and count_fp |
| `cursor` | string | Pagination cursor for fetching more results |
| `trades` | array | Array of trade objects |
| `paging` | object | Pagination cursor for fetching more results |
### `kalshi_get_candlesticks`
Retrieve OHLC candlestick data for a specific market (V2 - full API response)
Retrieve OHLC candlestick data for a specific market
#### Input
@@ -349,8 +243,7 @@ Retrieve OHLC candlestick data for a specific market (V2 - full API response)
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `ticker` | string | Market ticker |
| `candlesticks` | array | Array of OHLC candlestick data with nested bid/ask/price objects |
| `candlesticks` | array | Array of OHLC candlestick data |
### `kalshi_get_fills`
@@ -373,12 +266,12 @@ Retrieve your portfolio
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `fills` | array | Array of fill/trade objects with all API fields |
| `cursor` | string | Pagination cursor for fetching more results |
| `fills` | array | Array of fill/trade objects |
| `paging` | object | Pagination cursor for fetching more results |
### `kalshi_get_series_by_ticker`
Retrieve details of a specific market series by ticker (V2 - exact API response)
Retrieve details of a specific market series by ticker
#### Input
@@ -390,25 +283,11 @@ Retrieve details of a specific market series by ticker (V2 - exact API response)
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `series` | object | Series object with full details matching Kalshi API response |
| ↳ `ticker` | string | Series ticker |
| ↳ `title` | string | Series title |
| ↳ `frequency` | string | Event frequency |
| ↳ `category` | string | Series category |
| ↳ `tags` | array | Series tags |
| ↳ `settlement_sources` | array | Settlement sources |
| ↳ `contract_url` | string | Contract URL |
| ↳ `contract_terms_url` | string | Contract terms URL |
| ↳ `fee_type` | string | Fee type |
| ↳ `fee_multiplier` | number | Fee multiplier |
| ↳ `additional_prohibitions` | array | Additional prohibitions |
| ↳ `product_metadata` | object | Product metadata |
| ↳ `volume` | number | Series volume |
| ↳ `volume_fp` | number | Volume \(fixed-point\) |
| `series` | object | Series object with details |
### `kalshi_get_exchange_status`
Retrieve the current status of the Kalshi exchange (V2 - exact API response)
Retrieve the current status of the Kalshi exchange (trading and exchange activity)
#### Input
@@ -419,13 +298,11 @@ Retrieve the current status of the Kalshi exchange (V2 - exact API response)
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `exchange_active` | boolean | Whether the exchange is active |
| `trading_active` | boolean | Whether trading is active |
| `exchange_estimated_resume_time` | string | Estimated time when exchange will resume \(if inactive\) |
| `status` | object | Exchange status with trading_active and exchange_active flags |
### `kalshi_create_order`
Create a new order on a Kalshi prediction market (V2 with full API response)
Create a new order on a Kalshi prediction market
#### Input
@@ -455,44 +332,11 @@ Create a new order on a Kalshi prediction market (V2 with full API response)
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `order` | object | The created order object with full API response fields |
| ↳ `order_id` | string | Order ID |
| ↳ `user_id` | string | User ID |
| ↳ `client_order_id` | string | Client order ID |
| ↳ `ticker` | string | Market ticker |
| ↳ `side` | string | Order side \(yes/no\) |
| ↳ `action` | string | Action \(buy/sell\) |
| ↳ `type` | string | Order type \(limit/market\) |
| ↳ `status` | string | Order status \(resting/canceled/executed\) |
| ↳ `yes_price` | number | Yes price in cents |
| ↳ `no_price` | number | No price in cents |
| ↳ `yes_price_dollars` | string | Yes price in dollars |
| ↳ `no_price_dollars` | string | No price in dollars |
| ↳ `fill_count` | number | Filled contract count |
| ↳ `fill_count_fp` | string | Filled count \(fixed-point\) |
| ↳ `remaining_count` | number | Remaining contracts |
| ↳ `remaining_count_fp` | string | Remaining count \(fixed-point\) |
| ↳ `initial_count` | number | Initial contract count |
| ↳ `initial_count_fp` | string | Initial count \(fixed-point\) |
| ↳ `taker_fees` | number | Taker fees in cents |
| ↳ `maker_fees` | number | Maker fees in cents |
| ↳ `taker_fees_dollars` | string | Taker fees in dollars |
| ↳ `maker_fees_dollars` | string | Maker fees in dollars |
| ↳ `taker_fill_cost` | number | Taker fill cost in cents |
| ↳ `maker_fill_cost` | number | Maker fill cost in cents |
| ↳ `taker_fill_cost_dollars` | string | Taker fill cost in dollars |
| ↳ `maker_fill_cost_dollars` | string | Maker fill cost in dollars |
| ↳ `queue_position` | number | Queue position \(deprecated\) |
| ↳ `expiration_time` | string | Order expiration time |
| ↳ `created_time` | string | Order creation time |
| ↳ `last_update_time` | string | Last update time |
| ↳ `self_trade_prevention_type` | string | Self-trade prevention type |
| ↳ `order_group_id` | string | Order group ID |
| ↳ `cancel_order_on_pause` | boolean | Cancel on market pause |
| `order` | object | The created order object |
### `kalshi_cancel_order`
Cancel an existing order on Kalshi (V2 with full API response)
Cancel an existing order on Kalshi
#### Input
@@ -506,46 +350,12 @@ Cancel an existing order on Kalshi (V2 with full API response)
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `order` | object | The canceled order object with full API response fields |
| ↳ `order_id` | string | Order ID |
| ↳ `user_id` | string | User ID |
| ↳ `client_order_id` | string | Client order ID |
| ↳ `ticker` | string | Market ticker |
| ↳ `side` | string | Order side \(yes/no\) |
| ↳ `action` | string | Action \(buy/sell\) |
| ↳ `type` | string | Order type \(limit/market\) |
| ↳ `status` | string | Order status \(resting/canceled/executed\) |
| ↳ `yes_price` | number | Yes price in cents |
| ↳ `no_price` | number | No price in cents |
| ↳ `yes_price_dollars` | string | Yes price in dollars |
| ↳ `no_price_dollars` | string | No price in dollars |
| ↳ `fill_count` | number | Filled contract count |
| ↳ `fill_count_fp` | string | Filled count \(fixed-point\) |
| ↳ `remaining_count` | number | Remaining contracts |
| ↳ `remaining_count_fp` | string | Remaining count \(fixed-point\) |
| ↳ `initial_count` | number | Initial contract count |
| ↳ `initial_count_fp` | string | Initial count \(fixed-point\) |
| ↳ `taker_fees` | number | Taker fees in cents |
| ↳ `maker_fees` | number | Maker fees in cents |
| ↳ `taker_fees_dollars` | string | Taker fees in dollars |
| ↳ `maker_fees_dollars` | string | Maker fees in dollars |
| ↳ `taker_fill_cost` | number | Taker fill cost in cents |
| ↳ `maker_fill_cost` | number | Maker fill cost in cents |
| ↳ `taker_fill_cost_dollars` | string | Taker fill cost in dollars |
| ↳ `maker_fill_cost_dollars` | string | Maker fill cost in dollars |
| ↳ `queue_position` | number | Queue position \(deprecated\) |
| ↳ `expiration_time` | string | Order expiration time |
| ↳ `created_time` | string | Order creation time |
| ↳ `last_update_time` | string | Last update time |
| ↳ `self_trade_prevention_type` | string | Self-trade prevention type |
| ↳ `order_group_id` | string | Order group ID |
| ↳ `cancel_order_on_pause` | boolean | Cancel on market pause |
| `reduced_by` | number | Number of contracts canceled |
| `reduced_by_fp` | string | Number of contracts canceled in fixed-point format |
| `order` | object | The canceled order object |
| `reducedBy` | number | Number of contracts canceled |
### `kalshi_amend_order`
Modify the price or quantity of an existing order on Kalshi (V2 with full API response)
Modify the price or quantity of an existing order on Kalshi
#### Input
@@ -569,63 +379,6 @@ Modify the price or quantity of an existing order on Kalshi (V2 with full API re
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `old_order` | object | The original order object before amendment |
| ↳ `order_id` | string | Order ID |
| ↳ `user_id` | string | User ID |
| ↳ `ticker` | string | Market ticker |
| ↳ `event_ticker` | string | Event ticker |
| ↳ `status` | string | Order status |
| ↳ `side` | string | Order side \(yes/no\) |
| ↳ `type` | string | Order type \(limit/market\) |
| ↳ `yes_price` | number | Yes price in cents |
| ↳ `no_price` | number | No price in cents |
| ↳ `action` | string | Action \(buy/sell\) |
| ↳ `count` | number | Number of contracts |
| ↳ `remaining_count` | number | Remaining contracts |
| ↳ `created_time` | string | Order creation time |
| ↳ `expiration_time` | string | Order expiration time |
| ↳ `order_group_id` | string | Order group ID |
| ↳ `client_order_id` | string | Client order ID |
| ↳ `place_count` | number | Place count |
| ↳ `decrease_count` | number | Decrease count |
| ↳ `queue_position` | number | Queue position |
| ↳ `maker_fill_count` | number | Maker fill count |
| ↳ `taker_fill_count` | number | Taker fill count |
| ↳ `maker_fees` | number | Maker fees |
| ↳ `taker_fees` | number | Taker fees |
| ↳ `last_update_time` | string | Last update time |
| ↳ `take_profit_order_id` | string | Take profit order ID |
| ↳ `stop_loss_order_id` | string | Stop loss order ID |
| ↳ `amend_count` | number | Amend count |
| ↳ `amend_taker_fill_count` | number | Amend taker fill count |
| `order` | object | The amended order object with full API response fields |
| ↳ `order_id` | string | Order ID |
| ↳ `user_id` | string | User ID |
| ↳ `ticker` | string | Market ticker |
| ↳ `event_ticker` | string | Event ticker |
| ↳ `status` | string | Order status |
| ↳ `side` | string | Order side \(yes/no\) |
| ↳ `type` | string | Order type \(limit/market\) |
| ↳ `yes_price` | number | Yes price in cents |
| ↳ `no_price` | number | No price in cents |
| ↳ `action` | string | Action \(buy/sell\) |
| ↳ `count` | number | Number of contracts |
| ↳ `remaining_count` | number | Remaining contracts |
| ↳ `created_time` | string | Order creation time |
| ↳ `expiration_time` | string | Order expiration time |
| ↳ `order_group_id` | string | Order group ID |
| ↳ `client_order_id` | string | Client order ID |
| ↳ `place_count` | number | Place count |
| ↳ `decrease_count` | number | Decrease count |
| ↳ `queue_position` | number | Queue position |
| ↳ `maker_fill_count` | number | Maker fill count |
| ↳ `taker_fill_count` | number | Taker fill count |
| ↳ `maker_fees` | number | Maker fees |
| ↳ `taker_fees` | number | Taker fees |
| ↳ `last_update_time` | string | Last update time |
| ↳ `take_profit_order_id` | string | Take profit order ID |
| ↳ `stop_loss_order_id` | string | Stop loss order ID |
| ↳ `amend_count` | number | Amend count |
| ↳ `amend_taker_fill_count` | number | Amend taker fill count |
| `order` | object | The amended order object |

View File

@@ -97,12 +97,14 @@
"shopify",
"slack",
"smtp",
"spotify",
"sqs",
"ssh",
"stagehand",
"stripe",
"stt",
"supabase",
"table",
"tavily",
"telegram",
"textract",

View File

@@ -29,7 +29,7 @@ By using these documented API endpoints, you can seamlessly integrate Polymarket
## Usage Instructions
Integrate Polymarket prediction markets into the workflow. Can get markets, market, events, event, tags, series, orderbook, price, midpoint, price history, last trade price, spread, tick size, positions, trades, activity, leaderboard, holders, and search.
Integrate Polymarket prediction markets into the workflow. Can get markets, market, events, event, tags, series, orderbook, price, midpoint, price history, last trade price, spread, tick size, positions, trades, and search.
@@ -43,7 +43,7 @@ Retrieve a list of prediction markets from Polymarket with optional filtering
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `closed` | string | No | Filter by closed status \(true/false\). Use false for open markets only. |
| `closed` | string | No | Filter by closed status \(true/false\). Use false for active markets only. |
| `order` | string | No | Sort field \(e.g., volumeNum, liquidityNum, startDate, endDate, createdAt\) |
| `ascending` | string | No | Sort direction \(true for ascending, false for descending\) |
| `tagId` | string | No | Filter by tag ID |
@@ -55,21 +55,6 @@ Retrieve a list of prediction markets from Polymarket with optional filtering
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `markets` | array | Array of market objects |
| ↳ `id` | string | Market ID |
| ↳ `question` | string | Market question |
| ↳ `conditionId` | string | Condition ID |
| ↳ `slug` | string | Market slug |
| ↳ `endDate` | string | End date |
| ↳ `image` | string | Market image URL |
| ↳ `outcomes` | string | Outcomes JSON string |
| ↳ `outcomePrices` | string | Outcome prices JSON string |
| ↳ `volume` | string | Total volume |
| ↳ `liquidity` | string | Total liquidity |
| ↳ `active` | boolean | Whether market is active |
| ↳ `closed` | boolean | Whether market is closed |
| ↳ `volumeNum` | number | Volume as number |
| ↳ `liquidityNum` | number | Liquidity as number |
| ↳ `clobTokenIds` | array | CLOB token IDs |
### `polymarket_get_market`
@@ -87,28 +72,6 @@ Retrieve details of a specific prediction market by ID or slug
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `market` | object | Market object with details |
| ↳ `id` | string | Market ID |
| ↳ `question` | string | Market question |
| ↳ `conditionId` | string | Condition ID |
| ↳ `slug` | string | Market slug |
| ↳ `resolutionSource` | string | Resolution source |
| ↳ `endDate` | string | End date |
| ↳ `startDate` | string | Start date |
| ↳ `image` | string | Market image URL |
| ↳ `icon` | string | Market icon URL |
| ↳ `description` | string | Market description |
| ↳ `outcomes` | string | Outcomes JSON string |
| ↳ `outcomePrices` | string | Outcome prices JSON string |
| ↳ `volume` | string | Total volume |
| ↳ `liquidity` | string | Total liquidity |
| ↳ `active` | boolean | Whether market is active |
| ↳ `closed` | boolean | Whether market is closed |
| ↳ `archived` | boolean | Whether market is archived |
| ↳ `volumeNum` | number | Volume as number |
| ↳ `liquidityNum` | number | Liquidity as number |
| ↳ `clobTokenIds` | array | CLOB token IDs |
| ↳ `acceptingOrders` | boolean | Whether accepting orders |
| ↳ `negRisk` | boolean | Whether negative risk |
### `polymarket_get_events`
@@ -118,7 +81,7 @@ Retrieve a list of events from Polymarket with optional filtering
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `closed` | string | No | Filter by closed status \(true/false\). Use false for open events only. |
| `closed` | string | No | Filter by closed status \(true/false\). Use false for active events only. |
| `order` | string | No | Sort field \(e.g., volume, liquidity, startDate, endDate, createdAt\) |
| `ascending` | string | No | Sort direction \(true for ascending, false for descending\) |
| `tagId` | string | No | Filter by tag ID |
@@ -130,21 +93,6 @@ Retrieve a list of events from Polymarket with optional filtering
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `events` | array | Array of event objects |
| ↳ `id` | string | Event ID |
| ↳ `ticker` | string | Event ticker |
| ↳ `slug` | string | Event slug |
| ↳ `title` | string | Event title |
| ↳ `description` | string | Event description |
| ↳ `startDate` | string | Start date |
| ↳ `endDate` | string | End date |
| ↳ `image` | string | Event image URL |
| ↳ `icon` | string | Event icon URL |
| ↳ `active` | boolean | Whether event is active |
| ↳ `closed` | boolean | Whether event is closed |
| ↳ `archived` | boolean | Whether event is archived |
| ↳ `liquidity` | number | Total liquidity |
| ↳ `volume` | number | Total volume |
| ↳ `markets` | array | Array of markets in this event |
### `polymarket_get_event`
@@ -162,24 +110,6 @@ Retrieve details of a specific event by ID or slug
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `event` | object | Event object with details |
| ↳ `id` | string | Event ID |
| ↳ `ticker` | string | Event ticker |
| ↳ `slug` | string | Event slug |
| ↳ `title` | string | Event title |
| ↳ `description` | string | Event description |
| ↳ `startDate` | string | Start date |
| ↳ `creationDate` | string | Creation date |
| ↳ `endDate` | string | End date |
| ↳ `image` | string | Event image URL |
| ↳ `icon` | string | Event icon URL |
| ↳ `active` | boolean | Whether event is active |
| ↳ `closed` | boolean | Whether event is closed |
| ↳ `archived` | boolean | Whether event is archived |
| ↳ `liquidity` | number | Total liquidity |
| ↳ `volume` | number | Total volume |
| ↳ `openInterest` | number | Open interest |
| ↳ `commentCount` | number | Comment count |
| ↳ `markets` | array | Array of markets in this event |
### `polymarket_get_tags`
@@ -196,12 +126,7 @@ Retrieve available tags for filtering markets from Polymarket
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `tags` | array | Array of tag objects |
| ↳ `id` | string | Tag ID |
| ↳ `label` | string | Tag label |
| ↳ `slug` | string | Tag slug |
| ↳ `createdAt` | string | Creation timestamp |
| ↳ `updatedAt` | string | Last update timestamp |
| `tags` | array | Array of tag objects with id, label, and slug |
### `polymarket_search`
@@ -213,28 +138,13 @@ Search for markets, events, and profiles on Polymarket
| --------- | ---- | -------- | ----------- |
| `query` | string | Yes | Search query term |
| `limit` | string | No | Number of results per page \(max 50\) |
| `page` | string | No | Page number for pagination \(1-indexed\) |
| `cache` | string | No | Enable caching \(true/false\) |
| `eventsStatus` | string | No | Filter events by status |
| `limitPerType` | string | No | Limit results per type \(markets, events, profiles\) |
| `eventsTag` | string | No | Filter by event tags \(comma-separated\) |
| `sort` | string | No | Sort field |
| `ascending` | string | No | Sort direction \(true for ascending, false for descending\) |
| `searchTags` | string | No | Include tags in search results \(true/false\) |
| `searchProfiles` | string | No | Include profiles in search results \(true/false\) |
| `recurrence` | string | No | Filter by recurrence type |
| `excludeTagId` | string | No | Exclude events with these tag IDs \(comma-separated\) |
| `keepClosedMarkets` | string | No | Include closed markets in results \(0 or 1\) |
| `offset` | string | No | Pagination offset |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `results` | object | Search results containing markets, events, tags, and profiles arrays |
| ↳ `markets` | array | Array of matching market objects |
| ↳ `events` | array | Array of matching event objects |
| ↳ `tags` | array | Array of matching tag objects |
| ↳ `profiles` | array | Array of matching profile objects |
| `results` | object | Search results containing markets, events, and profiles arrays |
### `polymarket_get_series`
@@ -252,21 +162,6 @@ Retrieve series (related market groups) from Polymarket
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `series` | array | Array of series objects |
| ↳ `id` | string | Series ID |
| ↳ `ticker` | string | Series ticker |
| ↳ `slug` | string | Series slug |
| ↳ `title` | string | Series title |
| ↳ `seriesType` | string | Series type |
| ↳ `recurrence` | string | Recurrence pattern |
| ↳ `image` | string | Series image URL |
| ↳ `icon` | string | Series icon URL |
| ↳ `active` | boolean | Whether series is active |
| ↳ `closed` | boolean | Whether series is closed |
| ↳ `archived` | boolean | Whether series is archived |
| ↳ `featured` | boolean | Whether series is featured |
| ↳ `volume` | number | Total volume |
| ↳ `liquidity` | number | Total liquidity |
| ↳ `eventCount` | number | Number of events in series |
### `polymarket_get_series_by_id`
@@ -283,23 +178,6 @@ Retrieve a specific series (related market group) by ID from Polymarket
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `series` | object | Series object with details |
| ↳ `id` | string | Series ID |
| ↳ `ticker` | string | Series ticker |
| ↳ `slug` | string | Series slug |
| ↳ `title` | string | Series title |
| ↳ `seriesType` | string | Series type |
| ↳ `recurrence` | string | Recurrence pattern |
| ↳ `image` | string | Series image URL |
| ↳ `icon` | string | Series icon URL |
| ↳ `active` | boolean | Whether series is active |
| ↳ `closed` | boolean | Whether series is closed |
| ↳ `archived` | boolean | Whether series is archived |
| ↳ `featured` | boolean | Whether series is featured |
| ↳ `volume` | number | Total volume |
| ↳ `liquidity` | number | Total liquidity |
| ↳ `commentCount` | number | Comment count |
| ↳ `eventCount` | number | Number of events in series |
| ↳ `events` | array | Array of events in this series |
### `polymarket_get_orderbook`
@@ -316,21 +194,6 @@ Retrieve the order book summary for a specific token
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `orderbook` | object | Order book with bids and asks arrays |
| ↳ `market` | string | Market identifier |
| ↳ `asset_id` | string | Asset token ID |
| ↳ `hash` | string | Order book hash |
| ↳ `timestamp` | string | Timestamp |
| ↳ `bids` | array | Bid orders |
| ↳ `price` | string | Bid price |
| ↳ `size` | string | Bid size |
| ↳ `price` | string | Ask price |
| ↳ `size` | string | Ask size |
| ↳ `asks` | array | Ask orders |
| ↳ `price` | string | Ask price |
| ↳ `size` | string | Ask size |
| ↳ `min_order_size` | string | Minimum order size |
| ↳ `tick_size` | string | Tick size |
| ↳ `neg_risk` | boolean | Whether negative risk |
### `polymarket_get_price`
@@ -383,9 +246,7 @@ Retrieve historical price data for a specific market token
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `history` | array | Array of price history entries |
| ↳ `t` | number | Unix timestamp |
| ↳ `p` | number | Price at timestamp |
| `history` | array | Array of price history entries with timestamp \(t\) and price \(p\) |
### `polymarket_get_last_trade_price`
@@ -402,7 +263,6 @@ Retrieve the last trade price for a specific token
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `price` | string | Last trade price |
| `side` | string | Side of the last trade \(BUY or SELL\) |
### `polymarket_get_spread`
@@ -418,8 +278,7 @@ Retrieve the bid-ask spread for a specific token
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `spread` | object | Spread value between bid and ask |
| ↳ `spread` | string | The spread value |
| `spread` | object | Bid-ask spread with bid and ask prices |
### `polymarket_get_tick_size`
@@ -446,47 +305,13 @@ Retrieve user positions from Polymarket
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `user` | string | Yes | User wallet address |
| `market` | string | No | Condition IDs to filter positions \(comma-separated, mutually exclusive with eventId\) |
| `eventId` | string | No | Event ID to filter positions \(mutually exclusive with market\) |
| `sizeThreshold` | string | No | Minimum position size threshold \(default: 1\) |
| `redeemable` | string | No | Filter for redeemable positions only \(true/false\) |
| `mergeable` | string | No | Filter for mergeable positions only \(true/false\) |
| `sortBy` | string | No | Sort field \(TOKENS, CURRENT, INITIAL, CASHPNL, PERCENTPNL, TITLE, RESOLVING, PRICE, AVGPRICE\) |
| `sortDirection` | string | No | Sort direction \(ASC or DESC\) |
| `title` | string | No | Search filter by title |
| `limit` | string | No | Number of results per page |
| `offset` | string | No | Pagination offset |
| `market` | string | No | Optional market ID to filter positions |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `positions` | array | Array of position objects |
| ↳ `proxyWallet` | string | Proxy wallet address |
| ↳ `asset` | string | Asset token ID |
| ↳ `conditionId` | string | Condition ID |
| ↳ `size` | number | Position size |
| ↳ `avgPrice` | number | Average price |
| ↳ `initialValue` | number | Initial value |
| ↳ `currentValue` | number | Current value |
| ↳ `cashPnl` | number | Cash profit/loss |
| ↳ `percentPnl` | number | Percent profit/loss |
| ↳ `totalBought` | number | Total bought |
| ↳ `realizedPnl` | number | Realized profit/loss |
| ↳ `percentRealizedPnl` | number | Percent realized profit/loss |
| ↳ `curPrice` | number | Current price |
| ↳ `redeemable` | boolean | Whether position is redeemable |
| ↳ `mergeable` | boolean | Whether position is mergeable |
| ↳ `title` | string | Market title |
| ↳ `slug` | string | Market slug |
| ↳ `icon` | string | Market icon URL |
| ↳ `eventSlug` | string | Event slug |
| ↳ `outcome` | string | Outcome name |
| ↳ `outcomeIndex` | number | Outcome index |
| ↳ `oppositeOutcome` | string | Opposite outcome name |
| ↳ `oppositeAsset` | string | Opposite asset token ID |
| ↳ `endDate` | string | End date |
| ↳ `negativeRisk` | boolean | Whether negative risk |
### `polymarket_get_trades`
@@ -497,13 +322,8 @@ Retrieve trade history from Polymarket
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `user` | string | No | User wallet address to filter trades |
| `market` | string | No | Market/condition ID to filter trades \(mutually exclusive with eventId\) |
| `eventId` | string | No | Event ID to filter trades \(mutually exclusive with market\) |
| `side` | string | No | Trade direction filter \(BUY or SELL\) |
| `takerOnly` | string | No | Filter for taker trades only \(true/false, default: true\) |
| `filterType` | string | No | Filter type \(CASH or TOKENS\) - requires filterAmount |
| `filterAmount` | string | No | Filter amount threshold - requires filterType |
| `limit` | string | No | Number of results per page \(default: 100, max: 10000\) |
| `market` | string | No | Market ID to filter trades |
| `limit` | string | No | Number of results per page \(max 50\) |
| `offset` | string | No | Pagination offset \(skip this many results\) |
#### Output
@@ -511,141 +331,5 @@ Retrieve trade history from Polymarket
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `trades` | array | Array of trade objects |
| ↳ `proxyWallet` | string | Proxy wallet address |
| ↳ `side` | string | Trade side \(BUY or SELL\) |
| ↳ `asset` | string | Asset token ID |
| ↳ `conditionId` | string | Condition ID |
| ↳ `size` | number | Trade size |
| ↳ `price` | number | Trade price |
| ↳ `timestamp` | number | Unix timestamp |
| ↳ `title` | string | Market title |
| ↳ `slug` | string | Market slug |
| ↳ `icon` | string | Market icon URL |
| ↳ `eventSlug` | string | Event slug |
| ↳ `outcome` | string | Outcome name |
| ↳ `outcomeIndex` | number | Outcome index |
| ↳ `name` | string | Trader name |
| ↳ `pseudonym` | string | Trader pseudonym |
| ↳ `bio` | string | Trader bio |
| ↳ `profileImage` | string | Profile image URL |
| ↳ `profileImageOptimized` | string | Optimized profile image URL |
| ↳ `transactionHash` | string | Transaction hash |
### `polymarket_get_activity`
Retrieve on-chain activity for a user including trades, splits, merges, redemptions, rewards, and conversions
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `user` | string | Yes | User wallet address \(0x-prefixed\) |
| `limit` | string | No | Maximum results \(default: 100, max: 500\) |
| `offset` | string | No | Pagination offset \(default: 0, max: 10000\) |
| `market` | string | No | Comma-separated condition IDs \(mutually exclusive with eventId\) |
| `eventId` | string | No | Comma-separated event IDs \(mutually exclusive with market\) |
| `type` | string | No | Activity type filter: TRADE, SPLIT, MERGE, REDEEM, REWARD, CONVERSION, MAKER_REBATE |
| `start` | number | No | Start timestamp \(Unix seconds\) |
| `end` | number | No | End timestamp \(Unix seconds\) |
| `sortBy` | string | No | Sort field: TIMESTAMP, TOKENS, or CASH \(default: TIMESTAMP\) |
| `sortDirection` | string | No | Sort direction: ASC or DESC \(default: DESC\) |
| `side` | string | No | Trade side filter: BUY or SELL \(only applies to trades\) |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `activity` | array | Array of activity entries |
| ↳ `proxyWallet` | string | User proxy wallet address |
| ↳ `timestamp` | number | Unix timestamp of activity |
| ↳ `conditionId` | string | Market condition ID |
| ↳ `type` | string | Activity type \(TRADE, SPLIT, MERGE, REDEEM, REWARD, CONVERSION\) |
| ↳ `size` | number | Size in tokens |
| ↳ `usdcSize` | number | Size in USDC |
| ↳ `transactionHash` | string | Blockchain transaction hash |
| ↳ `price` | number | Price \(for trades\) |
| ↳ `asset` | string | Asset/token ID |
| ↳ `side` | string | Trade side \(BUY/SELL\) |
| ↳ `outcomeIndex` | number | Outcome index |
| ↳ `title` | string | Market title |
| ↳ `slug` | string | Market slug |
| ↳ `icon` | string | Market icon URL |
| ↳ `eventSlug` | string | Event slug |
| ↳ `outcome` | string | Outcome name |
| ↳ `name` | string | User display name |
| ↳ `pseudonym` | string | User pseudonym |
| ↳ `bio` | string | User bio |
| ↳ `profileImage` | string | User profile image URL |
| ↳ `profileImageOptimized` | string | Optimized profile image URL |
### `polymarket_get_leaderboard`
Retrieve trader leaderboard rankings by profit/loss or volume
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `category` | string | No | Category filter: OVERALL, POLITICS, SPORTS, CRYPTO, CULTURE, MENTIONS, WEATHER, ECONOMICS, TECH, FINANCE \(default: OVERALL\) |
| `timePeriod` | string | No | Time period: DAY, WEEK, MONTH, ALL \(default: DAY\) |
| `orderBy` | string | No | Order by: PNL or VOL \(default: PNL\) |
| `limit` | string | No | Number of results \(1-50, default: 25\) |
| `offset` | string | No | Pagination offset \(0-1000, default: 0\) |
| `user` | string | No | Filter by specific user wallet address |
| `userName` | string | No | Filter by username |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `leaderboard` | array | Array of leaderboard entries |
| ↳ `rank` | string | Leaderboard rank position |
| ↳ `proxyWallet` | string | User proxy wallet address |
| ↳ `userName` | string | User display name |
| ↳ `vol` | number | Trading volume |
| ↳ `pnl` | number | Profit and loss |
| ↳ `profileImage` | string | User profile image URL |
| ↳ `xUsername` | string | Twitter/X username |
| ↳ `verifiedBadge` | boolean | Whether user has verified badge |
### `polymarket_get_holders`
Retrieve top holders of a specific market token
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `market` | string | Yes | Comma-separated list of condition IDs |
| `limit` | string | No | Number of holders to return \(0-20, default: 20\) |
| `minBalance` | string | No | Minimum balance threshold \(default: 1\) |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `holders` | array | Array of market holder groups by token |
| ↳ `token` | string | Token/asset ID |
| ↳ `holders` | array | Array of holders for this token |
| ↳ `proxyWallet` | string | Holder wallet address |
| ↳ `bio` | string | Holder bio |
| ↳ `asset` | string | Asset ID |
| ↳ `pseudonym` | string | Holder pseudonym |
| ↳ `amount` | number | Amount held |
| ↳ `displayUsernamePublic` | boolean | Whether username is publicly displayed |
| ↳ `outcomeIndex` | number | Outcome index |
| ↳ `name` | string | Holder display name |
| ↳ `profileImage` | string | Profile image URL |
| ↳ `profileImageOptimized` | string | Optimized profile image URL |
| ↳ `proxyWallet` | string | Holder wallet address |
| ↳ `bio` | string | Holder bio |
| ↳ `asset` | string | Asset ID |
| ↳ `pseudonym` | string | Holder pseudonym |
| ↳ `amount` | number | Amount held |
| ↳ `displayUsernamePublic` | boolean | Whether username is publicly displayed |
| ↳ `outcomeIndex` | number | Outcome index |
| ↳ `name` | string | Holder display name |
| ↳ `profileImage` | string | Profile image URL |
| ↳ `profileImageOptimized` | string | Optimized profile image URL |

File diff suppressed because it is too large Load Diff

View File

@@ -299,7 +299,7 @@ Upload a file to a Supabase storage bucket
| `bucket` | string | Yes | The name of the storage bucket |
| `fileName` | string | Yes | The name of the file \(e.g., "document.pdf", "image.jpg"\) |
| `path` | string | No | Optional folder path \(e.g., "folder/subfolder/"\) |
| `fileData` | json | Yes | File to upload - UserFile object \(basic mode\) or string content \(advanced mode: base64 or plain text\). Supports data URLs. |
| `fileContent` | string | Yes | The file content \(base64 encoded for binary files, or plain text\) |
| `contentType` | string | No | MIME type of the file \(e.g., "image/jpeg", "text/plain"\) |
| `upsert` | boolean | No | If true, overwrites existing file \(default: false\) |
| `apiKey` | string | Yes | Your Supabase service role secret key |
@@ -309,7 +309,7 @@ Upload a file to a Supabase storage bucket
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `message` | string | Operation status message |
| `results` | object | Upload result including file path, bucket, and public URL |
| `results` | object | Upload result including file path and metadata |
### `supabase_storage_download`

View File

@@ -0,0 +1,351 @@
---
title: Table
description: User-defined data tables for storing and querying structured data
---
import { BlockInfoCard } from "@/components/ui/block-info-card"
<BlockInfoCard
type="table"
color="#10B981"
/>
Tables allow you to create and manage custom data tables directly within Sim. Store, query, and manipulate structured data within your workflows without needing external database integrations.
**Why Use Tables?**
- **No external setup**: Create tables instantly without configuring external databases
- **Workflow-native**: Data persists across workflow executions and is accessible from any workflow in your workspace
- **Flexible schema**: Define columns with types (string, number, boolean, date, json) and constraints (required, unique)
- **Powerful querying**: Filter, sort, and paginate data using MongoDB-style operators
- **Agent-friendly**: Tables can be used as tools by AI agents for dynamic data storage and retrieval
**Key Features:**
- Create tables with custom schemas
- Insert, update, upsert, and delete rows
- Query with filters and sorting
- Batch operations for bulk inserts
- Bulk updates and deletes by filter
- Up to 10,000 rows per table, 100 tables per workspace
## Creating Tables
Tables are created from the **Tables** section in the sidebar. Each table requires:
- **Name**: Alphanumeric with underscores (e.g., `customer_leads`)
- **Description**: Optional description of the table's purpose
- **Schema**: Define columns with name, type, and optional constraints
### Column Types
| Type | Description | Example Values |
|------|-------------|----------------|
| `string` | Text data | `"John Doe"`, `"active"` |
| `number` | Numeric data | `42`, `99.99` |
| `boolean` | True/false values | `true`, `false` |
| `date` | Date/time values | `"2024-01-15T10:30:00Z"` |
| `json` | Complex nested data | `{"address": {"city": "NYC"}}` |
### Column Constraints
- **Required**: Column must have a value (cannot be null)
- **Unique**: Values must be unique across all rows (enables upsert matching)
## Usage Instructions
Create and manage custom data tables. Store, query, and manipulate structured data within workflows.
## Tools
### `table_query_rows`
Query rows from a table with filtering, sorting, and pagination
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `tableId` | string | Yes | Table ID |
| `filter` | object | No | Filter conditions using MongoDB-style operators |
| `sort` | object | No | Sort order as \{column: "asc"\|"desc"\} |
| `limit` | number | No | Maximum rows to return \(default: 100, max: 1000\) |
| `offset` | number | No | Number of rows to skip \(default: 0\) |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `success` | boolean | Whether query succeeded |
| `rows` | array | Query result rows |
| `rowCount` | number | Number of rows returned |
| `totalCount` | number | Total rows matching filter |
| `limit` | number | Limit used in query |
| `offset` | number | Offset used in query |
### `table_insert_row`
Insert a new row into a table
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `tableId` | string | Yes | Table ID |
| `data` | object | Yes | Row data as JSON object matching the table schema |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `success` | boolean | Whether row was inserted |
| `row` | object | Inserted row data including generated ID |
| `message` | string | Status message |
### `table_upsert_row`
Insert or update a row based on unique column constraints. If a row with matching unique field exists, update it; otherwise insert a new row.
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `tableId` | string | Yes | Table ID |
| `data` | object | Yes | Row data to insert or update |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `success` | boolean | Whether row was upserted |
| `row` | object | Upserted row data |
| `operation` | string | Operation performed: "insert" or "update" |
| `message` | string | Status message |
### `table_batch_insert_rows`
Insert multiple rows at once (up to 1000 rows per batch)
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `tableId` | string | Yes | Table ID |
| `rows` | array | Yes | Array of row data objects to insert |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `success` | boolean | Whether batch insert succeeded |
| `rows` | array | Array of inserted rows with IDs |
| `insertedCount` | number | Number of rows inserted |
| `message` | string | Status message |
### `table_update_row`
Update a specific row by its ID
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `tableId` | string | Yes | Table ID |
| `rowId` | string | Yes | Row ID to update |
| `data` | object | Yes | Data to update \(partial update supported\) |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `success` | boolean | Whether row was updated |
| `row` | object | Updated row data |
| `message` | string | Status message |
### `table_update_rows_by_filter`
Update multiple rows matching a filter condition
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `tableId` | string | Yes | Table ID |
| `filter` | object | Yes | Filter to match rows for update |
| `data` | object | Yes | Data to apply to matching rows |
| `limit` | number | No | Maximum rows to update \(default: 1000\) |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `success` | boolean | Whether update succeeded |
| `updatedCount` | number | Number of rows updated |
| `updatedRowIds` | array | IDs of updated rows |
| `message` | string | Status message |
### `table_delete_row`
Delete a specific row by its ID
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `tableId` | string | Yes | Table ID |
| `rowId` | string | Yes | Row ID to delete |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `success` | boolean | Whether row was deleted |
| `deletedCount` | number | Number of rows deleted \(1 or 0\) |
| `message` | string | Status message |
### `table_delete_rows_by_filter`
Delete multiple rows matching a filter condition
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `tableId` | string | Yes | Table ID |
| `filter` | object | Yes | Filter to match rows for deletion |
| `limit` | number | No | Maximum rows to delete \(default: 1000\) |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `success` | boolean | Whether delete succeeded |
| `deletedCount` | number | Number of rows deleted |
| `deletedRowIds` | array | IDs of deleted rows |
| `message` | string | Status message |
### `table_get_row`
Get a single row by its ID
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `tableId` | string | Yes | Table ID |
| `rowId` | string | Yes | Row ID to retrieve |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `success` | boolean | Whether row was found |
| `row` | object | Row data |
| `message` | string | Status message |
### `table_get_schema`
Get the schema definition for a table
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `tableId` | string | Yes | Table ID |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `success` | boolean | Whether schema was retrieved |
| `name` | string | Table name |
| `columns` | array | Array of column definitions |
| `message` | string | Status message |
## Filter Operators
Filters use MongoDB-style operators for flexible querying:
| Operator | Description | Example |
|----------|-------------|---------|
| `$eq` | Equals | `{"status": {"$eq": "active"}}` or `{"status": "active"}` |
| `$ne` | Not equals | `{"status": {"$ne": "deleted"}}` |
| `$gt` | Greater than | `{"age": {"$gt": 18}}` |
| `$gte` | Greater than or equal | `{"score": {"$gte": 80}}` |
| `$lt` | Less than | `{"price": {"$lt": 100}}` |
| `$lte` | Less than or equal | `{"quantity": {"$lte": 10}}` |
| `$in` | In array | `{"status": {"$in": ["active", "pending"]}}` |
| `$nin` | Not in array | `{"type": {"$nin": ["spam", "blocked"]}}` |
| `$contains` | String contains | `{"email": {"$contains": "@gmail.com"}}` |
### Combining Filters
Multiple field conditions are combined with AND logic:
```json
{
"status": "active",
"age": {"$gte": 18}
}
```
Use `$or` for OR logic:
```json
{
"$or": [
{"status": "active"},
{"status": "pending"}
]
}
```
## Sort Specification
Specify sort order with column names and direction:
```json
{
"createdAt": "desc"
}
```
Multi-column sorting:
```json
{
"priority": "desc",
"name": "asc"
}
```
## Built-in Columns
Every row automatically includes:
| Column | Type | Description |
|--------|------|-------------|
| `id` | string | Unique row identifier |
| `createdAt` | date | When the row was created |
| `updatedAt` | date | When the row was last modified |
These can be used in filters and sorting.
## Limits
| Resource | Limit |
|----------|-------|
| Tables per workspace | 100 |
| Rows per table | 10,000 |
| Columns per table | 50 |
| Max row size | 100KB |
| String value length | 10,000 characters |
| Query limit | 1,000 rows |
| Batch insert size | 1,000 rows |
| Bulk update/delete | 1,000 rows |
## Notes
- Category: `blocks`
- Type: `table`
- Tables are scoped to workspaces and accessible from any workflow within that workspace
- Data persists across workflow executions
- Use unique constraints to enable upsert functionality
- The visual filter/sort builder provides an easy way to construct queries without writing JSON

View File

@@ -17,7 +17,7 @@ Los servidores MCP agrupan tus herramientas de flujo de trabajo. Créalos y gest
<Video src="mcp/mcp-server.mp4" width={700} height={450} />
</div>
1. Navega a **Configuración → Servidores MCP**
1. Navega a **Configuración → MCP implementados**
2. Haz clic en **Crear servidor**
3. Introduce un nombre y una descripción opcional
4. Copia la URL del servidor para usarla en tus clientes MCP
@@ -79,7 +79,7 @@ Incluye tu encabezado de clave API (`X-API-Key`) para acceso autenticado al usar
## Gestión del servidor
Desde la vista de detalles del servidor en **Configuración → Servidores MCP**, puedes:
Desde la vista de detalles del servidor en **Configuración → MCP implementados**, puedes:
- **Ver herramientas**: consulta todos los flujos de trabajo añadidos a un servidor
- **Copiar URL**: obtén la URL del servidor para clientes MCP

View File

@@ -27,7 +27,7 @@ Los servidores MCP proporcionan colecciones de herramientas que tus agentes pued
</div>
1. Navega a la configuración de tu espacio de trabajo
2. Ve a la sección **Servidores MCP**
2. Ve a la sección **MCP implementados**
3. Haz clic en **Añadir servidor MCP**
4. Introduce los detalles de configuración del servidor
5. Guarda la configuración

View File

@@ -10,20 +10,12 @@ Despliega Sim en tu propia infraestructura con Docker o Kubernetes.
## Requisitos
| Recurso | Pequeño | Estándar | Producción |
|----------|---------|----------|------------|
| CPU | 2 núcleos | 4 núcleos | 8+ núcleos |
| RAM | 12 GB | 16 GB | 32+ GB |
| Almacenamiento | 20 GB SSD | 50 GB SSD | 100+ GB SSD |
| Docker | 20.10+ | 20.10+ | Última versión |
**Pequeño**: Desarrollo, pruebas, usuario único (1-5 usuarios)
**Estándar**: Equipos (5-50 usuarios), cargas de trabajo moderadas
**Producción**: Equipos grandes (50+ usuarios), alta disponibilidad, ejecución intensiva de workflows
<Callout type="info">
Los requisitos de recursos están determinados por la ejecución de workflows (sandboxing isolated-vm), procesamiento de archivos (análisis de documentos en memoria) y operaciones vectoriales (pgvector). La memoria suele ser el factor limitante, no la CPU. La telemetría de producción muestra que la aplicación principal usa 4-8 GB en promedio con picos de hasta 12 GB bajo carga pesada.
</Callout>
| Recurso | Mínimo | Recomendado |
|----------|---------|-------------|
| CPU | 2 núcleos | 4+ núcleos |
| RAM | 12 GB | 16+ GB |
| Almacenamiento | 20 GB SSD | 50+ GB SSD |
| Docker | 20.10+ | Última versión |
## Inicio rápido

View File

@@ -17,7 +17,7 @@ Les serveurs MCP regroupent vos outils de workflow. Créez-les et gérez-les dan
<Video src="mcp/mcp-server.mp4" width={700} height={450} />
</div>
1. Accédez à **Paramètres → Serveurs MCP**
1. Accédez à **Paramètres → MCP déployés**
2. Cliquez sur **Créer un serveur**
3. Saisissez un nom et une description facultative
4. Copiez l'URL du serveur pour l'utiliser dans vos clients MCP
@@ -79,7 +79,7 @@ Incluez votre en-tête de clé API (`X-API-Key`) pour un accès authentifié lor
## Gestion du serveur
Depuis la vue détaillée du serveur dans **Paramètres → Serveurs MCP**, vous pouvez :
Depuis la vue détaillée du serveur dans **Paramètres → MCP déployés**, vous pouvez :
- **Voir les outils** : voir tous les workflows ajoutés à un serveur
- **Copier l'URL** : obtenir l'URL du serveur pour les clients MCP

View File

@@ -28,7 +28,7 @@ Les serveurs MCP fournissent des collections d'outils que vos agents peuvent uti
</div>
1. Accédez aux paramètres de votre espace de travail
2. Allez dans la section **Serveurs MCP**
2. Allez dans la section **MCP déployés**
3. Cliquez sur **Ajouter un serveur MCP**
4. Saisissez les détails de configuration du serveur
5. Enregistrez la configuration

View File

@@ -10,20 +10,12 @@ Déployez Sim sur votre propre infrastructure avec Docker ou Kubernetes.
## Prérequis
| Ressource | Petit | Standard | Production |
|----------|-------|----------|------------|
| CPU | 2 cœurs | 4 cœurs | 8+ cœurs |
| RAM | 12 Go | 16 Go | 32+ Go |
| Stockage | 20 Go SSD | 50 Go SSD | 100+ Go SSD |
| Docker | 20.10+ | 20.10+ | Dernière version |
**Petit** : Développement, tests, utilisateur unique (1-5 utilisateurs)
**Standard** : Équipes (5-50 utilisateurs), charges de travail modérées
**Production** : Grandes équipes (50+ utilisateurs), haute disponibilité, exécution intensive de workflows
<Callout type="info">
Les besoins en ressources sont déterminés par l'exécution des workflows (sandboxing isolated-vm), le traitement des fichiers (analyse de documents en mémoire) et les opérations vectorielles (pgvector). La mémoire est généralement le facteur limitant, pas le CPU. La télémétrie de production montre que l'application principale utilise 4-8 Go en moyenne avec des pics jusqu'à 12 Go sous forte charge.
</Callout>
| Ressource | Minimum | Recommandé |
|----------|---------|-------------|
| CPU | 2 cœurs | 4+ cœurs |
| RAM | 12 Go | 16+ Go |
| Stockage | 20 Go SSD | 50+ Go SSD |
| Docker | 20.10+ | Dernière version |
## Démarrage rapide

View File

@@ -16,7 +16,7 @@ MCPサーバーは、ワークフローツールをまとめてグループ化
<Video src="mcp/mcp-server.mp4" width={700} height={450} />
</div>
1. **設定 → MCP サーバー**に移動します
1. **設定 → デプロイ済みMCP**に移動します
2. **サーバーを作成**をクリックします
3. 名前とオプションの説明を入力します
4. MCPクライアントで使用するためにサーバーURLをコピーします
@@ -78,7 +78,7 @@ mcp-remoteまたは他のHTTPベースのMCPトランスポートを使用する
## サーバー管理
**設定 → MCP サーバー**のサーバー詳細ビューから、次のことができます:
**設定 → デプロイ済みMCP**のサーバー詳細ビューから、次のことができます:
- **ツールを表示**: サーバーに追加されたすべてのワークフローを確認
- **URLをコピー**: MCPクライアント用のサーバーURLを取得

View File

@@ -27,7 +27,7 @@ MCPサーバーはエージェントが使用できるツールのコレクシ
</div>
1. ワークスペース設定に移動します
2. **MCP サーバー**セクションに移動します
2. **デプロイ済みMCP**セクションに移動します
3. **MCPサーバーを追加**をクリックします
4. サーバー設定の詳細を入力します
5. 設定を保存します

View File

@@ -10,20 +10,12 @@ DockerまたはKubernetesを使用して、自社のインフラストラクチ
## 要件
| リソース | スモール | スタンダード | プロダクション |
|----------|---------|-------------|----------------|
| CPU | 2コア | 4コア | 8+コア |
| RAM | 12 GB | 16 GB | 32+ GB |
| ストレージ | 20 GB SSD | 50 GB SSD | 100+ GB SSD |
| Docker | 20.10+ | 20.10+ | 最新版 |
**スモール**: 開発、テスト、シングルユーザー1-5ユーザー
**スタンダード**: チーム5-50ユーザー、中程度のワークロード
**プロダクション**: 大規模チーム50+ユーザー)、高可用性、高負荷ワークフロー実行
<Callout type="info">
リソース要件は、ワークフロー実行isolated-vmサンドボックス、ファイル処理メモリ内ドキュメント解析、ベクトル演算pgvectorによって決まります。CPUよりもメモリが制約要因となることが多いです。本番環境のテレメトリによると、メインアプリは平均4-8 GB、高負荷時は最大12 GBを使用します。
</Callout>
| リソース | 最小 | 推奨 |
|----------|---------|-------------|
| CPU | 2コア | 4+コア |
| RAM | 12 GB | 16+ GB |
| ストレージ | 20 GB SSD | 50+ GB SSD |
| Docker | 20.10+ | 最新版 |
## クイックスタート

View File

@@ -16,7 +16,7 @@ MCP 服务器用于将您的工作流工具进行分组。您可以在工作区
<Video src="mcp/mcp-server.mp4" width={700} height={450} />
</div>
1. 进入 **设置 → MCP 服务器**
1. 进入 **设置 → 已部署的 MCPs**
2. 点击 **创建服务器**
3. 输入名称和可选描述
4. 复制服务器 URL 以在你的 MCP 客户端中使用
@@ -78,7 +78,7 @@ MCP 服务器用于将您的工作流工具进行分组。您可以在工作区
## 服务器管理
在 **设置 → MCP 服务器** 的服务器详情页,你可以:
在 **设置 → 已部署的 MCPs** 的服务器详情页,你可以:
- **查看工具**:查看添加到服务器的所有工作流
- **复制 URL**:获取 MCP 客户端的服务器 URL

View File

@@ -27,7 +27,7 @@ MCP 服务器提供工具集合,供您的代理使用。您可以在工作区
</div>
1. 进入您的工作区设置
2. 前往 **MCP Servers** 部分
2. 前往 **Deployed MCPs** 部分
3. 点击 **Add MCP Server**
4. 输入服务器配置信息
5. 保存配置

View File

@@ -10,20 +10,12 @@ import { Callout } from 'fumadocs-ui/components/callout'
## 要求
| 资源 | 小型 | 标准 | 生产环境 |
|----------|------|------|----------|
| CPU | 2 核 | 4 核 | 8+ 核 |
| 内存 | 12 GB | 16 GB | 32+ GB |
| 存储 | 20 GB SSD | 50 GB SSD | 100+ GB SSD |
| Docker | 20.10+ | 20.10+ | 最新版本 |
**小型**: 开发、测试、单用户1-5 用户)
**标准**: 团队5-50 用户)、中等工作负载
**生产环境**: 大型团队50+ 用户)、高可用性、密集工作流执行
<Callout type="info">
资源需求由工作流执行isolated-vm 沙箱、文件处理内存中文档解析和向量运算pgvector决定。内存通常是限制因素而不是 CPU。生产遥测数据显示主应用平均使用 4-8 GB高负载时峰值可达 12 GB。
</Callout>
| 资源 | 最低要求 | 推荐配置 |
|----------|---------|-------------|
| CPU | 2 核 | 4 核及以上 |
| 内存 | 12 GB | 16 GB 及以上 |
| 存储 | 20 GB SSD | 50 GB 及以上 SSD |
| Docker | 20.10+ | 最新版本 |
## 快速开始

Binary file not shown.

Before

Width:  |  Height:  |  Size: 104 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 45 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 114 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 44 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 66 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 48 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 49 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 78 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 82 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 146 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 60 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 90 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 103 KiB

View File

@@ -2,9 +2,10 @@
import { useEffect, useState } from 'react'
import { createLogger } from '@sim/logger'
import { Eye, EyeOff } from 'lucide-react'
import { ArrowRight, ChevronRight, Eye, EyeOff } from 'lucide-react'
import Link from 'next/link'
import { useRouter, useSearchParams } from 'next/navigation'
import { Button } from '@/components/ui/button'
import {
Dialog,
DialogContent,
@@ -21,7 +22,6 @@ import { getBaseUrl } from '@/lib/core/utils/urls'
import { quickValidateEmail } from '@/lib/messaging/email/validation'
import { inter } from '@/app/_styles/fonts/inter/inter'
import { soehne } from '@/app/_styles/fonts/soehne/soehne'
import { BrandedButton } from '@/app/(auth)/components/branded-button'
import { SocialLoginButtons } from '@/app/(auth)/components/social-login-buttons'
import { SSOLoginButton } from '@/app/(auth)/components/sso-login-button'
import { useBrandedButtonClass } from '@/hooks/use-branded-button-class'
@@ -107,6 +107,7 @@ export default function LoginPage({
const [passwordErrors, setPasswordErrors] = useState<string[]>([])
const [showValidationError, setShowValidationError] = useState(false)
const buttonClass = useBrandedButtonClass()
const [isButtonHovered, setIsButtonHovered] = useState(false)
const [callbackUrl, setCallbackUrl] = useState('/workspace')
const [isInviteFlow, setIsInviteFlow] = useState(false)
@@ -114,6 +115,7 @@ export default function LoginPage({
const [forgotPasswordOpen, setForgotPasswordOpen] = useState(false)
const [forgotPasswordEmail, setForgotPasswordEmail] = useState('')
const [isSubmittingReset, setIsSubmittingReset] = useState(false)
const [isResetButtonHovered, setIsResetButtonHovered] = useState(false)
const [resetStatus, setResetStatus] = useState<{
type: 'success' | 'error' | null
message: string
@@ -182,13 +184,6 @@ export default function LoginPage({
e.preventDefault()
setIsLoading(true)
const redirectToVerify = (emailToVerify: string) => {
if (typeof window !== 'undefined') {
sessionStorage.setItem('verificationEmail', emailToVerify)
}
router.push('/verify')
}
const formData = new FormData(e.currentTarget)
const emailRaw = formData.get('email') as string
const email = emailRaw.trim().toLowerCase()
@@ -220,9 +215,9 @@ export default function LoginPage({
onError: (ctx) => {
logger.error('Login error:', ctx.error)
// EMAIL_NOT_VERIFIED is handled by the catch block which redirects to /verify
if (ctx.error.code?.includes('EMAIL_NOT_VERIFIED')) {
errorHandled = true
redirectToVerify(email)
return
}
@@ -290,7 +285,10 @@ export default function LoginPage({
router.push(safeCallbackUrl)
} catch (err: any) {
if (err.message?.includes('not verified') || err.code?.includes('EMAIL_NOT_VERIFIED')) {
redirectToVerify(email)
if (typeof window !== 'undefined') {
sessionStorage.setItem('verificationEmail', email)
}
router.push('/verify')
return
}
@@ -493,14 +491,24 @@ export default function LoginPage({
</div>
</div>
<BrandedButton
<Button
type='submit'
onMouseEnter={() => setIsButtonHovered(true)}
onMouseLeave={() => setIsButtonHovered(false)}
className='group inline-flex w-full items-center justify-center gap-2 rounded-[10px] border border-[#6F3DFA] bg-gradient-to-b from-[#8357FF] to-[#6F3DFA] py-[6px] pr-[10px] pl-[12px] text-[15px] text-white shadow-[inset_0_2px_4px_0_#9B77FF] transition-all'
disabled={isLoading}
loading={isLoading}
loadingText='Signing in'
>
Sign in
</BrandedButton>
<span className='flex items-center gap-1'>
{isLoading ? 'Signing in...' : 'Sign in'}
<span className='inline-flex transition-transform duration-200 group-hover:translate-x-0.5'>
{isButtonHovered ? (
<ArrowRight className='h-4 w-4' aria-hidden='true' />
) : (
<ChevronRight className='h-4 w-4' aria-hidden='true' />
)}
</span>
</span>
</Button>
</form>
)}
@@ -611,15 +619,25 @@ export default function LoginPage({
<p>{resetStatus.message}</p>
</div>
)}
<BrandedButton
<Button
type='button'
onClick={handleForgotPassword}
onMouseEnter={() => setIsResetButtonHovered(true)}
onMouseLeave={() => setIsResetButtonHovered(false)}
className='group inline-flex w-full items-center justify-center gap-2 rounded-[10px] border border-[#6F3DFA] bg-gradient-to-b from-[#8357FF] to-[#6F3DFA] py-[6px] pr-[10px] pl-[12px] text-[15px] text-white shadow-[inset_0_2px_4px_0_#9B77FF] transition-all'
disabled={isSubmittingReset}
loading={isSubmittingReset}
loadingText='Sending'
>
Send Reset Link
</BrandedButton>
<span className='flex items-center gap-1'>
{isSubmittingReset ? 'Sending...' : 'Send Reset Link'}
<span className='inline-flex transition-transform duration-200 group-hover:translate-x-0.5'>
{isResetButtonHovered ? (
<ArrowRight className='h-4 w-4' aria-hidden='true' />
) : (
<ChevronRight className='h-4 w-4' aria-hidden='true' />
)}
</span>
</span>
</Button>
</div>
</DialogContent>
</Dialog>

View File

@@ -1,12 +1,13 @@
'use client'
import { useState } from 'react'
import { Eye, EyeOff } from 'lucide-react'
import { ArrowRight, ChevronRight, Eye, EyeOff } from 'lucide-react'
import { Button } from '@/components/ui/button'
import { Input } from '@/components/ui/input'
import { Label } from '@/components/ui/label'
import { cn } from '@/lib/core/utils/cn'
import { inter } from '@/app/_styles/fonts/inter/inter'
import { BrandedButton } from '@/app/(auth)/components/branded-button'
import { useBrandedButtonClass } from '@/hooks/use-branded-button-class'
interface RequestResetFormProps {
email: string
@@ -27,6 +28,9 @@ export function RequestResetForm({
statusMessage,
className,
}: RequestResetFormProps) {
const buttonClass = useBrandedButtonClass()
const [isButtonHovered, setIsButtonHovered] = useState(false)
const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault()
onSubmit(email)
@@ -64,14 +68,24 @@ export function RequestResetForm({
)}
</div>
<BrandedButton
<Button
type='submit'
disabled={isSubmitting}
loading={isSubmitting}
loadingText='Sending'
onMouseEnter={() => setIsButtonHovered(true)}
onMouseLeave={() => setIsButtonHovered(false)}
className='group inline-flex w-full items-center justify-center gap-2 rounded-[10px] border border-[#6F3DFA] bg-gradient-to-b from-[#8357FF] to-[#6F3DFA] py-[6px] pr-[10px] pl-[12px] text-[15px] text-white shadow-[inset_0_2px_4px_0_#9B77FF] transition-all'
>
Send Reset Link
</BrandedButton>
<span className='flex items-center gap-1'>
{isSubmitting ? 'Sending...' : 'Send Reset Link'}
<span className='inline-flex transition-transform duration-200 group-hover:translate-x-0.5'>
{isButtonHovered ? (
<ArrowRight className='h-4 w-4' aria-hidden='true' />
) : (
<ChevronRight className='h-4 w-4' aria-hidden='true' />
)}
</span>
</span>
</Button>
</form>
)
}
@@ -98,6 +112,8 @@ export function SetNewPasswordForm({
const [validationMessage, setValidationMessage] = useState('')
const [showPassword, setShowPassword] = useState(false)
const [showConfirmPassword, setShowConfirmPassword] = useState(false)
const buttonClass = useBrandedButtonClass()
const [isButtonHovered, setIsButtonHovered] = useState(false)
const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault()
@@ -227,14 +243,24 @@ export function SetNewPasswordForm({
)}
</div>
<BrandedButton
type='submit'
<Button
disabled={isSubmitting || !token}
loading={isSubmitting}
loadingText='Resetting'
type='submit'
onMouseEnter={() => setIsButtonHovered(true)}
onMouseLeave={() => setIsButtonHovered(false)}
className='group inline-flex w-full items-center justify-center gap-2 rounded-[10px] border border-[#6F3DFA] bg-gradient-to-b from-[#8357FF] to-[#6F3DFA] py-[6px] pr-[10px] pl-[12px] text-[15px] text-white shadow-[inset_0_2px_4px_0_#9B77FF] transition-all'
>
Reset Password
</BrandedButton>
<span className='flex items-center gap-1'>
{isSubmitting ? 'Resetting...' : 'Reset Password'}
<span className='inline-flex transition-transform duration-200 group-hover:translate-x-0.5'>
{isButtonHovered ? (
<ArrowRight className='h-4 w-4' aria-hidden='true' />
) : (
<ChevronRight className='h-4 w-4' aria-hidden='true' />
)}
</span>
</span>
</Button>
</form>
)
}

View File

@@ -2,9 +2,10 @@
import { Suspense, useEffect, useState } from 'react'
import { createLogger } from '@sim/logger'
import { Eye, EyeOff } from 'lucide-react'
import { ArrowRight, ChevronRight, Eye, EyeOff } from 'lucide-react'
import Link from 'next/link'
import { useRouter, useSearchParams } from 'next/navigation'
import { Button } from '@/components/ui/button'
import { Input } from '@/components/ui/input'
import { Label } from '@/components/ui/label'
import { client, useSession } from '@/lib/auth/auth-client'
@@ -13,7 +14,6 @@ import { cn } from '@/lib/core/utils/cn'
import { quickValidateEmail } from '@/lib/messaging/email/validation'
import { inter } from '@/app/_styles/fonts/inter/inter'
import { soehne } from '@/app/_styles/fonts/soehne/soehne'
import { BrandedButton } from '@/app/(auth)/components/branded-button'
import { SocialLoginButtons } from '@/app/(auth)/components/social-login-buttons'
import { SSOLoginButton } from '@/app/(auth)/components/sso-login-button'
import { useBrandedButtonClass } from '@/hooks/use-branded-button-class'
@@ -97,6 +97,7 @@ function SignupFormContent({
const [redirectUrl, setRedirectUrl] = useState('')
const [isInviteFlow, setIsInviteFlow] = useState(false)
const buttonClass = useBrandedButtonClass()
const [isButtonHovered, setIsButtonHovered] = useState(false)
const [name, setName] = useState('')
const [nameErrors, setNameErrors] = useState<string[]>([])
@@ -475,14 +476,24 @@ function SignupFormContent({
</div>
</div>
<BrandedButton
<Button
type='submit'
onMouseEnter={() => setIsButtonHovered(true)}
onMouseLeave={() => setIsButtonHovered(false)}
className='group inline-flex w-full items-center justify-center gap-2 rounded-[10px] border border-[#6F3DFA] bg-gradient-to-b from-[#8357FF] to-[#6F3DFA] py-[6px] pr-[10px] pl-[12px] text-[15px] text-white shadow-[inset_0_2px_4px_0_#9B77FF] transition-all'
disabled={isLoading}
loading={isLoading}
loadingText='Creating account'
>
Create account
</BrandedButton>
<span className='flex items-center gap-1'>
{isLoading ? 'Creating account' : 'Create account'}
<span className='inline-flex transition-transform duration-200 group-hover:translate-x-0.5'>
{isButtonHovered ? (
<ArrowRight className='h-4 w-4' aria-hidden='true' />
) : (
<ChevronRight className='h-4 w-4' aria-hidden='true' />
)}
</span>
</span>
</Button>
</form>
)}

View File

@@ -4,6 +4,7 @@ import { useRef, useState } from 'react'
import { createLogger } from '@sim/logger'
import { X } from 'lucide-react'
import { Textarea } from '@/components/emcn'
import { Button } from '@/components/ui/button'
import { Input } from '@/components/ui/input'
import { Label } from '@/components/ui/label'
import {
@@ -17,7 +18,6 @@ import { isHosted } from '@/lib/core/config/feature-flags'
import { cn } from '@/lib/core/utils/cn'
import { quickValidateEmail } from '@/lib/messaging/email/validation'
import { soehne } from '@/app/_styles/fonts/soehne/soehne'
import { BrandedButton } from '@/app/(auth)/components/branded-button'
import Footer from '@/app/(landing)/components/footer/footer'
import Nav from '@/app/(landing)/components/nav/nav'
@@ -493,17 +493,18 @@ export default function CareersPage() {
{/* Submit Button */}
<div className='flex justify-end pt-2'>
<BrandedButton
<Button
type='submit'
disabled={isSubmitting || submitStatus === 'success'}
loading={isSubmitting}
loadingText='Submitting'
showArrow={false}
fullWidth={false}
className='min-w-[200px]'
className='min-w-[200px] rounded-[10px] border border-[#6F3DFA] bg-gradient-to-b from-[#8357FF] to-[#6F3DFA] text-white shadow-[inset_0_2px_4px_0_#9B77FF] transition-all duration-300 hover:opacity-90 disabled:opacity-50'
size='lg'
>
{submitStatus === 'success' ? 'Submitted' : 'Submit Application'}
</BrandedButton>
{isSubmitting
? 'Submitting...'
: submitStatus === 'success'
? 'Submitted'
: 'Submit Application'}
</Button>
</div>
</form>
</section>

View File

@@ -59,7 +59,7 @@ export default function StatusIndicator() {
href={statusUrl}
target='_blank'
rel='noopener noreferrer'
className={`flex min-w-[165px] items-center gap-[6px] whitespace-nowrap text-[12px] transition-colors ${STATUS_COLORS[status]}`}
className={`flex items-center gap-[6px] whitespace-nowrap text-[12px] transition-colors ${STATUS_COLORS[status]}`}
aria-label={`System status: ${message}`}
>
<StatusDotIcon status={status} className='h-[6px] w-[6px]' aria-hidden='true' />

View File

@@ -10,8 +10,8 @@ export { LandingLoopNode } from './landing-canvas/landing-block/landing-loop-nod
export { LandingNode } from './landing-canvas/landing-block/landing-node'
export type { LoopBlockProps } from './landing-canvas/landing-block/loop-block'
export { LoopBlock } from './landing-canvas/landing-block/loop-block'
export type { SubBlockRowProps, TagProps } from './landing-canvas/landing-block/tag'
export { SubBlockRow, Tag } from './landing-canvas/landing-block/tag'
export type { TagProps } from './landing-canvas/landing-block/tag'
export { Tag } from './landing-canvas/landing-block/tag'
export type {
LandingBlockNode,
LandingCanvasProps,

View File

@@ -1,12 +1,12 @@
import React from 'react'
import { BookIcon } from 'lucide-react'
import {
SubBlockRow,
type SubBlockRowProps,
Tag,
type TagProps,
} from '@/app/(landing)/components/hero/components/landing-canvas/landing-block/tag'
/**
* Data structure for a landing card component
* Matches the workflow block structure from the application
*/
export interface LandingCardData {
/** Icon element to display in the card header */
@@ -15,8 +15,8 @@ export interface LandingCardData {
color: string | '#f6f6f6'
/** Name/title of the card */
name: string
/** Optional subblock rows to display below the header */
tags?: SubBlockRowProps[]
/** Optional tags to display at the bottom of the card */
tags?: TagProps[]
}
/**
@@ -28,8 +28,7 @@ export interface LandingBlockProps extends LandingCardData {
}
/**
* Landing block component that displays a card with icon, name, and optional subblock rows
* Styled to match the application's workflow blocks
* Landing block component that displays a card with icon, name, and optional tags
* @param props - Component properties including icon, color, name, tags, and className
* @returns A styled block card component
*/
@@ -40,37 +39,33 @@ export const LandingBlock = React.memo(function LandingBlock({
tags,
className,
}: LandingBlockProps) {
const hasContentBelowHeader = tags && tags.length > 0
return (
<div
className={`z-10 flex w-[250px] flex-col rounded-[8px] border border-[#E5E5E5] bg-white ${className ?? ''}`}
className={`z-10 flex w-64 flex-col items-start gap-3 rounded-[14px] border border-[#E5E5E5] bg-[#FEFEFE] p-3 ${className ?? ''}`}
style={{
boxShadow: '0 1px 2px 0 rgba(0, 0, 0, 0.05)',
}}
>
{/* Header - matches workflow-block.tsx header styling */}
<div
className={`flex items-center justify-between p-[8px] ${hasContentBelowHeader ? 'border-[#E5E5E5] border-b' : ''}`}
>
<div className='flex min-w-0 flex-1 items-center gap-[10px]'>
<div className='flex w-full items-center justify-between'>
<div className='flex items-center gap-2.5'>
<div
className='flex h-[24px] w-[24px] flex-shrink-0 items-center justify-center rounded-[6px]'
style={{ background: color as string }}
className='flex h-6 w-6 items-center justify-center rounded-[8px] text-white'
style={{ backgroundColor: color as string }}
>
{icon}
</div>
<span className='truncate font-medium text-[#171717] text-[16px]' title={name}>
{name}
</span>
<p className='text-base text-card-foreground'>{name}</p>
</div>
<BookIcon className='h-4 w-4 text-muted-foreground' />
</div>
{/* Content - SubBlock Rows matching workflow-block.tsx */}
{hasContentBelowHeader && (
<div className='flex flex-col gap-[8px] p-[8px]'>
{tags && tags.length > 0 ? (
<div className='flex flex-wrap gap-2'>
{tags.map((tag) => (
<SubBlockRow key={tag.label} icon={tag.icon} label={tag.label} />
<Tag key={tag.label} icon={tag.icon} label={tag.label} />
))}
</div>
)}
) : null}
</div>
)
})

View File

@@ -7,14 +7,9 @@ import {
type LandingCardData,
} from '@/app/(landing)/components/hero/components/landing-canvas/landing-block/landing-block'
/**
* Handle Y offset from block top - matches HANDLE_POSITIONS.DEFAULT_Y_OFFSET
*/
const HANDLE_Y_OFFSET = 20
/**
* React Flow node component for the landing canvas
* Styled to match the application's workflow blocks
* Includes CSS animations and connection handles
* @param props - Component properties containing node data
* @returns A React Flow compatible node component
*/
@@ -46,15 +41,15 @@ export const LandingNode = React.memo(function LandingNode({ data }: { data: Lan
type='target'
position={Position.Left}
style={{
width: '7px',
height: '20px',
background: '#D1D1D1',
border: 'none',
borderRadius: '2px 0 0 2px',
top: `${HANDLE_Y_OFFSET}px`,
left: '-7px',
width: '12px',
height: '12px',
background: '#FEFEFE',
border: '1px solid #E5E5E5',
borderRadius: '50%',
top: '50%',
left: '-20px',
transform: 'translateY(-50%)',
zIndex: 10,
zIndex: 2,
}}
isConnectable={false}
/>
@@ -64,15 +59,15 @@ export const LandingNode = React.memo(function LandingNode({ data }: { data: Lan
type='source'
position={Position.Right}
style={{
width: '7px',
height: '20px',
background: '#D1D1D1',
border: 'none',
borderRadius: '0 2px 2px 0',
top: `${HANDLE_Y_OFFSET}px`,
right: '-7px',
width: '12px',
height: '12px',
background: '#FEFEFE',
border: '1px solid #E5E5E5',
borderRadius: '50%',
top: '50%',
right: '-20px',
transform: 'translateY(-50%)',
zIndex: 10,
zIndex: 2,
}}
isConnectable={false}
/>

View File

@@ -15,7 +15,6 @@ export interface LoopBlockProps {
/**
* Loop block container component that provides a styled container
* for grouping related elements with a dashed border
* Styled to match the application's subflow containers
* @param props - Component properties including children and styling
* @returns A styled loop container component
*/
@@ -30,33 +29,33 @@ export const LoopBlock = React.memo(function LoopBlock({
style={{
width: '1198px',
height: '528px',
borderRadius: '8px',
background: 'rgba(59, 130, 246, 0.08)',
borderRadius: '14px',
background: 'rgba(59, 130, 246, 0.10)',
position: 'relative',
...style,
}}
>
{/* Custom dashed border with SVG - 8px border radius to match blocks */}
{/* Custom dashed border with SVG */}
<svg
className='pointer-events-none absolute inset-0 h-full w-full'
style={{ borderRadius: '8px' }}
style={{ borderRadius: '14px' }}
preserveAspectRatio='none'
>
<path
className='landing-loop-animated-dash'
d='M 1190 527.5
L 8 527.5
A 7.5 7.5 0 0 1 0.5 520
L 0.5 8
A 7.5 7.5 0 0 1 8 0.5
L 1190 0.5
A 7.5 7.5 0 0 1 1197.5 8
L 1197.5 520
A 7.5 7.5 0 0 1 1190 527.5 Z'
d='M 1183.5 527.5
L 14 527.5
A 13.5 13.5 0 0 1 0.5 514
L 0.5 14
A 13.5 13.5 0 0 1 14 0.5
L 1183.5 0.5
A 13.5 13.5 0 0 1 1197 14
L 1197 514
A 13.5 13.5 0 0 1 1183.5 527.5 Z'
fill='none'
stroke='#3B82F6'
strokeWidth='1'
strokeDasharray='8 8'
strokeDasharray='12 12'
strokeLinecap='round'
/>
</svg>

View File

@@ -1,52 +1,25 @@
import React from 'react'
/**
* Properties for a subblock row component
* Matches the SubBlockRow pattern from workflow-block.tsx
* Properties for a tag component
*/
export interface SubBlockRowProps {
/** Icon element to display (optional, for visual context) */
icon?: React.ReactNode
/** Text label for the row title */
export interface TagProps {
/** Icon element to display in the tag */
icon: React.ReactNode
/** Text label for the tag */
label: string
/** Optional value to display on the right side */
value?: string
}
/**
* Kept for backwards compatibility
* Tag component for displaying labeled icons in a compact format
* @param props - Tag properties including icon and label
* @returns A styled tag component
*/
export type TagProps = SubBlockRowProps
/**
* SubBlockRow component matching the workflow block's subblock row style
* @param props - Row properties including label and optional value
* @returns A styled row component
*/
export const SubBlockRow = React.memo(function SubBlockRow({ label, value }: SubBlockRowProps) {
// Split label by colon to separate title and value if present
const [title, displayValue] = label.includes(':')
? label.split(':').map((s) => s.trim())
: [label, value]
export const Tag = React.memo(function Tag({ icon, label }: TagProps) {
return (
<div className='flex items-center gap-[8px]'>
<span className='min-w-0 truncate text-[#888888] text-[14px] capitalize' title={title}>
{title}
</span>
{displayValue && (
<span
className='flex-1 truncate text-right text-[#171717] text-[14px]'
title={displayValue}
>
{displayValue}
</span>
)}
<div className='flex w-fit items-center gap-1 rounded-[8px] border border-gray-300 bg-white px-2 py-0.5'>
<div className='h-3 w-3 text-muted-foreground'>{icon}</div>
<p className='text-muted-foreground text-xs leading-normal'>{label}</p>
</div>
)
})
/**
* Tag component - alias for SubBlockRow for backwards compatibility
*/
export const Tag = SubBlockRow

View File

@@ -9,10 +9,9 @@ import { LandingFlow } from '@/app/(landing)/components/hero/components/landing-
/**
* Visual constants for landing node dimensions
* Matches BLOCK_DIMENSIONS from the application
*/
export const CARD_WIDTH = 250
export const CARD_HEIGHT = 100
export const CARD_WIDTH = 256
export const CARD_HEIGHT = 92
/**
* Landing block node with positioning information

View File

@@ -4,29 +4,33 @@ import React from 'react'
import { type EdgeProps, getSmoothStepPath, Position } from 'reactflow'
/**
* Custom edge component with animated dashed line
* Styled to match the application's workflow edges with rectangular handles
* Custom edge component with animated dotted line that floats between handles
* @param props - React Flow edge properties
* @returns An animated dashed edge component
* @returns An animated dotted edge component
*/
export const LandingEdge = React.memo(function LandingEdge(props: EdgeProps) {
const { id, sourceX, sourceY, targetX, targetY, sourcePosition, targetPosition, style } = props
const { id, sourceX, sourceY, targetX, targetY, sourcePosition, targetPosition, style, data } =
props
// Adjust the connection points to connect flush with rectangular handles
// Handle width is 7px, positioned at -7px from edge
// Adjust the connection points to create floating effect
// Account for handle size (12px) and additional spacing
const handleRadius = 6 // Half of handle width (12px)
const floatingGap = 1 // Additional gap for floating effect
// Calculate adjusted positions based on edge direction
let adjustedSourceX = sourceX
let adjustedTargetX = targetX
if (sourcePosition === Position.Right) {
adjustedSourceX = sourceX + 1
adjustedSourceX = sourceX + handleRadius + floatingGap
} else if (sourcePosition === Position.Left) {
adjustedSourceX = sourceX - 1
adjustedSourceX = sourceX - handleRadius - floatingGap
}
if (targetPosition === Position.Left) {
adjustedTargetX = targetX - 1
adjustedTargetX = targetX - handleRadius - floatingGap
} else if (targetPosition === Position.Right) {
adjustedTargetX = targetX + 1
adjustedTargetX = targetX + handleRadius + floatingGap
}
const [path] = getSmoothStepPath({
@@ -36,8 +40,8 @@ export const LandingEdge = React.memo(function LandingEdge(props: EdgeProps) {
targetY,
sourcePosition,
targetPosition,
borderRadius: 8,
offset: 16,
borderRadius: 20,
offset: 10,
})
return (

View File

@@ -1,7 +1,16 @@
'use client'
import React from 'react'
import { ArrowUp, CodeIcon } from 'lucide-react'
import {
ArrowUp,
BinaryIcon,
BookIcon,
CalendarIcon,
CodeIcon,
Globe2Icon,
MessageSquareIcon,
VariableIcon,
} from 'lucide-react'
import { useRouter } from 'next/navigation'
import { type Edge, type Node, Position } from 'reactflow'
import {
@@ -14,6 +23,7 @@ import {
JiraIcon,
LinearIcon,
NotionIcon,
OpenAIIcon,
OutlookIcon,
PackageSearchIcon,
PineconeIcon,
@@ -55,56 +65,67 @@ const SERVICE_TEMPLATES = {
/**
* Landing blocks for the canvas preview
* Styled to match the application's workflow blocks with subblock rows
*/
const LANDING_BLOCKS: LandingManualBlock[] = [
{
id: 'schedule',
name: 'Schedule',
color: '#7B68EE',
icon: <ScheduleIcon className='h-[16px] w-[16px] text-white' />,
icon: <ScheduleIcon className='h-4 w-4' />,
positions: {
mobile: { x: 8, y: 60 },
tablet: { x: 40, y: 120 },
desktop: { x: 60, y: 180 },
},
tags: [{ label: 'Time: 09:00AM Daily' }, { label: 'Timezone: PST' }],
tags: [
{ icon: <CalendarIcon className='h-3 w-3' />, label: '09:00AM Daily' },
{ icon: <Globe2Icon className='h-3 w-3' />, label: 'PST' },
],
},
{
id: 'knowledge',
name: 'Knowledge',
color: '#00B0B0',
icon: <PackageSearchIcon className='h-[16px] w-[16px] text-white' />,
icon: <PackageSearchIcon className='h-4 w-4' />,
positions: {
mobile: { x: 120, y: 140 },
tablet: { x: 220, y: 200 },
desktop: { x: 420, y: 241 },
},
tags: [{ label: 'Source: Product Vector DB' }, { label: 'Limit: 10' }],
tags: [
{ icon: <BookIcon className='h-3 w-3' />, label: 'Product Vector DB' },
{ icon: <BinaryIcon className='h-3 w-3' />, label: 'Limit: 10' },
],
},
{
id: 'agent',
name: 'Agent',
color: '#802FFF',
icon: <AgentIcon className='h-[16px] w-[16px] text-white' />,
icon: <AgentIcon className='h-4 w-4' />,
positions: {
mobile: { x: 340, y: 60 },
tablet: { x: 540, y: 120 },
desktop: { x: 880, y: 142 },
},
tags: [{ label: 'Model: gpt-5' }, { label: 'Prompt: You are a support ag...' }],
tags: [
{ icon: <OpenAIIcon className='h-3 w-3' />, label: 'gpt-5' },
{ icon: <MessageSquareIcon className='h-3 w-3' />, label: 'You are a support ag...' },
],
},
{
id: 'function',
name: 'Function',
color: '#FF402F',
icon: <CodeIcon className='h-[16px] w-[16px] text-white' />,
icon: <CodeIcon className='h-4 w-4' />,
positions: {
mobile: { x: 480, y: 220 },
tablet: { x: 740, y: 280 },
desktop: { x: 880, y: 340 },
},
tags: [{ label: 'Language: Python' }, { label: 'Code: time = "2025-09-01...' }],
tags: [
{ icon: <CodeIcon className='h-3 w-3' />, label: 'Python' },
{ icon: <VariableIcon className='h-3 w-3' />, label: 'time = "2025-09-01...' },
],
},
]

View File

@@ -229,7 +229,7 @@ function PricingCard({
*/
export default function LandingPricing() {
return (
<section id='pricing' className='px-4 pt-[23px] sm:px-0 sm:pt-[4px]' aria-label='Pricing plans'>
<section id='pricing' className='px-4 pt-[19px] sm:px-0 sm:pt-0' aria-label='Pricing plans'>
<h2 className='sr-only'>Pricing Plans</h2>
<div className='relative mx-auto w-full max-w-[1289px]'>
<div className='grid grid-cols-1 gap-4 sm:grid-cols-2 sm:gap-0 lg:grid-cols-4'>

View File

@@ -11,7 +11,6 @@ import { useBrandConfig } from '@/lib/branding/branding'
import { isHosted } from '@/lib/core/config/feature-flags'
import { soehne } from '@/app/_styles/fonts/soehne/soehne'
import { getFormattedGitHubStars } from '@/app/(landing)/actions/github'
import { useBrandedButtonClass } from '@/hooks/use-branded-button-class'
const logger = createLogger('nav')
@@ -21,12 +20,11 @@ interface NavProps {
}
export default function Nav({ hideAuthButtons = false, variant = 'landing' }: NavProps = {}) {
const [githubStars, setGithubStars] = useState('26.1k')
const [githubStars, setGithubStars] = useState('25.1k')
const [isHovered, setIsHovered] = useState(false)
const [isLoginHovered, setIsLoginHovered] = useState(false)
const router = useRouter()
const brand = useBrandConfig()
const buttonClass = useBrandedButtonClass()
useEffect(() => {
if (variant !== 'landing') return
@@ -185,7 +183,7 @@ export default function Nav({ hideAuthButtons = false, variant = 'landing' }: Na
href='/signup'
onMouseEnter={() => setIsHovered(true)}
onMouseLeave={() => setIsHovered(false)}
className={`${buttonClass} group inline-flex items-center justify-center gap-2 rounded-[10px] py-[6px] pr-[10px] pl-[12px] text-[15px] text-white transition-all`}
className='group inline-flex items-center justify-center gap-2 rounded-[10px] border border-[#6F3DFA] bg-gradient-to-b from-[#8357FF] to-[#6F3DFA] py-[6px] pr-[10px] pl-[12px] text-[14px] text-white shadow-[inset_0_2px_4px_0_#9B77FF] transition-all sm:text-[16px]'
aria-label='Get started with Sim - Sign up for free'
prefetch={true}
>

View File

@@ -1,27 +0,0 @@
'use client'
import { useState } from 'react'
import { ArrowLeft, ChevronLeft } from 'lucide-react'
import Link from 'next/link'
export function BackLink() {
const [isHovered, setIsHovered] = useState(false)
return (
<Link
href='/studio'
className='group flex items-center gap-1 text-gray-600 text-sm hover:text-gray-900'
onMouseEnter={() => setIsHovered(true)}
onMouseLeave={() => setIsHovered(false)}
>
<span className='group-hover:-translate-x-0.5 inline-flex transition-transform duration-200'>
{isHovered ? (
<ArrowLeft className='h-4 w-4' aria-hidden='true' />
) : (
<ChevronLeft className='h-4 w-4' aria-hidden='true' />
)}
</span>
Back to Sim Studio
</Link>
)
}

View File

@@ -5,10 +5,7 @@ import { Avatar, AvatarFallback, AvatarImage } from '@/components/emcn'
import { FAQ } from '@/lib/blog/faq'
import { getAllPostMeta, getPostBySlug, getRelatedPosts } from '@/lib/blog/registry'
import { buildArticleJsonLd, buildBreadcrumbJsonLd, buildPostMetadata } from '@/lib/blog/seo'
import { getBaseUrl } from '@/lib/core/utils/urls'
import { soehne } from '@/app/_styles/fonts/soehne/soehne'
import { BackLink } from '@/app/(landing)/studio/[slug]/back-link'
import { ShareButton } from '@/app/(landing)/studio/[slug]/share-button'
export async function generateStaticParams() {
const posts = await getAllPostMeta()
@@ -51,7 +48,9 @@ export default async function Page({ params }: { params: Promise<{ slug: string
/>
<header className='mx-auto max-w-[1450px] px-6 pt-8 sm:px-8 sm:pt-12 md:px-12 md:pt-16'>
<div className='mb-6'>
<BackLink />
<Link href='/studio' className='text-gray-600 text-sm hover:text-gray-900'>
Back to Sim Studio
</Link>
</div>
<div className='flex flex-col gap-8 md:flex-row md:gap-12'>
<div className='w-full flex-shrink-0 md:w-[450px]'>
@@ -76,31 +75,28 @@ export default async function Page({ params }: { params: Promise<{ slug: string
>
{post.title}
</h1>
<div className='mt-4 flex items-center justify-between'>
<div className='flex items-center gap-3'>
{(post.authors || [post.author]).map((a, idx) => (
<div key={idx} className='flex items-center gap-2'>
{a?.avatarUrl ? (
<Avatar className='size-6'>
<AvatarImage src={a.avatarUrl} alt={a.name} />
<AvatarFallback>{a.name.slice(0, 2)}</AvatarFallback>
</Avatar>
) : null}
<Link
href={a?.url || '#'}
target='_blank'
rel='noopener noreferrer author'
className='text-[14px] text-gray-600 leading-[1.5] hover:text-gray-900 sm:text-[16px]'
itemProp='author'
itemScope
itemType='https://schema.org/Person'
>
<span itemProp='name'>{a?.name}</span>
</Link>
</div>
))}
</div>
<ShareButton url={`${getBaseUrl()}/studio/${slug}`} title={post.title} />
<div className='mt-4 flex items-center gap-3'>
{(post.authors || [post.author]).map((a, idx) => (
<div key={idx} className='flex items-center gap-2'>
{a?.avatarUrl ? (
<Avatar className='size-6'>
<AvatarImage src={a.avatarUrl} alt={a.name} />
<AvatarFallback>{a.name.slice(0, 2)}</AvatarFallback>
</Avatar>
) : null}
<Link
href={a?.url || '#'}
target='_blank'
rel='noopener noreferrer author'
className='text-[14px] text-gray-600 leading-[1.5] hover:text-gray-900 sm:text-[16px]'
itemProp='author'
itemScope
itemType='https://schema.org/Person'
>
<span itemProp='name'>{a?.name}</span>
</Link>
</div>
))}
</div>
</div>
</div>

View File

@@ -1,65 +0,0 @@
'use client'
import { useState } from 'react'
import { Share2 } from 'lucide-react'
import { Popover, PopoverContent, PopoverItem, PopoverTrigger } from '@/components/emcn'
interface ShareButtonProps {
url: string
title: string
}
export function ShareButton({ url, title }: ShareButtonProps) {
const [open, setOpen] = useState(false)
const [copied, setCopied] = useState(false)
const handleCopyLink = async () => {
try {
await navigator.clipboard.writeText(url)
setCopied(true)
setTimeout(() => {
setCopied(false)
setOpen(false)
}, 1000)
} catch {
setOpen(false)
}
}
const handleShareTwitter = () => {
const tweetUrl = `https://twitter.com/intent/tweet?url=${encodeURIComponent(url)}&text=${encodeURIComponent(title)}`
window.open(tweetUrl, '_blank', 'noopener,noreferrer')
setOpen(false)
}
const handleShareLinkedIn = () => {
const linkedInUrl = `https://www.linkedin.com/sharing/share-offsite/?url=${encodeURIComponent(url)}`
window.open(linkedInUrl, '_blank', 'noopener,noreferrer')
setOpen(false)
}
return (
<Popover
open={open}
onOpenChange={setOpen}
variant='secondary'
size='sm'
colorScheme='inverted'
>
<PopoverTrigger asChild>
<button
className='flex items-center gap-1.5 text-gray-600 text-sm hover:text-gray-900'
aria-label='Share this post'
>
<Share2 className='h-4 w-4' />
<span>Share</span>
</button>
</PopoverTrigger>
<PopoverContent align='end' minWidth={140}>
<PopoverItem onClick={handleCopyLink}>{copied ? 'Copied!' : 'Copy link'}</PopoverItem>
<PopoverItem onClick={handleShareTwitter}>Share on X</PopoverItem>
<PopoverItem onClick={handleShareLinkedIn}>Share on LinkedIn</PopoverItem>
</PopoverContent>
</Popover>
)
}

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