Skip to content

Commit 8027afc

Browse files
refactor(cli): remove unrelated Copilot changes
1 parent 18fc377 commit 8027afc

67 files changed

Lines changed: 433 additions & 3031 deletions

Some content is hidden

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

apps/docs/openapi-core.json

Lines changed: 5 additions & 752 deletions
Large diffs are not rendered by default.

apps/sim/app/api/knowledge/utils.test.ts

Lines changed: 15 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -234,16 +234,6 @@ describe('Knowledge Utils', () => {
234234
expect(result.hasAccess).toBe(false)
235235
expect('notFound' in result && result.notFound).toBe(true)
236236
})
237-
238-
it('treats a knowledge base outside the trusted workspace as not found', async () => {
239-
queueTableRows(schemaMock.knowledgeBase, [
240-
{ id: 'kb1', userId: 'user1', workspaceId: 'workspace-2' },
241-
])
242-
243-
const result = await checkKnowledgeBaseAccess('kb1', 'user1', 'workspace-1')
244-
245-
expect(result).toEqual({ hasAccess: false, notFound: true })
246-
})
247237
})
248238

249239
describe('checkDocumentAccess', () => {
@@ -363,17 +353,23 @@ describe('Knowledge Utils', () => {
363353
it('should throw error when no API configuration provided', async () => {
364354
const { env } = await import('@/lib/core/config/env')
365355
Object.keys(env).forEach((key) => delete (env as any)[key])
366-
Object.assign(env, {
367-
OPENAI_API_KEY: undefined,
368-
OPENAI_API_KEY_1: undefined,
369-
OPENAI_API_KEY_2: undefined,
370-
OPENAI_API_KEY_3: undefined,
371-
OPENROUTER_API_KEY: undefined,
356+
// The env object lazily reads process.env, so a developer's local .env
357+
// keys survive the deletion above — stub the direct key empty and fail
358+
// the hosted rotation fallback for hermeticity on any machine.
359+
vi.stubEnv('OPENAI_API_KEY', '')
360+
const apiKeysModule = await import('@/lib/core/config/api-keys')
361+
const rotationSpy = vi.spyOn(apiKeysModule, 'getRotatingApiKey').mockImplementation(() => {
362+
throw new Error('No rotation keys configured')
372363
})
373364

374-
await expect(generateEmbeddings(['test text'])).rejects.toThrow(
375-
'OPENAI_API_KEY is not configured'
376-
)
365+
try {
366+
await expect(generateEmbeddings(['test text'])).rejects.toThrow(
367+
'OPENAI_API_KEY is not configured'
368+
)
369+
} finally {
370+
rotationSpy.mockRestore()
371+
vi.unstubAllEnvs()
372+
}
377373
})
378374
})
379375
})

apps/sim/app/api/knowledge/utils.ts

Lines changed: 11 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -163,8 +163,7 @@ export type ChunkAccessCheck = ChunkAccessResult | ChunkAccessDenied
163163
async function resolveKnowledgeBaseAccess(
164164
knowledgeBaseId: string,
165165
userId: string,
166-
requireWrite: boolean,
167-
workspaceId?: string
166+
requireWrite: boolean
168167
): Promise<KnowledgeBaseAccessCheck> {
169168
const kb = await db
170169
.select({
@@ -184,10 +183,6 @@ async function resolveKnowledgeBaseAccess(
184183

185184
const kbData = kb[0]
186185

187-
if (workspaceId && kbData.workspaceId !== workspaceId) {
188-
return { hasAccess: false, notFound: true }
189-
}
190-
191186
if (kbData.workspaceId) {
192187
// Workspace KB: use workspace permissions only
193188
const userPermission = await getUserEntityPermissions(userId, 'workspace', kbData.workspaceId)
@@ -210,10 +205,9 @@ async function resolveKnowledgeBaseAccess(
210205
*/
211206
export async function checkKnowledgeBaseAccess(
212207
knowledgeBaseId: string,
213-
userId: string,
214-
workspaceId?: string
208+
userId: string
215209
): Promise<KnowledgeBaseAccessCheck> {
216-
return resolveKnowledgeBaseAccess(knowledgeBaseId, userId, false, workspaceId)
210+
return resolveKnowledgeBaseAccess(knowledgeBaseId, userId, false)
217211
}
218212

219213
/**
@@ -225,10 +219,9 @@ export async function checkKnowledgeBaseAccess(
225219
*/
226220
export async function checkKnowledgeBaseWriteAccess(
227221
knowledgeBaseId: string,
228-
userId: string,
229-
workspaceId?: string
222+
userId: string
230223
): Promise<KnowledgeBaseAccessCheck> {
231-
return resolveKnowledgeBaseAccess(knowledgeBaseId, userId, true, workspaceId)
224+
return resolveKnowledgeBaseAccess(knowledgeBaseId, userId, true)
232225
}
233226

234227
/**
@@ -239,15 +232,9 @@ async function resolveDocumentAccess(
239232
knowledgeBaseId: string,
240233
documentId: string,
241234
userId: string,
242-
requireWrite: boolean,
243-
workspaceId?: string
235+
requireWrite: boolean
244236
): Promise<DocumentAccessCheck> {
245-
const kbAccess = await resolveKnowledgeBaseAccess(
246-
knowledgeBaseId,
247-
userId,
248-
requireWrite,
249-
workspaceId
250-
)
237+
const kbAccess = await resolveKnowledgeBaseAccess(knowledgeBaseId, userId, requireWrite)
251238

252239
if (!kbAccess.hasAccess) {
253240
return {
@@ -275,10 +262,9 @@ async function resolveDocumentAccess(
275262
export async function checkDocumentAccess(
276263
knowledgeBaseId: string,
277264
documentId: string,
278-
userId: string,
279-
workspaceId?: string
265+
userId: string
280266
): Promise<DocumentAccessCheck> {
281-
return resolveDocumentAccess(knowledgeBaseId, documentId, userId, false, workspaceId)
267+
return resolveDocumentAccess(knowledgeBaseId, documentId, userId, false)
282268
}
283269

284270
/**
@@ -288,10 +274,9 @@ export async function checkDocumentAccess(
288274
export async function checkDocumentWriteAccess(
289275
knowledgeBaseId: string,
290276
documentId: string,
291-
userId: string,
292-
workspaceId?: string
277+
userId: string
293278
): Promise<DocumentAccessCheck> {
294-
return resolveDocumentAccess(knowledgeBaseId, documentId, userId, true, workspaceId)
279+
return resolveDocumentAccess(knowledgeBaseId, documentId, userId, true)
295280
}
296281

297282
/**

apps/sim/app/workspace/[workspaceId]/home/types.ts

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@ export type {
99
MothershipResourceType,
1010
WorkspaceResourceRef,
1111
} from '@/lib/copilot/resources/types'
12-
export { SUBAGENT_LABELS } from '@/lib/copilot/tools/subagent-display'
1312

1413
/** Union of all valid context kind strings, derived from {@link ChatContext}. */
1514
export type ChatContextKind = ChatContext['kind']
@@ -178,3 +177,24 @@ export interface ChatMessage {
178177
contexts?: ChatMessageContext[]
179178
requestId?: string
180179
}
180+
181+
export const SUBAGENT_LABELS: Record<string, string> = {
182+
workflow: 'Workflow Agent',
183+
debug: 'Debug Agent',
184+
deploy: 'Deploy Agent',
185+
auth: 'Auth Agent',
186+
research: 'Research Agent',
187+
knowledge: 'Knowledge Agent',
188+
table: 'Table Agent',
189+
custom_tool: 'Custom Tool Agent',
190+
scout: 'Scout Agent',
191+
search: 'Search Agent',
192+
superagent: 'Superagent',
193+
run: 'Run Agent',
194+
agent: 'Tools Agent',
195+
// `job` retained as a backward-compat alias so historical transcripts still render a label.
196+
job: 'Job Agent',
197+
file: 'File Agent',
198+
media: 'Media Agent',
199+
browser: 'Browser Agent',
200+
} as const

apps/sim/lib/copilot/async-runs/repository.test.ts

Lines changed: 0 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ import {
1111
completeAsyncToolCall,
1212
detachAsyncToolCall,
1313
getClaimedWorkflowExecutionId,
14-
markAsyncToolRunning,
1514
recordToolPermissionDecision,
1615
releaseWorkflowToolExecutionClaim,
1716
replaceTerminalAsyncToolCallResult,
@@ -133,27 +132,6 @@ describe('async tool repository single-row semantics', () => {
133132
)
134133
})
135134

136-
it('marks a Sim tool running only while its durable row is still live', async () => {
137-
dbChainMockFns.returning.mockResolvedValueOnce([
138-
{
139-
toolCallId: 'sim-tool',
140-
status: 'running',
141-
claimedBy: 'sim-stream',
142-
},
143-
])
144-
145-
await markAsyncToolRunning('sim-tool', 'sim-stream')
146-
147-
const predicate = dbChainMockFns.where.mock.calls.at(-1)?.[0]
148-
expect(predicate).toEqual({
149-
type: 'and',
150-
conditions: [
151-
expect.objectContaining({ type: 'eq', right: 'sim-tool' }),
152-
expect.objectContaining({ type: 'inArray', values: ['pending', 'running'] }),
153-
],
154-
})
155-
})
156-
157135
it('atomically binds an eligible workflow tool to one execution', async () => {
158136
dbChainMockFns.returning.mockResolvedValueOnce([
159137
{

apps/sim/lib/copilot/async-runs/repository.ts

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -329,10 +329,7 @@ async function markAsyncToolStatus(
329329
}
330330

331331
export async function markAsyncToolRunning(toolCallId: string, claimedBy: string) {
332-
return markAsyncToolStatus(toolCallId, ASYNC_TOOL_STATUS.running, { claimedBy }, [
333-
ASYNC_TOOL_STATUS.pending,
334-
ASYNC_TOOL_STATUS.running,
335-
])
332+
return markAsyncToolStatus(toolCallId, 'running', { claimedBy })
336333
}
337334

338335
export function getClaimedWorkflowExecutionId(claimedBy: string | null | undefined) {

apps/sim/lib/copilot/chat/lifecycle.test.ts

Lines changed: 0 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@ vi.mock('@/lib/workspaces/permissions/utils', () => ({
2121

2222
import {
2323
getAccessibleCopilotChat,
24-
getAccessibleCopilotChatContinuationMetadata,
2524
getAccessibleCopilotChatWithMessages,
2625
resolveOrCreateChat,
2726
} from '@/lib/copilot/chat/lifecycle'
@@ -107,59 +106,6 @@ describe('lifecycle copilot chat reads (cutover to copilot_messages)', () => {
107106
expect(result?.messages).toEqual([])
108107
})
109108

110-
it('loads continuation metadata with a one-row probe and contexts-only MCP projection', async () => {
111-
const continuationRow = {
112-
id: chatRow.id,
113-
userId: chatRow.userId,
114-
workflowId: chatRow.workflowId,
115-
workspaceId: chatRow.workspaceId,
116-
type: chatRow.type,
117-
title: chatRow.title,
118-
}
119-
dbChainMockFns.limit
120-
.mockResolvedValueOnce([continuationRow])
121-
.mockResolvedValueOnce([{ id: 'message-1' }])
122-
dbChainMockFns.orderBy.mockResolvedValueOnce([
123-
{
124-
contexts: [
125-
{ kind: 'mcp', serverId: 'mcp-docs', label: 'Docs' },
126-
{ kind: 'skill', skillId: 'skill-review', label: 'Review' },
127-
],
128-
},
129-
{ contexts: [{ kind: 'mcp', serverId: 'mcp-docs', label: 'Docs again' }] },
130-
{ contexts: [{ kind: 'mcp', serverId: 'mcp-issues', label: 'Issues' }] },
131-
])
132-
133-
const result = await getAccessibleCopilotChatContinuationMetadata(CHAT_ID, USER_ID)
134-
135-
expect(result).toEqual({
136-
...continuationRow,
137-
hasMessages: true,
138-
mcpServerIds: ['mcp-docs', 'mcp-issues'],
139-
})
140-
expect(dbChainMockFns.limit).toHaveBeenCalledTimes(2)
141-
expect(dbChainMockFns.orderBy).toHaveBeenCalledTimes(1)
142-
const contextsProjection = dbChainMockFns.select.mock.calls[2]?.[0] as Record<string, unknown>
143-
expect(Object.keys(contextsProjection)).toEqual(['contexts'])
144-
})
145-
146-
it('skips the MCP projection for an empty persisted chat', async () => {
147-
const continuationRow = {
148-
id: chatRow.id,
149-
userId: chatRow.userId,
150-
workflowId: chatRow.workflowId,
151-
workspaceId: chatRow.workspaceId,
152-
type: chatRow.type,
153-
title: chatRow.title,
154-
}
155-
dbChainMockFns.limit.mockResolvedValueOnce([continuationRow]).mockResolvedValueOnce([])
156-
157-
const result = await getAccessibleCopilotChatContinuationMetadata(CHAT_ID, USER_ID)
158-
159-
expect(result).toEqual({ ...continuationRow, hasMessages: false, mcpServerIds: [] })
160-
expect(dbChainMockFns.orderBy).not.toHaveBeenCalled()
161-
})
162-
163109
it('returns null and does NOT query messages when the chat is not found', async () => {
164110
dbChainMockFns.limit.mockResolvedValueOnce([])
165111

apps/sim/lib/copilot/chat/lifecycle.ts

Lines changed: 1 addition & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,7 @@ import {
66
getActiveWorkflowRecord,
77
} from '@sim/platform-authz/workflow'
88
import { and, asc, eq, isNull, sql } from 'drizzle-orm'
9-
import {
10-
collectChatMcpServerIds,
11-
type PersistedMessage,
12-
stripToolResultOutput,
13-
} from '@/lib/copilot/chat/persisted-message'
9+
import { type PersistedMessage, stripToolResultOutput } from '@/lib/copilot/chat/persisted-message'
1410
import {
1511
assertActiveWorkspaceAccess,
1612
checkWorkspaceAccess,
@@ -39,11 +35,6 @@ const copilotChatAuthColumns = {
3935
type: copilotChats.type,
4036
} as const
4137

42-
const copilotChatContinuationColumns = {
43-
...copilotChatAuthColumns,
44-
title: copilotChats.title,
45-
} as const
46-
4738
/**
4839
* Column set for chat-detail callers that need chat metadata. The conversation
4940
* transcript is no longer selected from `copilot_chats.messages` (JSONB) —
@@ -112,12 +103,6 @@ type CopilotChatAuthRow = Pick<
112103
'id' | 'userId' | 'workflowId' | 'workspaceId' | 'type'
113104
>
114105

115-
export type CopilotChatContinuationMetadata = CopilotChatAuthRow & {
116-
title: string | null
117-
hasMessages: boolean
118-
mcpServerIds: string[]
119-
}
120-
121106
export type CopilotChatDetailRow = Pick<
122107
typeof copilotChats.$inferSelect,
123108
| 'id'
@@ -196,57 +181,6 @@ export async function getAccessibleCopilotChatAuth(
196181
return authorizeCopilotChatRow(chat, chatId, userId)
197182
}
198183

199-
/**
200-
* Loads only the authorized metadata needed to continue a persisted chat. The
201-
* one-row existence probe preserves first-turn title behavior, while the MCP
202-
* query projects only user-message context arrays. Assistant/tool content is
203-
* never loaded or normalized.
204-
*/
205-
export async function getAccessibleCopilotChatContinuationMetadata(
206-
chatId: string,
207-
userId: string
208-
): Promise<CopilotChatContinuationMetadata | null> {
209-
const [chat] = await db
210-
.select(copilotChatContinuationColumns)
211-
.from(copilotChats)
212-
.where(ownedLiveChatWhere(chatId, userId))
213-
.limit(1)
214-
215-
const authorized = await authorizeCopilotChatRow(chat, chatId, userId)
216-
if (!authorized) return null
217-
218-
const [message] = await db
219-
.select({ id: copilotMessages.id })
220-
.from(copilotMessages)
221-
.where(and(eq(copilotMessages.chatId, chatId), isNull(copilotMessages.deletedAt)))
222-
.limit(1)
223-
224-
if (!message) return { ...authorized, hasMessages: false, mcpServerIds: [] }
225-
226-
const contextRows = await db
227-
.select({ contexts: sql<unknown>`${copilotMessages.content} -> 'contexts'` })
228-
.from(copilotMessages)
229-
.where(
230-
and(
231-
eq(copilotMessages.chatId, chatId),
232-
eq(copilotMessages.role, 'user'),
233-
isNull(copilotMessages.deletedAt),
234-
sql`${copilotMessages.content} ? 'contexts'`
235-
)
236-
)
237-
.orderBy(
238-
sql`${copilotMessages.seq} asc nulls last`,
239-
asc(copilotMessages.createdAt),
240-
asc(copilotMessages.id)
241-
)
242-
243-
return {
244-
...authorized,
245-
hasMessages: true,
246-
mcpServerIds: collectChatMcpServerIds(contextRows),
247-
}
248-
}
249-
250184
/**
251185
* Load a copilot chat row for the legacy chat detail endpoint, including the
252186
* transcript plus `model` and `config`. Drops `previewYaml`

0 commit comments

Comments
 (0)