Skip to content

Commit 62a351a

Browse files
committed
Fix
1 parent 8aa203c commit 62a351a

39 files changed

+4820
-5811
lines changed

apps/sim/app/api/billing/update-cost/route.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,13 +42,13 @@ export async function POST(req: NextRequest) {
4242
'http.method': 'POST',
4343
'http.route': '/api/billing/update-cost',
4444
},
45-
async (span) => updateCostInner(req, span),
45+
async (span) => updateCostInner(req, span)
4646
)
4747
}
4848

4949
async function updateCostInner(
5050
req: NextRequest,
51-
span: import('@opentelemetry/api').Span,
51+
span: import('@opentelemetry/api').Span
5252
): Promise<NextResponse> {
5353
const requestId = generateRequestId()
5454
const startTime = Date.now()

apps/sim/app/api/copilot/api-keys/validate/route.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,6 @@ export async function POST(req: NextRequest) {
9393
span.setAttribute('http.status_code', 500)
9494
return NextResponse.json({ error: 'Failed to validate usage' }, { status: 500 })
9595
}
96-
},
96+
}
9797
)
9898
}

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

Lines changed: 105 additions & 113 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,12 @@
22
* @vitest-environment node
33
*/
44

5-
import { NextRequest } from "next/server";
6-
import { beforeEach, describe, expect, it, vi } from "vitest";
5+
import { NextRequest } from 'next/server'
6+
import { beforeEach, describe, expect, it, vi } from 'vitest'
77
import {
88
MothershipStreamV1CompletionStatus,
99
MothershipStreamV1EventType,
10-
} from "@/lib/copilot/generated/mothership-stream-v1";
10+
} from '@/lib/copilot/generated/mothership-stream-v1'
1111

1212
const {
1313
getLatestRunForStream,
@@ -21,13 +21,13 @@ const {
2121
readFilePreviewSessions: vi.fn(),
2222
checkForReplayGap: vi.fn(),
2323
authenticateCopilotRequestSessionOnly: vi.fn(),
24-
}));
24+
}))
2525

26-
vi.mock("@/lib/copilot/async-runs/repository", () => ({
26+
vi.mock('@/lib/copilot/async-runs/repository', () => ({
2727
getLatestRunForStream,
28-
}));
28+
}))
2929

30-
vi.mock("@/lib/copilot/request/session", () => ({
30+
vi.mock('@/lib/copilot/request/session', () => ({
3131
readEvents,
3232
readFilePreviewSessions,
3333
checkForReplayGap,
@@ -37,180 +37,172 @@ vi.mock("@/lib/copilot/request/session", () => ({
3737
cursor: event.cursor,
3838
},
3939
seq: event.seq,
40-
trace: { requestId: event.requestId ?? "" },
40+
trace: { requestId: event.requestId ?? '' },
4141
type: event.type,
4242
payload: event.payload,
4343
}),
4444
encodeSSEEnvelope: (event: Record<string, unknown>) =>
4545
new TextEncoder().encode(`data: ${JSON.stringify(event)}\n\n`),
4646
SSE_RESPONSE_HEADERS: {
47-
"Content-Type": "text/event-stream",
47+
'Content-Type': 'text/event-stream',
4848
},
49-
}));
49+
}))
5050

51-
vi.mock("@/lib/copilot/request/http", () => ({
51+
vi.mock('@/lib/copilot/request/http', () => ({
5252
authenticateCopilotRequestSessionOnly,
53-
}));
53+
}))
5454

55-
import { GET } from "./route";
55+
import { GET } from './route'
5656

5757
async function readAllChunks(response: Response): Promise<string[]> {
58-
const reader = response.body?.getReader();
59-
expect(reader).toBeTruthy();
58+
const reader = response.body?.getReader()
59+
expect(reader).toBeTruthy()
6060

61-
const chunks: string[] = [];
61+
const chunks: string[] = []
6262
while (true) {
63-
const { done, value } = await reader!.read();
63+
const { done, value } = await reader!.read()
6464
if (done) {
65-
break;
65+
break
6666
}
67-
chunks.push(new TextDecoder().decode(value));
67+
chunks.push(new TextDecoder().decode(value))
6868
}
69-
return chunks;
69+
return chunks
7070
}
7171

72-
describe("copilot chat stream replay route", () => {
72+
describe('copilot chat stream replay route', () => {
7373
beforeEach(() => {
74-
vi.clearAllMocks();
74+
vi.clearAllMocks()
7575
authenticateCopilotRequestSessionOnly.mockResolvedValue({
76-
userId: "user-1",
76+
userId: 'user-1',
7777
isAuthenticated: true,
78-
});
79-
readEvents.mockResolvedValue([]);
80-
readFilePreviewSessions.mockResolvedValue([]);
81-
checkForReplayGap.mockResolvedValue(null);
82-
});
78+
})
79+
readEvents.mockResolvedValue([])
80+
readFilePreviewSessions.mockResolvedValue([])
81+
checkForReplayGap.mockResolvedValue(null)
82+
})
8383

84-
it("returns preview sessions in batch mode", async () => {
84+
it('returns preview sessions in batch mode', async () => {
8585
getLatestRunForStream.mockResolvedValue({
86-
status: "active",
87-
executionId: "exec-1",
88-
id: "run-1",
89-
});
86+
status: 'active',
87+
executionId: 'exec-1',
88+
id: 'run-1',
89+
})
9090
readFilePreviewSessions.mockResolvedValue([
9191
{
9292
schemaVersion: 1,
93-
id: "preview-1",
94-
streamId: "stream-1",
95-
toolCallId: "preview-1",
96-
status: "streaming",
97-
fileName: "draft.md",
98-
previewText: "hello",
93+
id: 'preview-1',
94+
streamId: 'stream-1',
95+
toolCallId: 'preview-1',
96+
status: 'streaming',
97+
fileName: 'draft.md',
98+
previewText: 'hello',
9999
previewVersion: 2,
100-
updatedAt: "2026-04-10T00:00:00.000Z",
100+
updatedAt: '2026-04-10T00:00:00.000Z',
101101
},
102-
]);
102+
])
103103

104104
const response = await GET(
105105
new NextRequest(
106-
"http://localhost:3000/api/copilot/chat/stream?streamId=stream-1&after=0&batch=true",
107-
),
108-
);
106+
'http://localhost:3000/api/copilot/chat/stream?streamId=stream-1&after=0&batch=true'
107+
)
108+
)
109109

110-
expect(response.status).toBe(200);
110+
expect(response.status).toBe(200)
111111
await expect(response.json()).resolves.toMatchObject({
112112
success: true,
113113
previewSessions: [
114114
expect.objectContaining({
115-
id: "preview-1",
116-
previewText: "hello",
115+
id: 'preview-1',
116+
previewText: 'hello',
117117
previewVersion: 2,
118118
}),
119119
],
120-
status: "active",
121-
});
122-
});
120+
status: 'active',
121+
})
122+
})
123123

124-
it("stops replay polling when run becomes cancelled", async () => {
124+
it('stops replay polling when run becomes cancelled', async () => {
125125
getLatestRunForStream
126126
.mockResolvedValueOnce({
127-
status: "active",
128-
executionId: "exec-1",
129-
id: "run-1",
127+
status: 'active',
128+
executionId: 'exec-1',
129+
id: 'run-1',
130130
})
131131
.mockResolvedValueOnce({
132-
status: "cancelled",
133-
executionId: "exec-1",
134-
id: "run-1",
135-
});
132+
status: 'cancelled',
133+
executionId: 'exec-1',
134+
id: 'run-1',
135+
})
136136

137137
const response = await GET(
138-
new NextRequest(
139-
"http://localhost:3000/api/copilot/chat/stream?streamId=stream-1&after=0",
140-
),
141-
);
138+
new NextRequest('http://localhost:3000/api/copilot/chat/stream?streamId=stream-1&after=0')
139+
)
142140

143-
const chunks = await readAllChunks(response);
144-
expect(chunks.join("")).toContain(
141+
const chunks = await readAllChunks(response)
142+
expect(chunks.join('')).toContain(
145143
JSON.stringify({
146144
status: MothershipStreamV1CompletionStatus.cancelled,
147-
reason: "terminal_status",
148-
}),
149-
);
150-
expect(getLatestRunForStream).toHaveBeenCalledTimes(2);
151-
});
145+
reason: 'terminal_status',
146+
})
147+
)
148+
expect(getLatestRunForStream).toHaveBeenCalledTimes(2)
149+
})
152150

153-
it("emits structured terminal replay error when run metadata disappears", async () => {
151+
it('emits structured terminal replay error when run metadata disappears', async () => {
154152
getLatestRunForStream
155153
.mockResolvedValueOnce({
156-
status: "active",
157-
executionId: "exec-1",
158-
id: "run-1",
154+
status: 'active',
155+
executionId: 'exec-1',
156+
id: 'run-1',
159157
})
160-
.mockResolvedValueOnce(null);
158+
.mockResolvedValueOnce(null)
161159

162160
const response = await GET(
163-
new NextRequest(
164-
"http://localhost:3000/api/copilot/chat/stream?streamId=stream-1&after=0",
165-
),
166-
);
167-
168-
const chunks = await readAllChunks(response);
169-
const body = chunks.join("");
170-
expect(body).toContain(`"type":"${MothershipStreamV1EventType.error}"`);
171-
expect(body).toContain('"code":"resume_run_unavailable"');
172-
expect(body).toContain(`"type":"${MothershipStreamV1EventType.complete}"`);
173-
});
174-
175-
it("uses the latest live request id for synthetic terminal replay events", async () => {
161+
new NextRequest('http://localhost:3000/api/copilot/chat/stream?streamId=stream-1&after=0')
162+
)
163+
164+
const chunks = await readAllChunks(response)
165+
const body = chunks.join('')
166+
expect(body).toContain(`"type":"${MothershipStreamV1EventType.error}"`)
167+
expect(body).toContain('"code":"resume_run_unavailable"')
168+
expect(body).toContain(`"type":"${MothershipStreamV1EventType.complete}"`)
169+
})
170+
171+
it('uses the latest live request id for synthetic terminal replay events', async () => {
176172
getLatestRunForStream
177173
.mockResolvedValueOnce({
178-
status: "active",
179-
executionId: "exec-1",
180-
id: "run-1",
174+
status: 'active',
175+
executionId: 'exec-1',
176+
id: 'run-1',
181177
})
182178
.mockResolvedValueOnce({
183-
status: "cancelled",
184-
executionId: "exec-1",
185-
id: "run-1",
186-
});
179+
status: 'cancelled',
180+
executionId: 'exec-1',
181+
id: 'run-1',
182+
})
187183
readEvents
188184
.mockResolvedValueOnce([
189185
{
190-
stream: { streamId: "stream-1", cursor: "1" },
186+
stream: { streamId: 'stream-1', cursor: '1' },
191187
seq: 1,
192-
trace: { requestId: "req-live-123" },
188+
trace: { requestId: 'req-live-123' },
193189
type: MothershipStreamV1EventType.text,
194190
payload: {
195-
channel: "assistant",
196-
text: "hello",
191+
channel: 'assistant',
192+
text: 'hello',
197193
},
198194
},
199195
])
200-
.mockResolvedValueOnce([]);
196+
.mockResolvedValueOnce([])
201197

202198
const response = await GET(
203-
new NextRequest(
204-
"http://localhost:3000/api/copilot/chat/stream?streamId=stream-1&after=0",
205-
),
206-
);
207-
208-
const chunks = await readAllChunks(response);
209-
const terminalChunk = chunks[chunks.length - 1] ?? "";
210-
expect(terminalChunk).toContain(
211-
`"type":"${MothershipStreamV1EventType.complete}"`,
212-
);
213-
expect(terminalChunk).toContain('"requestId":"req-live-123"');
214-
expect(terminalChunk).toContain('"status":"cancelled"');
215-
});
216-
});
199+
new NextRequest('http://localhost:3000/api/copilot/chat/stream?streamId=stream-1&after=0')
200+
)
201+
202+
const chunks = await readAllChunks(response)
203+
const terminalChunk = chunks[chunks.length - 1] ?? ''
204+
expect(terminalChunk).toContain(`"type":"${MothershipStreamV1EventType.complete}"`)
205+
expect(terminalChunk).toContain('"requestId":"req-live-123"')
206+
expect(terminalChunk).toContain('"status":"cancelled"')
207+
})
208+
})

0 commit comments

Comments
 (0)