Skip to content

Commit c5dd90e

Browse files
authored
feat(copilot): enterprise configuration (#3184)
* Copilot enterprise models * Fix azure anthropic * Fix * Consolidation * Cleanup * Clean up code * Fix lint * cleanup * Fix greptile
1 parent 20b230d commit c5dd90e

File tree

21 files changed

+410
-743
lines changed

21 files changed

+410
-743
lines changed

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

Lines changed: 53 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,8 @@ import { getSession } from '@/lib/auth'
88
import { buildConversationHistory } from '@/lib/copilot/chat-context'
99
import { resolveOrCreateChat } from '@/lib/copilot/chat-lifecycle'
1010
import { buildCopilotRequestPayload } from '@/lib/copilot/chat-payload'
11-
import { generateChatTitle } from '@/lib/copilot/chat-title'
12-
import { getCopilotModel } from '@/lib/copilot/config'
13-
import { COPILOT_MODEL_IDS, COPILOT_REQUEST_MODES } from '@/lib/copilot/models'
11+
import { SIM_AGENT_API_URL } from '@/lib/copilot/constants'
12+
import { COPILOT_REQUEST_MODES } from '@/lib/copilot/models'
1413
import { orchestrateCopilotStream } from '@/lib/copilot/orchestrator'
1514
import {
1615
createStreamEventWriter,
@@ -29,6 +28,49 @@ import { resolveWorkflowIdForUser } from '@/lib/workflows/utils'
2928

3029
const logger = createLogger('CopilotChatAPI')
3130

31+
async function requestChatTitleFromCopilot(params: {
32+
message: string
33+
model: string
34+
provider?: string
35+
}): Promise<string | null> {
36+
const { message, model, provider } = params
37+
if (!message || !model) return null
38+
39+
const headers: Record<string, string> = {
40+
'Content-Type': 'application/json',
41+
}
42+
if (env.COPILOT_API_KEY) {
43+
headers['x-api-key'] = env.COPILOT_API_KEY
44+
}
45+
46+
try {
47+
const response = await fetch(`${SIM_AGENT_API_URL}/api/generate-chat-title`, {
48+
method: 'POST',
49+
headers,
50+
body: JSON.stringify({
51+
message,
52+
model,
53+
...(provider ? { provider } : {}),
54+
}),
55+
})
56+
57+
const payload = await response.json().catch(() => ({}))
58+
if (!response.ok) {
59+
logger.warn('Failed to generate chat title via copilot backend', {
60+
status: response.status,
61+
error: payload,
62+
})
63+
return null
64+
}
65+
66+
const title = typeof payload?.title === 'string' ? payload.title.trim() : ''
67+
return title || null
68+
} catch (error) {
69+
logger.error('Error generating chat title:', error)
70+
return null
71+
}
72+
}
73+
3274
const FileAttachmentSchema = z.object({
3375
id: z.string(),
3476
key: z.string(),
@@ -43,14 +85,14 @@ const ChatMessageSchema = z.object({
4385
chatId: z.string().optional(),
4486
workflowId: z.string().optional(),
4587
workflowName: z.string().optional(),
46-
model: z.enum(COPILOT_MODEL_IDS).optional().default('claude-4.6-opus'),
88+
model: z.string().optional().default('claude-opus-4-6'),
4789
mode: z.enum(COPILOT_REQUEST_MODES).optional().default('agent'),
4890
prefetch: z.boolean().optional(),
4991
createNewChat: z.boolean().optional().default(false),
5092
stream: z.boolean().optional().default(true),
5193
implicitFeedback: z.string().optional(),
5294
fileAttachments: z.array(FileAttachmentSchema).optional(),
53-
provider: z.string().optional().default('openai'),
95+
provider: z.string().optional(),
5496
conversationId: z.string().optional(),
5597
contexts: z
5698
.array(
@@ -173,14 +215,14 @@ export async function POST(req: NextRequest) {
173215
let currentChat: any = null
174216
let conversationHistory: any[] = []
175217
let actualChatId = chatId
218+
const selectedModel = model || 'claude-opus-4-6'
176219

177220
if (chatId || createNewChat) {
178-
const defaultsForChatRow = getCopilotModel('chat')
179221
const chatResult = await resolveOrCreateChat({
180222
chatId,
181223
userId: authenticatedUserId,
182224
workflowId,
183-
model: defaultsForChatRow.model,
225+
model: selectedModel,
184226
})
185227
currentChat = chatResult.chat
186228
actualChatId = chatResult.chatId || chatId
@@ -191,8 +233,6 @@ export async function POST(req: NextRequest) {
191233
conversationHistory = history.history
192234
}
193235

194-
const defaults = getCopilotModel('chat')
195-
const selectedModel = model || defaults.model
196236
const effectiveMode = mode === 'agent' ? 'build' : mode
197237
const effectiveConversationId =
198238
(currentChat?.conversationId as string | undefined) || conversationId
@@ -205,6 +245,7 @@ export async function POST(req: NextRequest) {
205245
userMessageId: userMessageIdToUse,
206246
mode,
207247
model: selectedModel,
248+
provider,
208249
conversationHistory,
209250
contexts: agentContexts,
210251
fileAttachments,
@@ -283,7 +324,7 @@ export async function POST(req: NextRequest) {
283324
}
284325

285326
if (actualChatId && !currentChat?.title && conversationHistory.length === 0) {
286-
generateChatTitle(message)
327+
requestChatTitleFromCopilot({ message, model: selectedModel, provider })
287328
.then(async (title) => {
288329
if (title) {
289330
await db
@@ -372,10 +413,7 @@ export async function POST(req: NextRequest) {
372413
content: nonStreamingResult.content,
373414
toolCalls: nonStreamingResult.toolCalls,
374415
model: selectedModel,
375-
provider:
376-
(requestPayload?.provider as Record<string, unknown>)?.provider ||
377-
env.COPILOT_PROVIDER ||
378-
'openai',
416+
provider: typeof requestPayload?.provider === 'string' ? requestPayload.provider : undefined,
379417
}
380418

381419
logger.info(`[${tracker.requestId}] Non-streaming response from orchestrator:`, {
@@ -413,7 +451,7 @@ export async function POST(req: NextRequest) {
413451
// Start title generation in parallel if this is first message (non-streaming)
414452
if (actualChatId && !currentChat.title && conversationHistory.length === 0) {
415453
logger.info(`[${tracker.requestId}] Starting title generation for non-streaming response`)
416-
generateChatTitle(message)
454+
requestChatTitleFromCopilot({ message, model: selectedModel, provider })
417455
.then(async (title) => {
418456
if (title) {
419457
await db
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
import { createLogger } from '@sim/logger'
2+
import { type NextRequest, NextResponse } from 'next/server'
3+
import { SIM_AGENT_API_URL } from '@/lib/copilot/constants'
4+
import { authenticateCopilotRequestSessionOnly } from '@/lib/copilot/request-helpers'
5+
import type { AvailableModel } from '@/lib/copilot/types'
6+
import { env } from '@/lib/core/config/env'
7+
8+
const logger = createLogger('CopilotModelsAPI')
9+
10+
interface RawAvailableModel {
11+
id: string
12+
friendlyName?: string
13+
displayName?: string
14+
provider?: string
15+
}
16+
17+
function isRawAvailableModel(item: unknown): item is RawAvailableModel {
18+
return (
19+
typeof item === 'object' &&
20+
item !== null &&
21+
'id' in item &&
22+
typeof (item as { id: unknown }).id === 'string'
23+
)
24+
}
25+
26+
export async function GET(_req: NextRequest) {
27+
const { userId, isAuthenticated } = await authenticateCopilotRequestSessionOnly()
28+
if (!isAuthenticated || !userId) {
29+
return NextResponse.json({ error: 'Unauthorized' }, { status: 401 })
30+
}
31+
32+
const headers: Record<string, string> = {
33+
'Content-Type': 'application/json',
34+
}
35+
if (env.COPILOT_API_KEY) {
36+
headers['x-api-key'] = env.COPILOT_API_KEY
37+
}
38+
39+
try {
40+
const response = await fetch(`${SIM_AGENT_API_URL}/api/get-available-models`, {
41+
method: 'GET',
42+
headers,
43+
cache: 'no-store',
44+
})
45+
46+
const payload = await response.json().catch(() => ({}))
47+
if (!response.ok) {
48+
logger.warn('Failed to fetch available models from copilot backend', {
49+
status: response.status,
50+
})
51+
return NextResponse.json(
52+
{
53+
success: false,
54+
error: payload?.error || 'Failed to fetch available models',
55+
models: [],
56+
},
57+
{ status: response.status }
58+
)
59+
}
60+
61+
const rawModels = Array.isArray(payload?.models) ? payload.models : []
62+
const models: AvailableModel[] = rawModels
63+
.filter((item: unknown): item is RawAvailableModel => isRawAvailableModel(item))
64+
.map((item: RawAvailableModel) => ({
65+
id: item.id,
66+
friendlyName: item.friendlyName || item.displayName || item.id,
67+
provider: item.provider || 'unknown',
68+
}))
69+
70+
return NextResponse.json({ success: true, models })
71+
} catch (error) {
72+
logger.error('Error fetching available models', {
73+
error: error instanceof Error ? error.message : String(error),
74+
})
75+
return NextResponse.json(
76+
{
77+
success: false,
78+
error: 'Failed to fetch available models',
79+
models: [],
80+
},
81+
{ status: 500 }
82+
)
83+
}
84+
}

apps/sim/app/api/copilot/user-models/route.ts

Lines changed: 0 additions & 139 deletions
This file was deleted.

0 commit comments

Comments
 (0)