Skip to content

Commit 2bc181d

Browse files
committed
Fix block id edit, slash commands at end, thinking tag resolution, add continue button
1 parent 5db5c1c commit 2bc181d

File tree

10 files changed

+268
-310
lines changed

10 files changed

+268
-310
lines changed

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

Lines changed: 15 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import { z } from 'zod'
77
import { getSession } from '@/lib/auth'
88
import { generateChatTitle } from '@/lib/copilot/chat-title'
99
import { getCopilotModel } from '@/lib/copilot/config'
10+
import { COPILOT_MODEL_IDS, COPILOT_REQUEST_MODES } from '@/lib/copilot/models'
1011
import { SIM_AGENT_API_URL_DEFAULT, SIM_AGENT_VERSION } from '@/lib/copilot/constants'
1112
import {
1213
authenticateCopilotRequestSessionOnly,
@@ -40,34 +41,8 @@ const ChatMessageSchema = z.object({
4041
userMessageId: z.string().optional(), // ID from frontend for the user message
4142
chatId: z.string().optional(),
4243
workflowId: z.string().min(1, 'Workflow ID is required'),
43-
model: z
44-
.enum([
45-
'gpt-5-fast',
46-
'gpt-5',
47-
'gpt-5-medium',
48-
'gpt-5-high',
49-
'gpt-5.1-fast',
50-
'gpt-5.1',
51-
'gpt-5.1-medium',
52-
'gpt-5.1-high',
53-
'gpt-5-codex',
54-
'gpt-5.1-codex',
55-
'gpt-5.2',
56-
'gpt-5.2-codex',
57-
'gpt-5.2-pro',
58-
'gpt-4o',
59-
'gpt-4.1',
60-
'o3',
61-
'claude-4-sonnet',
62-
'claude-4.5-haiku',
63-
'claude-4.5-sonnet',
64-
'claude-4.5-opus',
65-
'claude-4.1-opus',
66-
'gemini-3-pro',
67-
])
68-
.optional()
69-
.default('claude-4.5-opus'),
70-
mode: z.enum(['ask', 'agent', 'plan']).optional().default('agent'),
44+
model: z.enum(COPILOT_MODEL_IDS).optional().default('claude-4.5-opus'),
45+
mode: z.enum(COPILOT_REQUEST_MODES).optional().default('agent'),
7146
prefetch: z.boolean().optional(),
7247
createNewChat: z.boolean().optional().default(false),
7348
stream: z.boolean().optional().default(true),
@@ -295,7 +270,8 @@ export async function POST(req: NextRequest) {
295270
}
296271

297272
const defaults = getCopilotModel('chat')
298-
const modelToUse = env.COPILOT_MODEL || defaults.model
273+
const selectedModel = model || defaults.model
274+
const envModel = env.COPILOT_MODEL || defaults.model
299275

300276
let providerConfig: CopilotProviderConfig | undefined
301277
const providerEnv = env.COPILOT_PROVIDER as any
@@ -304,28 +280,31 @@ export async function POST(req: NextRequest) {
304280
if (providerEnv === 'azure-openai') {
305281
providerConfig = {
306282
provider: 'azure-openai',
307-
model: modelToUse,
283+
model: envModel,
308284
apiKey: env.AZURE_OPENAI_API_KEY,
309285
apiVersion: 'preview',
310286
endpoint: env.AZURE_OPENAI_ENDPOINT,
311287
}
312288
} else if (providerEnv === 'vertex') {
313289
providerConfig = {
314290
provider: 'vertex',
315-
model: modelToUse,
291+
model: envModel,
316292
apiKey: env.COPILOT_API_KEY,
317293
vertexProject: env.VERTEX_PROJECT,
318294
vertexLocation: env.VERTEX_LOCATION,
319295
}
320296
} else {
321297
providerConfig = {
322298
provider: providerEnv,
323-
model: modelToUse,
299+
model: selectedModel,
324300
apiKey: env.COPILOT_API_KEY,
325301
}
326302
}
327303
}
328304

305+
const effectiveMode = mode === 'agent' ? 'build' : mode
306+
const transportMode = effectiveMode === 'build' ? 'agent' : effectiveMode
307+
329308
// Determine conversationId to use for this request
330309
const effectiveConversationId =
331310
(currentChat?.conversationId as string | undefined) || conversationId
@@ -345,7 +324,7 @@ export async function POST(req: NextRequest) {
345324
}
346325
} | null = null
347326

348-
if (mode === 'agent') {
327+
if (effectiveMode === 'build') {
349328
// Build base tools (executed locally, not deferred)
350329
// Include function_execute for code execution capability
351330
baseTools = [
@@ -452,8 +431,8 @@ export async function POST(req: NextRequest) {
452431
userId: authenticatedUserId,
453432
stream: stream,
454433
streamToolCalls: true,
455-
model: model,
456-
mode: mode,
434+
model: selectedModel,
435+
mode: transportMode,
457436
messageId: userMessageIdToUse,
458437
version: SIM_AGENT_VERSION,
459438
...(providerConfig ? { provider: providerConfig } : {}),
@@ -477,7 +456,7 @@ export async function POST(req: NextRequest) {
477456
hasConversationId: !!effectiveConversationId,
478457
hasFileAttachments: processedFileContents.length > 0,
479458
messageLength: message.length,
480-
mode,
459+
mode: effectiveMode,
481460
hasTools: integrationTools.length > 0,
482461
toolCount: integrationTools.length,
483462
hasBaseTools: baseTools.length > 0,

apps/sim/app/api/copilot/chat/update-messages/route.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import {
1111
createRequestTracker,
1212
createUnauthorizedResponse,
1313
} from '@/lib/copilot/request-helpers'
14+
import { COPILOT_MODES } from '@/lib/copilot/models'
1415

1516
const logger = createLogger('CopilotChatUpdateAPI')
1617

@@ -45,7 +46,7 @@ const UpdateMessagesSchema = z.object({
4546
planArtifact: z.string().nullable().optional(),
4647
config: z
4748
.object({
48-
mode: z.enum(['ask', 'build', 'plan']).optional(),
49+
mode: z.enum(COPILOT_MODES).optional(),
4950
model: z.string().optional(),
5051
})
5152
.nullable()

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

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,13 @@ import { createLogger } from '@sim/logger'
22
import { eq } from 'drizzle-orm'
33
import { type NextRequest, NextResponse } from 'next/server'
44
import { getSession } from '@/lib/auth'
5+
import type { CopilotModelId } from '@/lib/copilot/models'
56
import { db } from '@/../../packages/db'
67
import { settings } from '@/../../packages/db/schema'
78

89
const logger = createLogger('CopilotUserModelsAPI')
910

10-
const DEFAULT_ENABLED_MODELS: Record<string, boolean> = {
11+
const DEFAULT_ENABLED_MODELS: Record<CopilotModelId, boolean> = {
1112
'gpt-4o': false,
1213
'gpt-4.1': false,
1314
'gpt-5-fast': false,
@@ -28,7 +29,7 @@ const DEFAULT_ENABLED_MODELS: Record<string, boolean> = {
2829
'claude-4.5-haiku': true,
2930
'claude-4.5-sonnet': true,
3031
'claude-4.5-opus': true,
31-
// 'claude-4.1-opus': true,
32+
'claude-4.1-opus': false,
3233
'gemini-3-pro': true,
3334
}
3435

@@ -54,7 +55,9 @@ export async function GET(request: NextRequest) {
5455

5556
const mergedModels = { ...DEFAULT_ENABLED_MODELS }
5657
for (const [modelId, enabled] of Object.entries(userModelsMap)) {
57-
mergedModels[modelId] = enabled
58+
if (modelId in mergedModels) {
59+
mergedModels[modelId as CopilotModelId] = enabled
60+
}
5861
}
5962

6063
const hasNewModels = Object.keys(DEFAULT_ENABLED_MODELS).some(

apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/copilot/components/tool-call/tool-call.tsx

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1446,8 +1446,10 @@ function WorkflowEditSummary({ toolCall }: { toolCall: CopilotToolCall }) {
14461446
blockType = blockType || op.block_type || ''
14471447
}
14481448

1449-
// Fallback name to type or ID
1450-
if (!blockName) blockName = blockType || blockId
1449+
if (!blockName) blockName = blockType || ''
1450+
if (!blockName && !blockType) {
1451+
continue
1452+
}
14511453

14521454
const change: BlockChange = { blockId, blockName, blockType }
14531455

apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/copilot/components/user-input/hooks/use-context-management.ts

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,9 @@ interface UseContextManagementProps {
2222
export function useContextManagement({ message, initialContexts }: UseContextManagementProps) {
2323
const [selectedContexts, setSelectedContexts] = useState<ChatContext[]>(initialContexts ?? [])
2424
const initializedRef = useRef(false)
25+
const escapeRegex = useCallback((value: string) => {
26+
return value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')
27+
}, [])
2528

2629
// Initialize with initial contexts when they're first provided (for edit mode)
2730
useEffect(() => {
@@ -78,10 +81,8 @@ export function useContextManagement({ message, initialContexts }: UseContextMan
7881
// Check for slash command tokens or mention tokens based on kind
7982
const isSlashCommand = c.kind === 'slash_command'
8083
const prefix = isSlashCommand ? '/' : '@'
81-
const tokenWithSpaces = ` ${prefix}${c.label} `
82-
const tokenAtStart = `${prefix}${c.label} `
83-
// Token can appear with leading space OR at the start of the message
84-
return message.includes(tokenWithSpaces) || message.startsWith(tokenAtStart)
84+
const tokenPattern = new RegExp(`(^|\\s)${escapeRegex(prefix)}${escapeRegex(c.label)}(\\s|$)`)
85+
return tokenPattern.test(message)
8586
})
8687
return filtered.length === prev.length ? prev : filtered
8788
})

apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/copilot/components/user-input/hooks/use-mention-tokens.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,15 @@ export function useMentionTokens({
7676
ranges.push({ start: idx, end: idx + token.length, label })
7777
fromIndex = idx + token.length
7878
}
79+
80+
// Token at end of message without trailing space: "@label" or " /label"
81+
const tokenAtEnd = `${prefix}${label}`
82+
if (message.endsWith(tokenAtEnd)) {
83+
const idx = message.lastIndexOf(tokenAtEnd)
84+
const hasLeadingSpace = idx > 0 && message[idx - 1] === ' '
85+
const start = hasLeadingSpace ? idx - 1 : idx
86+
ranges.push({ start, end: message.length, label })
87+
}
7988
}
8089

8190
ranges.sort((a, b) => a.start - b.start)

apps/sim/lib/copilot/api.ts

Lines changed: 9 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,9 @@
11
import { createLogger } from '@sim/logger'
2+
import type {
3+
CopilotMode,
4+
CopilotModelId,
5+
CopilotTransportMode,
6+
} from '@/lib/copilot/models'
27

38
const logger = createLogger('CopilotAPI')
49

@@ -27,8 +32,8 @@ export interface CopilotMessage {
2732
* Chat config stored in database
2833
*/
2934
export interface CopilotChatConfig {
30-
mode?: 'ask' | 'build' | 'plan'
31-
model?: string
35+
mode?: CopilotMode
36+
model?: CopilotModelId
3237
}
3338

3439
/**
@@ -65,30 +70,8 @@ export interface SendMessageRequest {
6570
userMessageId?: string // ID from frontend for the user message
6671
chatId?: string
6772
workflowId?: string
68-
mode?: 'ask' | 'agent' | 'plan'
69-
model?:
70-
| 'gpt-5-fast'
71-
| 'gpt-5'
72-
| 'gpt-5-medium'
73-
| 'gpt-5-high'
74-
| 'gpt-5.1-fast'
75-
| 'gpt-5.1'
76-
| 'gpt-5.1-medium'
77-
| 'gpt-5.1-high'
78-
| 'gpt-5-codex'
79-
| 'gpt-5.1-codex'
80-
| 'gpt-5.2'
81-
| 'gpt-5.2-codex'
82-
| 'gpt-5.2-pro'
83-
| 'gpt-4o'
84-
| 'gpt-4.1'
85-
| 'o3'
86-
| 'claude-4-sonnet'
87-
| 'claude-4.5-haiku'
88-
| 'claude-4.5-sonnet'
89-
| 'claude-4.5-opus'
90-
| 'claude-4.1-opus'
91-
| 'gemini-3-pro'
73+
mode?: CopilotMode | CopilotTransportMode
74+
model?: CopilotModelId
9275
prefetch?: boolean
9376
createNewChat?: boolean
9477
stream?: boolean

apps/sim/lib/copilot/models.ts

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
export const COPILOT_MODEL_IDS = [
2+
'gpt-5-fast',
3+
'gpt-5',
4+
'gpt-5-medium',
5+
'gpt-5-high',
6+
'gpt-5.1-fast',
7+
'gpt-5.1',
8+
'gpt-5.1-medium',
9+
'gpt-5.1-high',
10+
'gpt-5-codex',
11+
'gpt-5.1-codex',
12+
'gpt-5.2',
13+
'gpt-5.2-codex',
14+
'gpt-5.2-pro',
15+
'gpt-4o',
16+
'gpt-4.1',
17+
'o3',
18+
'claude-4-sonnet',
19+
'claude-4.5-haiku',
20+
'claude-4.5-sonnet',
21+
'claude-4.5-opus',
22+
'claude-4.1-opus',
23+
'gemini-3-pro',
24+
] as const
25+
26+
export type CopilotModelId = (typeof COPILOT_MODEL_IDS)[number]
27+
28+
export const COPILOT_MODES = ['ask', 'build', 'plan'] as const
29+
export type CopilotMode = (typeof COPILOT_MODES)[number]
30+
31+
export const COPILOT_TRANSPORT_MODES = ['ask', 'agent', 'plan'] as const
32+
export type CopilotTransportMode = (typeof COPILOT_TRANSPORT_MODES)[number]
33+
34+
export const COPILOT_REQUEST_MODES = ['ask', 'build', 'plan', 'agent'] as const
35+
export type CopilotRequestMode = (typeof COPILOT_REQUEST_MODES)[number]
36+

0 commit comments

Comments
 (0)