Skip to content

Commit 1c818b2

Browse files
v0.3.23: multiplayer variables, api key fixes, kb improvements, triggers fixes
v0.3.23: multiplayer variables, api key fixes, kb improvements, triggers fixes
2 parents aedf5e7 + 1a7de84 commit 1c818b2

File tree

294 files changed

+16706
-10734
lines changed

Some content is hidden

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

294 files changed

+16706
-10734
lines changed

.github/CONTRIBUTING.md

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -416,8 +416,8 @@ In addition, you will need to update the registries:
416416
Your tool should export a constant with a naming convention of `{toolName}Tool`. The tool ID should follow the format `{provider}_{tool_name}`. For example:
417417
418418
```typescript:/apps/sim/tools/pinecone/fetch.ts
419-
import { ToolConfig, ToolResponse } from '../types'
420-
import { PineconeParams, PineconeResponse } from './types'
419+
import { ToolConfig, ToolResponse } from '@/tools/types'
420+
import { PineconeParams, PineconeResponse } from '@/tools/pinecone/types'
421421
422422
export const fetchTool: ToolConfig<PineconeParams, PineconeResponse> = {
423423
id: 'pinecone_fetch', // Follow the {provider}_{tool_name} format
@@ -448,17 +448,14 @@ In addition, you will need to update the registries:
448448
transformResponse: async (response: Response) => {
449449
// Transform response
450450
},
451-
transformError: (error) => {
452-
// Handle errors
453-
},
454451
}
455452
```
456453
457454
6. **Register Your Tool:**
458455
Update the tools registry in `/apps/sim/tools/index.ts` to include your new tool:
459456
460457
```typescript:/apps/sim/tools/index.ts
461-
import { fetchTool, generateEmbeddingsTool, searchTextTool } from './pinecone'
458+
import { fetchTool, generateEmbeddingsTool, searchTextTool } from '/@tools/pinecone'
462459
// ... other imports
463460
464461
export const tools: Record<string, ToolConfig> = {

apps/docs/content/docs/tools/airtable.mdx

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -151,8 +151,6 @@ Update multiple existing records in an Airtable table
151151
| `baseId` | string | Yes | ID of the Airtable base |
152152
| `tableId` | string | Yes | ID or name of the table |
153153
| `records` | json | Yes | Array of records to update, each with an `id` and a `fields` object |
154-
| `fields` | string | No | No description |
155-
| `fields` | string | No | No description |
156154

157155
#### Output
158156

apps/docs/content/docs/tools/browser_use.mdx

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -82,9 +82,10 @@ Runs a browser automation task using BrowserUse
8282

8383
| Parameter | Type | Description |
8484
| --------- | ---- | ----------- |
85-
| `success` | boolean | Operation success status |
86-
| `output` | json | Browser automation task results including task ID, success status, output data, and execution steps |
87-
| `error` | string | Error message if the operation failed |
85+
| `id` | string | Task execution identifier |
86+
| `success` | boolean | Task completion status |
87+
| `output` | json | Task output data |
88+
| `steps` | json | Execution steps taken |
8889

8990

9091

apps/docs/content/docs/tools/elevenlabs.mdx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ Convert TTS using ElevenLabs voices
6262

6363
| Parameter | Type | Description |
6464
| --------- | ---- | ----------- |
65-
| `audioUrl` | string | Generated audio URL |
65+
| `audioUrl` | string | The URL of the generated audio |
6666

6767

6868

apps/docs/content/docs/tools/file.mdx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -71,8 +71,8 @@ Parse one or more uploaded files or files from URLs (text, PDF, CSV, images, etc
7171

7272
| Parameter | Type | Description |
7373
| --------- | ---- | ----------- |
74-
| `files` | json | Array of parsed file objects with content, metadata, and file properties |
75-
| `combinedContent` | string | All file contents merged into a single text string |
74+
| `files` | array | Array of parsed files |
75+
| `combinedContent` | string | Combined content of all parsed files |
7676

7777

7878

apps/docs/content/docs/tools/supabase.mdx

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -101,8 +101,8 @@ Query data from a Supabase table
101101

102102
| Parameter | Type | Description |
103103
| --------- | ---- | ----------- |
104-
| `success` | boolean | Operation success status |
105-
| `output` | object | Query operation results |
104+
| `message` | string | Operation status message |
105+
| `results` | array | Array of records returned from the query |
106106

107107
### `supabase_insert`
108108

@@ -121,8 +121,8 @@ Insert data into a Supabase table
121121

122122
| Parameter | Type | Description |
123123
| --------- | ---- | ----------- |
124-
| `success` | boolean | Operation success status |
125-
| `output` | object | Insert operation results |
124+
| `message` | string | Operation status message |
125+
| `results` | array | Array of inserted records |
126126

127127
### `supabase_get_row`
128128

@@ -141,8 +141,8 @@ Get a single row from a Supabase table based on filter criteria
141141

142142
| Parameter | Type | Description |
143143
| --------- | ---- | ----------- |
144-
| `success` | boolean | Operation success status |
145-
| `output` | object | Get row operation results |
144+
| `message` | string | Operation status message |
145+
| `results` | object | The row data if found, null if not found |
146146

147147
### `supabase_update`
148148

@@ -162,8 +162,8 @@ Update rows in a Supabase table based on filter criteria
162162

163163
| Parameter | Type | Description |
164164
| --------- | ---- | ----------- |
165-
| `success` | boolean | Operation success status |
166-
| `output` | object | Update operation results |
165+
| `message` | string | Operation status message |
166+
| `results` | array | Array of updated records |
167167

168168
### `supabase_delete`
169169

@@ -182,8 +182,8 @@ Delete rows from a Supabase table based on filter criteria
182182

183183
| Parameter | Type | Description |
184184
| --------- | ---- | ----------- |
185-
| `success` | boolean | Operation success status |
186-
| `output` | object | Delete operation results |
185+
| `message` | string | Operation status message |
186+
| `results` | array | Array of deleted records |
187187

188188

189189

apps/sim/app/api/chat/route.test.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -245,6 +245,8 @@ describe('Chat API Route', () => {
245245
NODE_ENV: 'development',
246246
NEXT_PUBLIC_APP_URL: 'http://localhost:3000',
247247
},
248+
isTruthy: (value: string | boolean | number | undefined) =>
249+
typeof value === 'string' ? value === 'true' || value === '1' : Boolean(value),
248250
}))
249251

250252
const validData = {
@@ -287,6 +289,8 @@ describe('Chat API Route', () => {
287289
NODE_ENV: 'development',
288290
NEXT_PUBLIC_APP_URL: 'http://localhost:3000',
289291
},
292+
isTruthy: (value: string | boolean | number | undefined) =>
293+
typeof value === 'string' ? value === 'true' || value === '1' : Boolean(value),
290294
}))
291295

292296
const validData = {

apps/sim/app/api/help/route.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -98,8 +98,8 @@ ${message}
9898

9999
// Send email using Resend
100100
const { data, error } = await resend.emails.send({
101-
from: `Sim <noreply@${env.EMAIL_DOMAIN || getEmailDomain()}>`,
102-
to: [`help@${env.EMAIL_DOMAIN || getEmailDomain()}`],
101+
from: `Sim <noreply@${getEmailDomain()}>`,
102+
to: [`help@${getEmailDomain()}`],
103103
subject: `[${type.toUpperCase()}] ${subject}`,
104104
replyTo: email,
105105
text: emailText,
@@ -121,7 +121,7 @@ ${message}
121121
// Send confirmation email to the user
122122
await resend.emails
123123
.send({
124-
from: `Sim <noreply@${env.EMAIL_DOMAIN || getEmailDomain()}>`,
124+
from: `Sim <noreply@${getEmailDomain()}>`,
125125
to: [email],
126126
subject: `Your ${type} request has been received: ${subject}`,
127127
text: `
@@ -137,7 +137,7 @@ ${images.length > 0 ? `You attached ${images.length} image(s).` : ''}
137137
Best regards,
138138
The Sim Team
139139
`,
140-
replyTo: `help@${env.EMAIL_DOMAIN || getEmailDomain()}`,
140+
replyTo: `help@${getEmailDomain()}`,
141141
})
142142
.catch((err) => {
143143
logger.warn(`[${requestId}] Failed to send confirmation email`, err)
Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
import { randomUUID } from 'crypto'
2+
import { and, eq, isNotNull } from 'drizzle-orm'
3+
import { type NextRequest, NextResponse } from 'next/server'
4+
import { getSession } from '@/lib/auth'
5+
import { createLogger } from '@/lib/logs/console/logger'
6+
import { checkKnowledgeBaseAccess } from '@/app/api/knowledge/utils'
7+
import { db } from '@/db'
8+
import { document, embedding, knowledgeBaseTagDefinitions } from '@/db/schema'
9+
10+
export const dynamic = 'force-dynamic'
11+
12+
const logger = createLogger('TagDefinitionAPI')
13+
14+
// DELETE /api/knowledge/[id]/tag-definitions/[tagId] - Delete a tag definition
15+
export async function DELETE(
16+
req: NextRequest,
17+
{ params }: { params: Promise<{ id: string; tagId: string }> }
18+
) {
19+
const requestId = randomUUID().slice(0, 8)
20+
const { id: knowledgeBaseId, tagId } = await params
21+
22+
try {
23+
logger.info(
24+
`[${requestId}] Deleting tag definition ${tagId} from knowledge base ${knowledgeBaseId}`
25+
)
26+
27+
const session = await getSession()
28+
if (!session?.user?.id) {
29+
return NextResponse.json({ error: 'Unauthorized' }, { status: 401 })
30+
}
31+
32+
// Check if user has access to the knowledge base
33+
const accessCheck = await checkKnowledgeBaseAccess(knowledgeBaseId, session.user.id)
34+
if (!accessCheck.hasAccess) {
35+
return NextResponse.json({ error: 'Forbidden' }, { status: 403 })
36+
}
37+
38+
// Get the tag definition to find which slot it uses
39+
const tagDefinition = await db
40+
.select({
41+
id: knowledgeBaseTagDefinitions.id,
42+
tagSlot: knowledgeBaseTagDefinitions.tagSlot,
43+
displayName: knowledgeBaseTagDefinitions.displayName,
44+
})
45+
.from(knowledgeBaseTagDefinitions)
46+
.where(
47+
and(
48+
eq(knowledgeBaseTagDefinitions.id, tagId),
49+
eq(knowledgeBaseTagDefinitions.knowledgeBaseId, knowledgeBaseId)
50+
)
51+
)
52+
.limit(1)
53+
54+
if (tagDefinition.length === 0) {
55+
return NextResponse.json({ error: 'Tag definition not found' }, { status: 404 })
56+
}
57+
58+
const tagDef = tagDefinition[0]
59+
60+
// Delete the tag definition and clear all document tags in a transaction
61+
await db.transaction(async (tx) => {
62+
logger.info(`[${requestId}] Starting transaction to delete ${tagDef.tagSlot}`)
63+
64+
try {
65+
// Clear the tag from documents that actually have this tag set
66+
logger.info(`[${requestId}] Clearing tag from documents...`)
67+
await tx
68+
.update(document)
69+
.set({ [tagDef.tagSlot]: null })
70+
.where(
71+
and(
72+
eq(document.knowledgeBaseId, knowledgeBaseId),
73+
isNotNull(document[tagDef.tagSlot as keyof typeof document.$inferSelect])
74+
)
75+
)
76+
77+
logger.info(`[${requestId}] Documents updated successfully`)
78+
79+
// Clear the tag from embeddings that actually have this tag set
80+
logger.info(`[${requestId}] Clearing tag from embeddings...`)
81+
await tx
82+
.update(embedding)
83+
.set({ [tagDef.tagSlot]: null })
84+
.where(
85+
and(
86+
eq(embedding.knowledgeBaseId, knowledgeBaseId),
87+
isNotNull(embedding[tagDef.tagSlot as keyof typeof embedding.$inferSelect])
88+
)
89+
)
90+
91+
logger.info(`[${requestId}] Embeddings updated successfully`)
92+
93+
// Delete the tag definition
94+
logger.info(`[${requestId}] Deleting tag definition...`)
95+
await tx
96+
.delete(knowledgeBaseTagDefinitions)
97+
.where(eq(knowledgeBaseTagDefinitions.id, tagId))
98+
99+
logger.info(`[${requestId}] Tag definition deleted successfully`)
100+
} catch (error) {
101+
logger.error(`[${requestId}] Error in transaction:`, error)
102+
throw error
103+
}
104+
})
105+
106+
logger.info(
107+
`[${requestId}] Successfully deleted tag definition ${tagDef.displayName} (${tagDef.tagSlot})`
108+
)
109+
110+
return NextResponse.json({
111+
success: true,
112+
message: `Tag definition "${tagDef.displayName}" deleted successfully`,
113+
})
114+
} catch (error) {
115+
logger.error(`[${requestId}] Error deleting tag definition`, error)
116+
return NextResponse.json({ error: 'Failed to delete tag definition' }, { status: 500 })
117+
}
118+
}

apps/sim/app/api/knowledge/[id]/tag-definitions/route.ts

Lines changed: 87 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { randomUUID } from 'crypto'
2-
import { eq } from 'drizzle-orm'
2+
import { and, eq } from 'drizzle-orm'
33
import { type NextRequest, NextResponse } from 'next/server'
44
import { getSession } from '@/lib/auth'
55
import { createLogger } from '@/lib/logs/console/logger'
@@ -55,3 +55,89 @@ export async function GET(req: NextRequest, { params }: { params: Promise<{ id:
5555
return NextResponse.json({ error: 'Failed to get tag definitions' }, { status: 500 })
5656
}
5757
}
58+
59+
// POST /api/knowledge/[id]/tag-definitions - Create a new tag definition
60+
export async function POST(req: NextRequest, { params }: { params: Promise<{ id: string }> }) {
61+
const requestId = randomUUID().slice(0, 8)
62+
const { id: knowledgeBaseId } = await params
63+
64+
try {
65+
logger.info(`[${requestId}] Creating tag definition for knowledge base ${knowledgeBaseId}`)
66+
67+
const session = await getSession()
68+
if (!session?.user?.id) {
69+
return NextResponse.json({ error: 'Unauthorized' }, { status: 401 })
70+
}
71+
72+
// Check if user has access to the knowledge base
73+
const accessCheck = await checkKnowledgeBaseAccess(knowledgeBaseId, session.user.id)
74+
if (!accessCheck.hasAccess) {
75+
return NextResponse.json({ error: 'Forbidden' }, { status: 403 })
76+
}
77+
78+
const body = await req.json()
79+
const { tagSlot, displayName, fieldType } = body
80+
81+
if (!tagSlot || !displayName || !fieldType) {
82+
return NextResponse.json(
83+
{ error: 'tagSlot, displayName, and fieldType are required' },
84+
{ status: 400 }
85+
)
86+
}
87+
88+
// Check if tag slot is already used
89+
const existingTag = await db
90+
.select()
91+
.from(knowledgeBaseTagDefinitions)
92+
.where(
93+
and(
94+
eq(knowledgeBaseTagDefinitions.knowledgeBaseId, knowledgeBaseId),
95+
eq(knowledgeBaseTagDefinitions.tagSlot, tagSlot)
96+
)
97+
)
98+
.limit(1)
99+
100+
if (existingTag.length > 0) {
101+
return NextResponse.json({ error: 'Tag slot is already in use' }, { status: 409 })
102+
}
103+
104+
// Check if display name is already used
105+
const existingName = await db
106+
.select()
107+
.from(knowledgeBaseTagDefinitions)
108+
.where(
109+
and(
110+
eq(knowledgeBaseTagDefinitions.knowledgeBaseId, knowledgeBaseId),
111+
eq(knowledgeBaseTagDefinitions.displayName, displayName)
112+
)
113+
)
114+
.limit(1)
115+
116+
if (existingName.length > 0) {
117+
return NextResponse.json({ error: 'Tag name is already in use' }, { status: 409 })
118+
}
119+
120+
// Create the new tag definition
121+
const newTagDefinition = {
122+
id: randomUUID(),
123+
knowledgeBaseId,
124+
tagSlot,
125+
displayName,
126+
fieldType,
127+
createdAt: new Date(),
128+
updatedAt: new Date(),
129+
}
130+
131+
await db.insert(knowledgeBaseTagDefinitions).values(newTagDefinition)
132+
133+
logger.info(`[${requestId}] Successfully created tag definition ${displayName} (${tagSlot})`)
134+
135+
return NextResponse.json({
136+
success: true,
137+
data: newTagDefinition,
138+
})
139+
} catch (error) {
140+
logger.error(`[${requestId}] Error creating tag definition`, error)
141+
return NextResponse.json({ error: 'Failed to create tag definition' }, { status: 500 })
142+
}
143+
}

0 commit comments

Comments
 (0)