Script for easily configuring, using, switching and comparing local offline coding models
1import { OLLAMA_URL } from "../config.js";
2import { getActiveChatModel } from "../runtime-config.js";
3import { err } from "../log.js";
4import { ensureOllama } from "./server.js";
5
6export async function runAsk(question: string): Promise<void> {
7 await ensureOllama();
8 const model = getActiveChatModel();
9
10 const body = JSON.stringify({
11 model: model.ollamaTag,
12 messages: [
13 {
14 role: "system",
15 content:
16 "You are an expert programmer. Give concise, practical answers. Include code examples when helpful.",
17 },
18 { role: "user", content: question },
19 ],
20 stream: true,
21 });
22
23 let res: Response;
24 try {
25 res = await fetch(`${OLLAMA_URL}/v1/chat/completions`, {
26 method: "POST",
27 headers: { "Content-Type": "application/json" },
28 body,
29 });
30 } catch {
31 err("Ollama not running. Start it with: localcode start");
32 }
33
34 if (!res!.ok) {
35 err(`Server returned ${res!.status}`);
36 }
37
38 // Stream the response
39 const reader = res!.body?.getReader();
40 if (!reader) {
41 err("No response body");
42 }
43
44 const decoder = new TextDecoder();
45 let buffer = "";
46
47 while (true) {
48 const { done, value } = await reader.read();
49 if (done) break;
50
51 buffer += decoder.decode(value, { stream: true });
52 const lines = buffer.split("\n");
53 buffer = lines.pop()!;
54
55 for (const line of lines) {
56 if (!line.startsWith("data: ")) continue;
57 const data = line.slice(6);
58 if (data === "[DONE]") continue;
59 try {
60 const json = JSON.parse(data) as {
61 choices?: { delta?: { content?: string } }[];
62 };
63 const content = json.choices?.[0]?.delta?.content;
64 if (content) process.stdout.write(content);
65 } catch {
66 // skip malformed chunks
67 }
68 }
69 }
70 process.stdout.write("\n");
71}