firefox + llama.cpp == very good prose.
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

chore(comments) unify comments format

eagleusb 2ae5844f e5977765

+48 -54
+12 -12
src/api.ts
··· 1 1 import { API_PARAMS, API_TIMEOUT_MS } from "./config"; 2 2 import type { ApiErrorResponse, ApiChatCompletionStreamChunk } from "./types/api"; 3 3 4 - /** Error thrown when the API call fails for any reason (network, HTTP, malformed response). */ 4 + /** error thrown when the api call fails for any reason (network, http, malformed response). */ 5 5 export class ApiError extends Error { 6 6 constructor( 7 7 message: string, ··· 14 14 } 15 15 16 16 /** 17 - * Streams a text correction request to the local llama.cpp server. 17 + * streams a text correction request to the local llama.cpp server. 18 18 * 19 - * Yields each token as it arrives from the SSE stream, enabling progressive 20 - * display in the UI without waiting for the full response. 19 + * yields each token as it arrives from the sse stream, enabling progressive 20 + * display in the ui without waiting for the full response. 21 21 * 22 - * @param text - Validated, non-empty input text 23 - * @param systemPrompt - System prompt to instruct the model 24 - * @param baseUrl - API server base URL (e.g. "http://localhost:8080") 25 - * @yields Individual content tokens from the model's stream 26 - * @throws {@link ApiError} on timeout, HTTP errors, or network failures 22 + * @param text - validated, non-empty input text 23 + * @param systemPrompt - system prompt to instruct the model 24 + * @param baseUrl - api server base url (e.g. "http://localhost:8080") 25 + * @yields individual content tokens from the model's stream 26 + * @throws {@link ApiError} on timeout, http errors, or network failures 27 27 */ 28 28 export async function* streamCorrection( 29 29 text: string, ··· 65 65 ); 66 66 } 67 67 68 - // Connection established — clear the connect-timeout 68 + /* connection established — clear the connect-timeout */ 69 69 clearTimeout(timeout); 70 70 71 - // ─── HTTP status errors ────────────────────────────────────────────────── 71 + /* http status errors */ 72 72 73 73 if (!response.ok) { 74 74 const status = response.status; ··· 103 103 } 104 104 } 105 105 106 - // ─── SSE stream parsing ───────────────────────────────────────────────── 106 + /* sse stream parsing */ 107 107 108 108 const body = response.body; 109 109 if (!body) {
+20 -26
src/background.ts
··· 2 2 import { validateInput, ValidationError } from "./validation"; 3 3 import { CORRECT_PROMPT, SUGGEST_PROMPT, API_BASE_URL, STORAGE_KEY_API_URL } from "./config"; 4 4 5 - /** Context menu item ID. */ 5 + /** context menu item id */ 6 6 const MENU_ID = "correct-with-llamacpp"; 7 7 8 - /** Section identifiers for streaming responses. */ 8 + /** section identifiers for streaming responses */ 9 9 type Section = "corrected" | "suggested"; 10 10 11 - /** Maps a section to its system prompt. */ 11 + /** maps a section to its system prompt */ 12 12 const SECTION_PROMPTS: Record<Section, string> = { 13 13 corrected: CORRECT_PROMPT, 14 14 suggested: SUGGEST_PROMPT, 15 15 }; 16 16 17 - /** 18 - * Pending state for a popup window that hasn't signalled "ready" yet. 19 - */ 17 + /** pending state for a popup window that hasn't signalled "ready" yet */ 20 18 interface PendingResult { 21 19 tabId: number; 22 20 resolve: () => void; ··· 24 22 25 23 let pending: PendingResult | null = null; 26 24 27 - // ─── Storage helpers ─────────────────────────────────────────────────────── 25 + /* storage helpers */ 28 26 29 - /** Reads the configured API base URL from storage, falling back to the default. */ 27 + /** reads the configured api base url from storage, falling back to the default */ 30 28 async function getApiBaseUrl(): Promise<string> { 31 29 const result = await browser.storage.local.get(STORAGE_KEY_API_URL); 32 30 const stored = result[STORAGE_KEY_API_URL]; 33 31 return typeof stored === "string" && stored.length > 0 ? stored : API_BASE_URL; 34 32 } 35 33 36 - // ─── Context menu setup ──────────────────────────────────────────────────── 34 + /* context menu setup */ 37 35 38 36 browser.runtime.onInstalled.addListener(() => { 39 37 browser.contextMenus.create({ ··· 43 41 }); 44 42 }); 45 43 46 - // ─── Message handler (result tab readiness + retry) ──────────────────────── 44 + /* message handler (result tab readiness + retry) */ 47 45 48 46 browser.runtime.onMessage.addListener((msg: { type: string }, sender) => { 49 47 if (msg.type === "ready") { ··· 63 61 } 64 62 }); 65 63 66 - // ─── Context menu click handler ──────────────────────────────────────────── 64 + /* context menu click handler */ 67 65 68 66 browser.contextMenus.onClicked.addListener(async (info) => { 69 67 if (info.menuItemId !== MENU_ID) { 70 68 return; 71 69 } 72 70 73 - // 1. Validate input 71 + /* 1. validate input */ 74 72 let inputText: string; 75 73 try { 76 74 inputText = validateInput(info.selectionText); ··· 80 78 return; 81 79 } 82 80 83 - // 2. Open popup immediately (shows loading spinner) 81 + /* 2. open popup immediately (shows loading spinner) */ 84 82 const window = await browser.windows.create({ 85 83 type: "popup", 86 84 url: browser.runtime.getURL("result.html"), ··· 94 92 } 95 93 const tabId = tab.id; 96 94 97 - // 3. Wait for the result tab to signal "ready" 95 + /* 3. wait for the result tab to signal "ready" */ 98 96 const readyPromise = new Promise<void>((resolve) => { 99 97 pending = { tabId, resolve }; 100 98 }); 101 99 await readyPromise; 102 100 pending = null; 103 101 104 - // 4. Tell the result tab to show the original text 102 + /* 4. tell the result tab to show the original text */ 105 103 await browser.tabs.sendMessage(tabId, { 106 104 type: "start", 107 105 original: inputText, 108 106 }); 109 107 110 - // 5. Sequential streaming with per-section error handling 108 + /* 5. sequential streaming with per-section error handling */ 111 109 const baseUrl = await getApiBaseUrl(); 112 110 113 111 const correctedOk = await attemptStreamSection(tabId, inputText, "corrected", baseUrl); ··· 119 117 await browser.tabs.sendMessage(tabId, { type: "done" }); 120 118 }); 121 119 122 - // ─── Stream a single section, returning success/failure ──────────────────── 123 - 124 120 /** 125 - * Attempts to stream a section. On success, sends `section-done`. 126 - * On failure, sends `section-error` with the error message. 127 - * Returns `true` if the section completed successfully. 121 + * attempts to stream a section. on success sends section-done. 122 + * on failure sends section-error with the error message. 123 + * returns true if the section completed successfully. 128 124 */ 129 125 async function attemptStreamSection( 130 126 tabId: number, ··· 145 141 } 146 142 } 147 143 148 - // ─── Stream a single section from the API ────────────────────────────────── 149 - 144 + /** stream a single section from the api, measuring ttft latency */ 150 145 async function streamSection( 151 146 tabId: number, 152 147 text: string, ··· 174 169 await browser.tabs.sendMessage(tabId, { type: "section-done", section }); 175 170 } 176 171 177 - // ─── Retry handler ───────────────────────────────────────────────────────── 172 + /* retry handler */ 178 173 179 174 async function handleRetry(tabId: number, section: Section, original: string): Promise<void> { 180 175 const baseUrl = await getApiBaseUrl(); 181 176 await attemptStreamSection(tabId, original, section, baseUrl); 182 177 } 183 178 184 - // ─── Helper: open popup with an error when validation fails immediately ──── 185 - 179 + /** open popup with an error when validation fails immediately */ 186 180 async function openPopupWithError(message: string): Promise<void> { 187 181 const window = await browser.windows.create({ 188 182 type: "popup",
+2 -2
src/config.ts
··· 19 19 * Instructs the model to return only the corrected text. 20 20 */ 21 21 export const CORRECT_PROMPT = `# Agent Guidelines 22 - You are an agent specialized in english grammar correction. 22 + You are an agent specialized in english and french grammar correction. 23 23 Correct the grammar, spelling, and punctuation of the submitted text. 24 24 25 25 # Output ··· 32 32 * Instructs the model to return a better-worded version of the text. 33 33 */ 34 34 export const SUGGEST_PROMPT = `# Agent Guidelines 35 - You are an agent specialized in english writing improvement. 35 + You are an agent specialized in english and french writing improvement. 36 36 Rewrite the submitted text with better wording and phrasing while preserving the original meaning. 37 37 38 38 # Output
+14 -14
src/result.ts
··· 1 1 import { API_BASE_URL, STORAGE_KEY_API_URL } from "./config"; 2 2 3 - // ─── DOM references ──────────────────────────────────────────────────────── 3 + /* dom references */ 4 4 5 5 const apiUrlInput = document.getElementById("api-url") as HTMLInputElement; 6 6 const apiSavedEl = document.getElementById("api-saved")!; ··· 18 18 const latencyCorrectedEl = document.getElementById("latency-corrected")!; 19 19 const latencySuggestedEl = document.getElementById("latency-suggested")!; 20 20 21 - // ─── Section state ───────────────────────────────────────────────────────── 21 + /* section state */ 22 22 23 23 type Section = "corrected" | "suggested"; 24 24 ··· 53 53 }, 54 54 }; 55 55 56 - /** Stored original text for retry requests. */ 56 + /** stored original text for retry requests */ 57 57 let originalText = ""; 58 58 59 - // ─── Message types from background script ────────────────────────────────── 59 + /* message types from background script */ 60 60 61 61 type ResultMessage = 62 62 | { type: "start"; original: string } ··· 67 67 | { type: "done" } 68 68 | { type: "error"; message: string }; 69 69 70 - // ─── Message handler ─────────────────────────────────────────────────────── 70 + /* message handler */ 71 71 72 72 browser.runtime.onMessage.addListener((msg: ResultMessage) => { 73 73 switch (msg.type) { ··· 94 94 } 95 95 }); 96 96 97 - // ─── UI helpers ──────────────────────────────────────────────────────────── 97 + /* ui helpers */ 98 98 99 99 function showStart(original: string): void { 100 100 originalText = original; ··· 159 159 function showSectionError(section: Section, message: string): void { 160 160 const state = sections[section]; 161 161 162 - // Hide and detach the streaming indicator 162 + /* hide and detach the streaming indicator */ 163 163 state.indicator.classList.add("hidden"); 164 164 state.indicator.remove(); 165 165 ··· 178 178 errorMessageEl.textContent = message; 179 179 } 180 180 181 - // ─── Click-to-copy on content boxes ──────────────────────────────────────── 181 + /* click-to-copy on content boxes */ 182 182 183 183 function setupCopyOnDone(section: Section): void { 184 184 const state = sections[section]; ··· 193 193 state.el.classList.add("copied"); 194 194 setTimeout(() => state.el.classList.remove("copied"), 2_000); 195 195 } catch { 196 - // silently ignore clipboard failures 196 + /* silently ignore clipboard failures */ 197 197 } 198 198 }); 199 199 } ··· 201 201 setupCopyOnDone("corrected"); 202 202 setupCopyOnDone("suggested"); 203 203 204 - // ─── Retry icons ─────────────────────────────────────────────────────────── 204 + /* retry icons */ 205 205 206 206 function setupRetryIcon(section: Section): void { 207 207 const state = sections[section]; ··· 222 222 setupRetryIcon("corrected"); 223 223 setupRetryIcon("suggested"); 224 224 225 - // ─── API URL settings ────────────────────────────────────────────────────── 225 + /* api url settings */ 226 226 227 - /** Load stored API URL into the input field on popup open. */ 227 + /** load stored api url into the input field on popup open */ 228 228 browser.storage.local.get(STORAGE_KEY_API_URL).then((result) => { 229 229 const stored = result[STORAGE_KEY_API_URL]; 230 230 apiUrlInput.value = typeof stored === "string" && stored.length > 0 ··· 232 232 : API_BASE_URL; 233 233 }); 234 234 235 - /** Save API URL to storage on change. */ 235 + /** save api url to storage on change */ 236 236 apiUrlInput.addEventListener("change", () => { 237 237 const value = apiUrlInput.value.trim(); 238 238 if (value.startsWith("http://") || value.startsWith("https://")) { ··· 243 243 } 244 244 }); 245 245 246 - // ─── Signal readiness to background script ───────────────────────────────── 246 + /* signal readiness to background script */ 247 247 248 248 browser.runtime.sendMessage({ type: "ready" });