Skip to content

Commit 90e0b93

Browse files
committed
Merge branch 'staging' into feat/workflow-as-mcp
2 parents feacd08 + b7f6bab commit 90e0b93

File tree

593 files changed

+81785
-18234
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

593 files changed

+81785
-18234
lines changed

apps/docs/app/[lang]/[[...slug]]/page.tsx

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -258,8 +258,7 @@ export async function generateMetadata(props: {
258258
const baseUrl = 'https://docs.sim.ai'
259259
const fullUrl = `${baseUrl}${page.url}`
260260

261-
const description = data.description || ''
262-
const ogImageUrl = `${baseUrl}/api/og?title=${encodeURIComponent(data.title)}&category=DOCUMENTATION${description ? `&description=${encodeURIComponent(description)}` : ''}`
261+
const ogImageUrl = `${baseUrl}/api/og?title=${encodeURIComponent(data.title)}`
263262

264263
return {
265264
title: data.title,

apps/docs/app/api/og/route.tsx

Lines changed: 13 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -39,12 +39,10 @@ async function loadGoogleFont(font: string, weights: string, text: string): Prom
3939
export async function GET(request: NextRequest) {
4040
const { searchParams } = new URL(request.url)
4141
const title = searchParams.get('title') || 'Documentation'
42-
const category = searchParams.get('category') || 'DOCUMENTATION'
43-
const description = searchParams.get('description') || ''
4442

4543
const baseUrl = new URL(request.url).origin
4644

47-
const allText = `${title}${category}${description}docs.sim.ai`
45+
const allText = `${title}docs.sim.ai`
4846
const fontData = await loadGoogleFont('Geist', '400;500;600', allText)
4947

5048
return new ImageResponse(
@@ -59,7 +57,7 @@ export async function GET(request: NextRequest) {
5957
fontFamily: 'Geist',
6058
}}
6159
>
62-
{/* Base gradient layer - very subtle purple tint across the entire image */}
60+
{/* Base gradient layer - subtle purple tint across the entire image */}
6361
<div
6462
style={{
6563
position: 'absolute',
@@ -114,56 +112,25 @@ export async function GET(request: NextRequest) {
114112
{/* Logo */}
115113
<img src={`${baseUrl}/static/logo.png`} alt='sim' height={32} />
116114

117-
{/* Category + Title + Description */}
118-
<div
115+
{/* Title */}
116+
<span
119117
style={{
120-
display: 'flex',
121-
flexDirection: 'column',
122-
gap: 12,
118+
fontSize: getTitleFontSize(title),
119+
fontWeight: 600,
120+
color: '#ffffff',
121+
lineHeight: 1.1,
122+
letterSpacing: '-0.02em',
123123
}}
124124
>
125-
<span
126-
style={{
127-
fontSize: 15,
128-
fontWeight: 600,
129-
color: '#802fff',
130-
letterSpacing: '0.02em',
131-
}}
132-
>
133-
{category}
134-
</span>
135-
<span
136-
style={{
137-
fontSize: getTitleFontSize(title),
138-
fontWeight: 600,
139-
color: '#ffffff',
140-
lineHeight: 1.1,
141-
letterSpacing: '-0.02em',
142-
}}
143-
>
144-
{title}
145-
</span>
146-
{description && (
147-
<span
148-
style={{
149-
fontSize: 18,
150-
fontWeight: 400,
151-
color: '#a1a1aa',
152-
lineHeight: 1.4,
153-
marginTop: 4,
154-
}}
155-
>
156-
{description.length > 100 ? `${description.slice(0, 100)}...` : description}
157-
</span>
158-
)}
159-
</div>
125+
{title}
126+
</span>
160127

161128
{/* Footer */}
162129
<span
163130
style={{
164-
fontSize: 15,
131+
fontSize: 20,
165132
fontWeight: 500,
166-
color: '#52525b',
133+
color: '#71717a',
167134
}}
168135
>
169136
docs.sim.ai

apps/docs/app/api/search/route.ts

Lines changed: 126 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,126 @@
1-
import { createFromSource } from 'fumadocs-core/search/server'
2-
import { source } from '@/lib/source'
3-
4-
export const revalidate = 3600 // Revalidate every hour
5-
6-
export const { GET } = createFromSource(source, {
7-
localeMap: {
8-
en: { language: 'english' },
9-
es: { language: 'spanish' },
10-
fr: { language: 'french' },
11-
de: { language: 'german' },
12-
// ja and zh are not supported by the stemmer library, so we'll skip language config for them
13-
ja: {},
14-
zh: {},
15-
},
16-
})
1+
import { sql } from 'drizzle-orm'
2+
import { type NextRequest, NextResponse } from 'next/server'
3+
import { db, docsEmbeddings } from '@/lib/db'
4+
import { generateSearchEmbedding } from '@/lib/embeddings'
5+
6+
export const runtime = 'nodejs'
7+
export const revalidate = 0
8+
9+
/**
10+
* Hybrid search API endpoint
11+
* - English: Vector embeddings + keyword search
12+
* - Other languages: Keyword search only
13+
*/
14+
export async function GET(request: NextRequest) {
15+
try {
16+
const searchParams = request.nextUrl.searchParams
17+
const query = searchParams.get('query') || searchParams.get('q') || ''
18+
const locale = searchParams.get('locale') || 'en'
19+
const limit = Number.parseInt(searchParams.get('limit') || '10', 10)
20+
21+
if (!query || query.trim().length === 0) {
22+
return NextResponse.json([])
23+
}
24+
25+
const candidateLimit = limit * 3
26+
const similarityThreshold = 0.6
27+
28+
const localeMap: Record<string, string> = {
29+
en: 'english',
30+
es: 'spanish',
31+
fr: 'french',
32+
de: 'german',
33+
ja: 'simple', // PostgreSQL doesn't have Japanese support, use simple
34+
zh: 'simple', // PostgreSQL doesn't have Chinese support, use simple
35+
}
36+
const tsConfig = localeMap[locale] || 'simple'
37+
38+
const useVectorSearch = locale === 'en'
39+
let vectorResults: Array<{
40+
chunkId: string
41+
chunkText: string
42+
sourceDocument: string
43+
sourceLink: string
44+
headerText: string
45+
headerLevel: number
46+
similarity: number
47+
searchType: string
48+
}> = []
49+
50+
if (useVectorSearch) {
51+
const queryEmbedding = await generateSearchEmbedding(query)
52+
vectorResults = await db
53+
.select({
54+
chunkId: docsEmbeddings.chunkId,
55+
chunkText: docsEmbeddings.chunkText,
56+
sourceDocument: docsEmbeddings.sourceDocument,
57+
sourceLink: docsEmbeddings.sourceLink,
58+
headerText: docsEmbeddings.headerText,
59+
headerLevel: docsEmbeddings.headerLevel,
60+
similarity: sql<number>`1 - (${docsEmbeddings.embedding} <=> ${JSON.stringify(queryEmbedding)}::vector)`,
61+
searchType: sql<string>`'vector'`,
62+
})
63+
.from(docsEmbeddings)
64+
.where(
65+
sql`1 - (${docsEmbeddings.embedding} <=> ${JSON.stringify(queryEmbedding)}::vector) >= ${similarityThreshold}`
66+
)
67+
.orderBy(sql`${docsEmbeddings.embedding} <=> ${JSON.stringify(queryEmbedding)}::vector`)
68+
.limit(candidateLimit)
69+
}
70+
71+
const keywordResults = await db
72+
.select({
73+
chunkId: docsEmbeddings.chunkId,
74+
chunkText: docsEmbeddings.chunkText,
75+
sourceDocument: docsEmbeddings.sourceDocument,
76+
sourceLink: docsEmbeddings.sourceLink,
77+
headerText: docsEmbeddings.headerText,
78+
headerLevel: docsEmbeddings.headerLevel,
79+
similarity: sql<number>`ts_rank(${docsEmbeddings.chunkTextTsv}, plainto_tsquery(${tsConfig}, ${query}))`,
80+
searchType: sql<string>`'keyword'`,
81+
})
82+
.from(docsEmbeddings)
83+
.where(sql`${docsEmbeddings.chunkTextTsv} @@ plainto_tsquery(${tsConfig}, ${query})`)
84+
.orderBy(
85+
sql`ts_rank(${docsEmbeddings.chunkTextTsv}, plainto_tsquery(${tsConfig}, ${query})) DESC`
86+
)
87+
.limit(candidateLimit)
88+
89+
const seenIds = new Set<string>()
90+
const mergedResults = []
91+
92+
for (let i = 0; i < Math.max(vectorResults.length, keywordResults.length); i++) {
93+
if (i < vectorResults.length && !seenIds.has(vectorResults[i].chunkId)) {
94+
mergedResults.push(vectorResults[i])
95+
seenIds.add(vectorResults[i].chunkId)
96+
}
97+
if (i < keywordResults.length && !seenIds.has(keywordResults[i].chunkId)) {
98+
mergedResults.push(keywordResults[i])
99+
seenIds.add(keywordResults[i].chunkId)
100+
}
101+
}
102+
103+
const filteredResults = mergedResults.slice(0, limit)
104+
const searchResults = filteredResults.map((result) => {
105+
const title = result.headerText || result.sourceDocument.replace('.mdx', '')
106+
const pathParts = result.sourceDocument
107+
.replace('.mdx', '')
108+
.split('/')
109+
.map((part) => part.charAt(0).toUpperCase() + part.slice(1))
110+
111+
return {
112+
id: result.chunkId,
113+
type: 'page' as const,
114+
url: result.sourceLink,
115+
content: title,
116+
breadcrumbs: pathParts,
117+
}
118+
})
119+
120+
return NextResponse.json(searchResults)
121+
} catch (error) {
122+
console.error('Semantic search error:', error)
123+
124+
return NextResponse.json([])
125+
}
126+
}

apps/docs/app/layout.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ export const metadata = {
5858
'Comprehensive documentation for Sim - the visual workflow builder for AI applications. Create powerful AI agents, automation workflows, and data processing pipelines.',
5959
images: [
6060
{
61-
url: 'https://docs.sim.ai/api/og?title=Sim%20Documentation&category=DOCUMENTATION',
61+
url: 'https://docs.sim.ai/api/og?title=Sim%20Documentation',
6262
width: 1200,
6363
height: 630,
6464
alt: 'Sim Documentation',
@@ -72,7 +72,7 @@ export const metadata = {
7272
'Comprehensive documentation for Sim - the visual workflow builder for AI applications.',
7373
creator: '@simdotai',
7474
site: '@simdotai',
75-
images: ['https://docs.sim.ai/api/og?title=Sim%20Documentation&category=DOCUMENTATION'],
75+
images: ['https://docs.sim.ai/api/og?title=Sim%20Documentation'],
7676
},
7777
robots: {
7878
index: true,

apps/docs/components/icons.tsx

Lines changed: 43 additions & 0 deletions
Large diffs are not rendered by default.

apps/docs/components/ui/icon-mapping.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import {
1313
BrainIcon,
1414
BrowserUseIcon,
1515
CalendlyIcon,
16+
CirclebackIcon,
1617
ClayIcon,
1718
ConfluenceIcon,
1819
CursorIcon,
@@ -40,6 +41,7 @@ import {
4041
GoogleSlidesIcon,
4142
GoogleVaultIcon,
4243
GrafanaIcon,
44+
GrainIcon,
4345
HubspotIcon,
4446
HuggingFaceIcon,
4547
HunterIOIcon,
@@ -128,6 +130,7 @@ export const blockTypeToIconMap: Record<string, IconComponent> = {
128130
asana: AsanaIcon,
129131
browser_use: BrowserUseIcon,
130132
calendly: CalendlyIcon,
133+
circleback: CirclebackIcon,
131134
clay: ClayIcon,
132135
confluence: ConfluenceIcon,
133136
cursor: CursorIcon,
@@ -154,6 +157,7 @@ export const blockTypeToIconMap: Record<string, IconComponent> = {
154157
google_slides: GoogleSlidesIcon,
155158
google_vault: GoogleVaultIcon,
156159
grafana: GrafanaIcon,
160+
grain: GrainIcon,
157161
hubspot: HubspotIcon,
158162
huggingface: HuggingFaceIcon,
159163
hunter: HunterIOIcon,

0 commit comments

Comments
 (0)