Skip to content

Commit 091343a

Browse files
authored
fix(copilot): fix origin (#1015)
* Fix v1 * Use env var * Lint
1 parent 63c66bf commit 091343a

File tree

8 files changed

+153
-2
lines changed

8 files changed

+153
-2
lines changed

README.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,13 @@ cd apps/sim
158158
bun run dev:sockets
159159
```
160160

161+
## Copilot API Keys
162+
163+
Copilot is a Sim-managed service. To use Copilot on a self-hosted instance:
164+
165+
- Go to https://sim.ai → Settings → Copilot and generate a Copilot API key
166+
- Set `COPILOT_API_KEY` in your self-hosted environment to that value
167+
161168
## Tech Stack
162169

163170
- **Framework**: [Next.js](https://nextjs.org/) (App Router)
Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
---
2+
title: Copilot
3+
description: Build and edit workflows with Sim Copilot
4+
---
5+
6+
import { Callout } from 'fumadocs-ui/components/callout'
7+
import { Card, Cards } from 'fumadocs-ui/components/card'
8+
import { MessageCircle, Package, Zap, Infinity as InfinityIcon, Brain, BrainCircuit } from 'lucide-react'
9+
10+
## What is Copilot
11+
12+
Copilot is your in-editor assistant that helps you build, understand, and improve workflows. It can:
13+
14+
- **Explain**: Answer questions about Sim and your current workflow
15+
- **Guide**: Suggest edits and best practices
16+
- **Edit**: Make changes to blocks, connections, and settings when you approve
17+
18+
<Callout type="info">
19+
Copilot is a Sim-managed service. For self-hosted deployments, generate a Copilot API key in the hosted app (sim.ai → Settings → Copilot) and set `COPILOT_API_KEY` in your environment.
20+
</Callout>
21+
22+
## Modes
23+
24+
<Cards>
25+
<Card title="Ask">
26+
<div className="flex items-start gap-3">
27+
<span className="mt-0.5 inline-flex h-8 w-8 items-center justify-center rounded-md border border-border/50 bg-muted/60">
28+
<MessageCircle className="h-4 w-4 text-muted-foreground" />
29+
</span>
30+
<div>
31+
<p className="m-0 text-sm">
32+
Q&A mode for explanations, guidance, and suggestions without making changes to your workflow.
33+
</p>
34+
</div>
35+
</div>
36+
</Card>
37+
<Card title="Agent">
38+
<div className="flex items-start gap-3">
39+
<span className="mt-0.5 inline-flex h-8 w-8 items-center justify-center rounded-md border border-border/50 bg-muted/60">
40+
<Package className="h-4 w-4 text-muted-foreground" />
41+
</span>
42+
<div>
43+
<p className="m-0 text-sm">
44+
Build-and-edit mode. Copilot proposes specific edits (add blocks, wire variables, tweak settings) and applies them when you approve.
45+
</p>
46+
</div>
47+
</div>
48+
</Card>
49+
</Cards>
50+
51+
## Depth Levels
52+
53+
<Cards>
54+
<Card title="Fast">
55+
<div className="flex items-start gap-3">
56+
<span className="mt-0.5 inline-flex h-8 w-8 items-center justify-center rounded-md border border-border/50 bg-muted/60">
57+
<Zap className="h-4 w-4 text-muted-foreground" />
58+
</span>
59+
<div>
60+
<p className="m-0 text-sm">Quickest and cheapest. Best for small edits, simple workflows, and minor tweaks.</p>
61+
</div>
62+
</div>
63+
</Card>
64+
<Card title="Auto">
65+
<div className="flex items-start gap-3">
66+
<span className="mt-0.5 inline-flex h-8 w-8 items-center justify-center rounded-md border border-border/50 bg-muted/60">
67+
<InfinityIcon className="h-4 w-4 text-muted-foreground" />
68+
</span>
69+
<div>
70+
<p className="m-0 text-sm">Balanced speed and reasoning. Recommended default for most tasks.</p>
71+
</div>
72+
</div>
73+
</Card>
74+
<Card title="Pro">
75+
<div className="flex items-start gap-3">
76+
<span className="mt-0.5 inline-flex h-8 w-8 items-center justify-center rounded-md border border-border/50 bg-muted/60">
77+
<Brain className="h-4 w-4 text-muted-foreground" />
78+
</span>
79+
<div>
80+
<p className="m-0 text-sm">More reasoning for larger workflows and complex edits while staying performant.</p>
81+
</div>
82+
</div>
83+
</Card>
84+
<Card title="Max">
85+
<div className="flex items-start gap-3">
86+
<span className="mt-0.5 inline-flex h-8 w-8 items-center justify-center rounded-md border border-border/50 bg-muted/60">
87+
<BrainCircuit className="h-4 w-4 text-muted-foreground" />
88+
</span>
89+
<div>
90+
<p className="m-0 text-sm">Maximum reasoning for deep planning, debugging, and complex architectural changes.</p>
91+
</div>
92+
</div>
93+
</Card>
94+
</Cards>
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
{
2+
"title": "Copilot",
3+
"pages": ["index"]
4+
}

apps/docs/content/docs/meta.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@
1212
"connections",
1313
"---Execution---",
1414
"execution",
15+
"---Copilot---",
16+
"copilot",
1517
"---Advanced---",
1618
"./variables/index",
1719
"yaml",

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

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,7 @@ describe('Copilot Chat API Route', () => {
105105
env: {
106106
SIM_AGENT_API_URL: 'http://localhost:8000',
107107
COPILOT_API_KEY: 'test-sim-agent-key',
108+
BETTER_AUTH_URL: 'http://localhost:3000',
108109
},
109110
}))
110111

@@ -225,6 +226,7 @@ describe('Copilot Chat API Route', () => {
225226
mode: 'agent',
226227
provider: 'openai',
227228
depth: 0,
229+
origin: 'http://localhost:3000',
228230
}),
229231
})
230232
)
@@ -288,6 +290,7 @@ describe('Copilot Chat API Route', () => {
288290
mode: 'agent',
289291
provider: 'openai',
290292
depth: 0,
293+
origin: 'http://localhost:3000',
291294
}),
292295
})
293296
)
@@ -343,6 +346,7 @@ describe('Copilot Chat API Route', () => {
343346
mode: 'agent',
344347
provider: 'openai',
345348
depth: 0,
349+
origin: 'http://localhost:3000',
346350
}),
347351
})
348352
)
@@ -438,6 +442,7 @@ describe('Copilot Chat API Route', () => {
438442
mode: 'ask',
439443
provider: 'openai',
440444
depth: 0,
445+
origin: 'http://localhost:3000',
441446
}),
442447
})
443448
)

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

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,15 @@ const logger = createLogger('CopilotChatAPI')
2828
// Sim Agent API configuration
2929
const SIM_AGENT_API_URL = env.SIM_AGENT_API_URL || SIM_AGENT_API_URL_DEFAULT
3030

31+
function getRequestOrigin(_req: NextRequest): string {
32+
try {
33+
// Strictly use configured Better Auth URL
34+
return env.BETTER_AUTH_URL || ''
35+
} catch (_) {
36+
return ''
37+
}
38+
}
39+
3140
function deriveKey(keyString: string): Buffer {
3241
return createHash('sha256').update(keyString, 'utf8').digest()
3342
}
@@ -197,6 +206,14 @@ export async function POST(req: NextRequest) {
197206
conversationId,
198207
} = ChatMessageSchema.parse(body)
199208

209+
// Derive request origin for downstream service
210+
const requestOrigin = getRequestOrigin(req)
211+
212+
if (!requestOrigin) {
213+
logger.error(`[${tracker.requestId}] Missing required configuration: BETTER_AUTH_URL`)
214+
return createInternalServerErrorResponse('Missing required configuration: BETTER_AUTH_URL')
215+
}
216+
200217
logger.info(`[${tracker.requestId}] Processing copilot chat request`, {
201218
userId: authenticatedUserId,
202219
workflowId,
@@ -209,6 +226,7 @@ export async function POST(req: NextRequest) {
209226
provider: provider || 'openai',
210227
hasConversationId: !!conversationId,
211228
depth,
229+
origin: requestOrigin,
212230
})
213231

214232
// Handle chat context
@@ -386,6 +404,7 @@ export async function POST(req: NextRequest) {
386404
...(effectiveConversationId ? { conversationId: effectiveConversationId } : {}),
387405
...(typeof depth === 'number' ? { depth } : {}),
388406
...(session?.user?.name && { userName: session.user.name }),
407+
...(requestOrigin ? { origin: requestOrigin } : {}),
389408
}
390409

391410
// Log the payload being sent to the streaming endpoint
@@ -399,6 +418,7 @@ export async function POST(req: NextRequest) {
399418
hasConversationId: !!effectiveConversationId,
400419
depth: typeof depth === 'number' ? depth : undefined,
401420
messagesCount: requestPayload.messages.length,
421+
...(requestOrigin ? { origin: requestOrigin } : {}),
402422
})
403423
// Full payload as JSON string
404424
logger.info(

apps/sim/app/api/copilot/methods/route.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { type NextRequest, NextResponse } from 'next/server'
22
import { z } from 'zod'
33
import { copilotToolRegistry } from '@/lib/copilot/tools/server-tools/registry'
44
import type { NotificationStatus } from '@/lib/copilot/types'
5-
import { checkInternalApiKey } from '@/lib/copilot/utils'
5+
import { checkCopilotApiKey, checkInternalApiKey } from '@/lib/copilot/utils'
66
import { createLogger } from '@/lib/logs/console/logger'
77
import { getRedisClient } from '@/lib/redis'
88
import { createErrorResponse } from '@/app/api/copilot/methods/utils'
@@ -233,7 +233,7 @@ export async function POST(req: NextRequest) {
233233

234234
try {
235235
// Check authentication (internal API key)
236-
const authResult = checkInternalApiKey(req)
236+
const authResult = checkInternalApiKey(req) || checkCopilotApiKey(req)
237237
if (!authResult.success) {
238238
return NextResponse.json(createErrorResponse(authResult.error || 'Authentication failed'), {
239239
status: 401,

apps/sim/lib/copilot/utils.ts

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,3 +19,22 @@ export function checkInternalApiKey(req: NextRequest) {
1919

2020
return { success: true }
2121
}
22+
23+
export function checkCopilotApiKey(req: NextRequest) {
24+
const apiKey = req.headers.get('x-api-key')
25+
const expectedApiKey = env.COPILOT_API_KEY
26+
27+
if (!expectedApiKey) {
28+
return { success: false, error: 'Copilot API key not configured' }
29+
}
30+
31+
if (!apiKey) {
32+
return { success: false, error: 'API key required' }
33+
}
34+
35+
if (apiKey !== expectedApiKey) {
36+
return { success: false, error: 'Invalid API key' }
37+
}
38+
39+
return { success: true }
40+
}

0 commit comments

Comments
 (0)