Skip to content

Commit 9b1ea89

Browse files
committed
Formatting fixes
1 parent f5f68ee commit 9b1ea89

8 files changed

Lines changed: 170 additions & 60 deletions

File tree

api/_lib/aiHandler.test.ts

Lines changed: 38 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,10 @@ import { describe, expect, it, vi } from "vitest";
33
import { runAiTurn } from "./aiHandler.js";
44
import type { OpenRouterFinalMessage, OpenRouterLike } from "./openrouterClient.js";
55

6-
function fakeClient(finals: OpenRouterFinalMessage[], textByCall: string[][] = []): OpenRouterLike & { calls: any[] } {
6+
function fakeClient(
7+
finals: OpenRouterFinalMessage[],
8+
textByCall: string[][] = [],
9+
): OpenRouterLike & { calls: any[] } {
710
let call = 0;
811
const calls: any[] = [];
912
return {
@@ -48,7 +51,10 @@ describe("runAiTurn", () => {
4851
);
4952
await runAiTurn(req, { ...deps, client }, sink);
5053

51-
expect(events.filter((e) => e.event === "text").map((e) => e.data.delta)).toEqual(["hel", "lo"]);
54+
expect(events.filter((e) => e.event === "text").map((e) => e.data.delta)).toEqual([
55+
"hel",
56+
"lo",
57+
]);
5258
const done = events.find((e) => e.event === "done");
5359
expect(done?.data.finish_reason).toBe("stop");
5460
expect(sink.end).toHaveBeenCalledOnce();
@@ -62,7 +68,11 @@ describe("runAiTurn", () => {
6268
role: "assistant",
6369
content: null,
6470
tool_calls: [
65-
{ id: "t1", type: "function", function: { name: "run_check", arguments: '{"resource":"doc:x"}' } },
71+
{
72+
id: "t1",
73+
type: "function",
74+
function: { name: "run_check", arguments: '{"resource":"doc:x"}' },
75+
},
6676
],
6777
},
6878
finish_reason: "tool_calls",
@@ -122,7 +132,10 @@ describe("runAiTurn", () => {
122132
},
123133
finish_reason: "tool_calls",
124134
},
125-
{ message: { role: "assistant", content: "Based on the reference." }, finish_reason: "stop" },
135+
{
136+
message: { role: "assistant", content: "Based on the reference." },
137+
finish_reason: "stop",
138+
},
126139
],
127140
[["Let me check the docs."], ["Based on the reference."]],
128141
);
@@ -190,7 +203,11 @@ describe("runAiTurn", () => {
190203
role: "assistant",
191204
content: null,
192205
tool_calls: [
193-
{ id: "s1", type: "function", function: { name: "read_skill_reference", arguments: '{"name":"patte' } },
206+
{
207+
id: "s1",
208+
type: "function",
209+
function: { name: "read_skill_reference", arguments: '{"name":"patte' },
210+
},
194211
],
195212
},
196213
finish_reason: "tool_calls",
@@ -218,7 +235,11 @@ describe("runAiTurn", () => {
218235
role: "assistant",
219236
content: null,
220237
tool_calls: [
221-
{ id: "bad1", type: "function", function: { name: "read_skill_reference", arguments: "{not json" } },
238+
{
239+
id: "bad1",
240+
type: "function",
241+
function: { name: "read_skill_reference", arguments: "{not json" },
242+
},
222243
{ id: "c1", type: "function", function: { name: "run_check", arguments: "{}" } },
223244
],
224245
},
@@ -242,8 +263,16 @@ describe("runAiTurn", () => {
242263
role: "assistant",
243264
content: null,
244265
tool_calls: [
245-
{ id: "x", type: "function", function: { name: "read_skill_reference", arguments: "{not json" } },
246-
{ id: "x", type: "function", function: { name: "run_check", arguments: '{"resource":"doc:x"}' } },
266+
{
267+
id: "x",
268+
type: "function",
269+
function: { name: "read_skill_reference", arguments: "{not json" },
270+
},
271+
{
272+
id: "x",
273+
type: "function",
274+
function: { name: "run_check", arguments: '{"resource":"doc:x"}' },
275+
},
247276
],
248277
},
249278
finish_reason: "tool_calls",
@@ -286,6 +315,6 @@ describe("runAiTurn", () => {
286315
expect(handoff!.data.malformedClientToolCalls).toEqual([
287316
{ id: "c1", name: "run_check", error: expect.any(String) },
288317
]);
289-
expect((handoff!.data.serverToolResults[0] as any)).toMatchObject({ tool_call_id: "c1" });
318+
expect(handoff!.data.serverToolResults[0] as any).toMatchObject({ tool_call_id: "c1" });
290319
});
291320
});

api/_lib/aiHandler.ts

Lines changed: 24 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
import { buildSystemMessage, buildToolDefs } from "./openrouter.js";
2-
import type { OpenRouterFinalMessage, OpenRouterLike, OpenRouterMessage } from "./openrouterClient.js";
2+
import type {
3+
OpenRouterFinalMessage,
4+
OpenRouterLike,
5+
OpenRouterMessage,
6+
} from "./openrouterClient.js";
37
import { ParagraphBreakTracker } from "./paragraphBreak.js";
48
import type { AiRequest } from "./schema.js";
59
import { SERVER_TOOLS, SERVER_TOOL_NAMES } from "./serverTools.js";
@@ -48,7 +52,10 @@ export async function runAiTurn(
4852
// Paired by array position, never by call.id — ids aren't guaranteed
4953
// unique across the calls in one turn, and keying by id let one call's
5054
// arguments silently overwrite another's.
51-
const outcomes = toolCalls.map((call) => ({ call, parsed: parseArguments(call.function.arguments) }));
55+
const outcomes = toolCalls.map((call) => ({
56+
call,
57+
parsed: parseArguments(call.function.arguments),
58+
}));
5259

5360
const malformedResults: OpenRouterMessage[] = [];
5461
const malformedClientToolCalls: { id: string; name: string; error: string }[] = [];
@@ -60,21 +67,32 @@ export async function runAiTurn(
6067
content: `Malformed arguments for tool "${o.call.function.name}": ${o.parsed.error}. The call was not executed.`,
6168
});
6269
if (!SERVER_TOOL_NAMES.has(o.call.function.name)) {
63-
malformedClientToolCalls.push({ id: o.call.id, name: o.call.function.name, error: o.parsed.error });
70+
malformedClientToolCalls.push({
71+
id: o.call.id,
72+
name: o.call.function.name,
73+
error: o.parsed.error,
74+
});
6475
}
6576
}
6677

6778
const validOutcomes = outcomes.filter(
68-
(o): o is { call: (typeof outcomes)[number]["call"]; parsed: { ok: true; value: unknown } } => o.parsed.ok,
79+
(o): o is { call: (typeof outcomes)[number]["call"]; parsed: { ok: true; value: unknown } } =>
80+
o.parsed.ok,
6981
);
7082
const serverOutcomes = validOutcomes.filter((o) => SERVER_TOOL_NAMES.has(o.call.function.name));
71-
const clientOutcomes = validOutcomes.filter((o) => !SERVER_TOOL_NAMES.has(o.call.function.name));
83+
const clientOutcomes = validOutcomes.filter(
84+
(o) => !SERVER_TOOL_NAMES.has(o.call.function.name),
85+
);
7286

7387
const serverToolResults: OpenRouterMessage[] = [
7488
...malformedResults,
7589
...serverOutcomes.map((o) => {
7690
const tool = SERVER_TOOLS.find((t) => t.name === o.call.function.name)!;
77-
return { role: "tool" as const, tool_call_id: o.call.id, content: tool.execute(o.parsed.value) };
91+
return {
92+
role: "tool" as const,
93+
tool_call_id: o.call.id,
94+
content: tool.execute(o.parsed.value),
95+
};
7896
}),
7997
];
8098

api/_lib/openrouterClient.test.ts

Lines changed: 56 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,12 @@ describe("accumulateChunk / finalizeAccumulator", () => {
2525
{
2626
delta: {
2727
tool_calls: [
28-
{ index: 0, id: "call_1", type: "function", function: { name: "run_check", arguments: "" } },
28+
{
29+
index: 0,
30+
id: "call_1",
31+
type: "function",
32+
function: { name: "run_check", arguments: "" },
33+
},
2934
],
3035
},
3136
},
@@ -35,15 +40,21 @@ describe("accumulateChunk / finalizeAccumulator", () => {
3540
choices: [{ delta: { tool_calls: [{ index: 0, function: { arguments: '{"re' } }] } }],
3641
});
3742
accumulateChunk(acc, {
38-
choices: [{ delta: { tool_calls: [{ index: 0, function: { arguments: 'source":"doc:x"}' } }] } }],
43+
choices: [
44+
{ delta: { tool_calls: [{ index: 0, function: { arguments: 'source":"doc:x"}' } }] } },
45+
],
3946
});
4047
accumulateChunk(acc, { choices: [{ delta: {}, finish_reason: "tool_calls" }] });
4148

4249
const final = finalizeAccumulator(acc);
4350
expect(final.finish_reason).toBe("tool_calls");
4451
expect(final.message.content).toBeNull();
4552
expect(final.message.tool_calls).toEqual([
46-
{ id: "call_1", type: "function", function: { name: "run_check", arguments: '{"resource":"doc:x"}' } },
53+
{
54+
id: "call_1",
55+
type: "function",
56+
function: { name: "run_check", arguments: '{"resource":"doc:x"}' },
57+
},
4758
]);
4859
});
4960

@@ -54,8 +65,18 @@ describe("accumulateChunk / finalizeAccumulator", () => {
5465
{
5566
delta: {
5667
tool_calls: [
57-
{ index: 0, id: "call_a", type: "function", function: { name: "a", arguments: "{}" } },
58-
{ index: 1, id: "call_b", type: "function", function: { name: "b", arguments: "{}" } },
68+
{
69+
index: 0,
70+
id: "call_a",
71+
type: "function",
72+
function: { name: "a", arguments: "{}" },
73+
},
74+
{
75+
index: 1,
76+
id: "call_b",
77+
type: "function",
78+
function: { name: "b", arguments: "{}" },
79+
},
5980
],
6081
},
6182
},
@@ -126,13 +147,15 @@ describe("createOpenRouterClient", () => {
126147
}
127148

128149
it("streams text deltas and resolves the final message", async () => {
129-
const fetchImpl = vi.fn().mockResolvedValue(
130-
sseResponse([
131-
'data: {"choices":[{"delta":{"content":"Hi"}}]}\n\n',
132-
'data: {"choices":[{"delta":{},"finish_reason":"stop"}]}\n\n',
133-
"data: [DONE]\n\n",
134-
]),
135-
);
150+
const fetchImpl = vi
151+
.fn()
152+
.mockResolvedValue(
153+
sseResponse([
154+
'data: {"choices":[{"delta":{"content":"Hi"}}]}\n\n',
155+
'data: {"choices":[{"delta":{},"finish_reason":"stop"}]}\n\n',
156+
"data: [DONE]\n\n",
157+
]),
158+
);
136159
const client = createOpenRouterClient("sk-test", fetchImpl);
137160
const stream = client.stream({
138161
model: "anthropic/claude-sonnet-5",
@@ -195,9 +218,11 @@ describe("createOpenRouterClient", () => {
195218
});
196219

197220
it("throws OpenRouterApiError on a mid-stream inline error chunk", async () => {
198-
const fetchImpl = vi.fn().mockResolvedValue(
199-
sseResponse(['data: {"error":{"message":"provider overloaded","code":503}}\n\n']),
200-
);
221+
const fetchImpl = vi
222+
.fn()
223+
.mockResolvedValue(
224+
sseResponse(['data: {"error":{"message":"provider overloaded","code":503}}\n\n']),
225+
);
201226
const client = createOpenRouterClient("sk-test", fetchImpl);
202227
const stream = client.stream({
203228
model: "anthropic/claude-sonnet-5",
@@ -213,11 +238,13 @@ describe("createOpenRouterClient", () => {
213238
// https://openrouter.ai/docs/api_reference/streaming#handling-errors-during-streaming
214239
// — once tokens have streamed, HTTP 200 is already committed, so the
215240
// error arrives as a string type code, not a numeric HTTP status.
216-
const fetchImpl = vi.fn().mockResolvedValue(
217-
sseResponse([
218-
'data: {"id":"cmpl-abc123","object":"chat.completion.chunk","created":1234567890,"model":"openai/gpt-4o","provider":"openai","error":{"code":"server_error","message":"Provider disconnected unexpectedly"},"choices":[{"index":0,"delta":{"content":""},"finish_reason":"error"}]}\n\n',
219-
]),
220-
);
241+
const fetchImpl = vi
242+
.fn()
243+
.mockResolvedValue(
244+
sseResponse([
245+
'data: {"id":"cmpl-abc123","object":"chat.completion.chunk","created":1234567890,"model":"openai/gpt-4o","provider":"openai","error":{"code":"server_error","message":"Provider disconnected unexpectedly"},"choices":[{"index":0,"delta":{"content":""},"finish_reason":"error"}]}\n\n',
246+
]),
247+
);
221248
const client = createOpenRouterClient("sk-test", fetchImpl);
222249
const stream = client.stream({
223250
model: "anthropic/claude-sonnet-5",
@@ -312,7 +339,10 @@ describe("createOpenRouterClient", () => {
312339
return Promise.resolve(new Response(body, { status: 503 }));
313340
}
314341
return Promise.resolve(
315-
sseResponse(['data: {"choices":[{"delta":{},"finish_reason":"stop"}]}\n\n', "data: [DONE]\n\n"]),
342+
sseResponse([
343+
'data: {"choices":[{"delta":{},"finish_reason":"stop"}]}\n\n',
344+
"data: [DONE]\n\n",
345+
]),
316346
);
317347
});
318348
const client = createOpenRouterClient("sk-test", fetchImpl);
@@ -333,9 +363,11 @@ describe("createOpenRouterClient", () => {
333363
});
334364

335365
it("does not retry a non-retryable HTTP status", async () => {
336-
const fetchImpl = vi.fn().mockResolvedValue(
337-
new Response(JSON.stringify({ error: { message: "Invalid API key" } }), { status: 401 }),
338-
);
366+
const fetchImpl = vi
367+
.fn()
368+
.mockResolvedValue(
369+
new Response(JSON.stringify({ error: { message: "Invalid API key" } }), { status: 401 }),
370+
);
339371
const client = createOpenRouterClient("sk-test", fetchImpl);
340372
const stream = client.stream({
341373
model: "anthropic/claude-sonnet-5",

api/_lib/openrouterClient.ts

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,9 @@ interface RawDeltaToolCall {
8282
}
8383
interface RawChunk {
8484
error?: { message?: string; code?: number | string };
85-
choices?: [{ delta?: { content?: string; tool_calls?: RawDeltaToolCall[] }; finish_reason?: string }];
85+
choices?: [
86+
{ delta?: { content?: string; tool_calls?: RawDeltaToolCall[] }; finish_reason?: string },
87+
];
8688
}
8789

8890
// Once tokens have already streamed, OpenRouter can't change the committed
@@ -116,7 +118,8 @@ export function accumulateChunk(acc: StreamAccumulator, chunk: RawChunk): string
116118
if (chunk.error) {
117119
const rawCode = chunk.error.code;
118120
const baseMessage = chunk.error.message ?? "OpenRouter stream error";
119-
const isNonNumericStringCode = typeof rawCode === "string" && parseNumericCode(rawCode) === null;
121+
const isNonNumericStringCode =
122+
typeof rawCode === "string" && parseNumericCode(rawCode) === null;
120123
throw new OpenRouterApiError(
121124
isNonNumericStringCode ? `${baseMessage} (code: ${rawCode})` : baseMessage,
122125
normalizeErrorCode(rawCode),
@@ -236,7 +239,9 @@ async function runStream(
236239
}
237240

238241
const acc = createAccumulator();
239-
const events = res.body.pipeThrough(new TextDecoderStream()).pipeThrough(new EventSourceParserStream());
242+
const events = res.body
243+
.pipeThrough(new TextDecoderStream())
244+
.pipeThrough(new EventSourceParserStream());
240245

241246
for await (const event of events as unknown as AsyncIterable<EventSourceMessage>) {
242247
if (event.data === "[DONE]") continue;

api/_lib/schema.test.ts

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -58,10 +58,7 @@ describe("AiRequestSchema", () => {
5858
it("accepts a tool-role message", () => {
5959
const { error } = z.safeParse(AiRequestSchema, {
6060
...valid,
61-
messages: [
62-
...valid.messages,
63-
{ role: "tool", tool_call_id: "t1", content: "{\"ok\":true}" },
64-
],
61+
messages: [...valid.messages, { role: "tool", tool_call_id: "t1", content: '{"ok":true}' }],
6562
});
6663
expect(error).toBeUndefined();
6764
});

src/components/rightdock/DockActivityBar.tsx

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -49,10 +49,7 @@ export function DockActivityBar({ aiEnabled }: { aiEnabled: boolean }) {
4949
size="icon-sm"
5050
variant="ghost"
5151
aria-label="Assistant"
52-
className={cn(
53-
"relative",
54-
isActive("assistant") && "bg-chrome-panel text-foreground",
55-
)}
52+
className={cn("relative", isActive("assistant") && "bg-chrome-panel text-foreground")}
5653
onClick={onToggleAssistant}
5754
>
5855
<Bot />

0 commit comments

Comments
 (0)