From 17571c9ba848dbc4c89214bd29cc156988a637dc Mon Sep 17 00:00:00 2001 From: cb-alish Date: Mon, 14 Sep 2026 16:34:25 +0530 Subject: [PATCH] Add local/lorem-ipsum model to avoid OpenRouter spend MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Streams lorem ipsum word-by-word from the app itself — no external API call, no credits consumed. Available to all plan tiers. Useful for dev, demos, and as a fallback when OpenRouter quota is exhausted. Co-authored-by: Cursor --- pointer/config/models.yaml | 3 +++ pointer/lib/generate/index.ts | 5 ++++ pointer/lib/generate/lorem.ts | 51 +++++++++++++++++++++++++++++++++++ 3 files changed, 59 insertions(+) create mode 100644 pointer/lib/generate/lorem.ts diff --git a/pointer/config/models.yaml b/pointer/config/models.yaml index 5e87ea1..1dc4195 100644 --- a/pointer/config/models.yaml +++ b/pointer/config/models.yaml @@ -1,11 +1,14 @@ # OpenRouter model slugs (https://openrouter.ai/api/v1/models). `*` grants any # slug; a `:*` suffix grants every variant of one model, e.g. `:batch`. basic: + - local/lorem-ipsum - poolside/laguna-s-2.1:free advanced: + - local/lorem-ipsum - poolside/laguna-s-2.1:free - nvidia/nemotron-3.5-lightning:free premium: + - local/lorem-ipsum - poolside/laguna-s-2.1:free - nvidia/nemotron-3.5-lightning:free - google/gemma-4-31b-it:free diff --git a/pointer/lib/generate/index.ts b/pointer/lib/generate/index.ts index 27801f9..91825e8 100644 --- a/pointer/lib/generate/index.ts +++ b/pointer/lib/generate/index.ts @@ -1,6 +1,7 @@ import { streamText } from "ai"; import { chatModel } from "./openrouter"; +import { LOREM_MODEL, streamLoremIpsum } from "./lorem"; const MAX_PROMPT_CHARS = 8_000; const MAX_OUTPUT_TOKENS = 4_096; @@ -98,6 +99,10 @@ export function streamGeneration( input: GenerateInput, signal: AbortSignal, ): GenerationStream { + if (input.model === LOREM_MODEL) { + return streamLoremIpsum(input, signal); + } + let failure: unknown; const result = streamText({ diff --git a/pointer/lib/generate/lorem.ts b/pointer/lib/generate/lorem.ts new file mode 100644 index 0000000..1c80d6c --- /dev/null +++ b/pointer/lib/generate/lorem.ts @@ -0,0 +1,51 @@ +import type { GenerateInput, Generation, GenerationStream } from "./index"; + +// Must match the slug added to config/models.yaml. +export const LOREM_MODEL = "local/lorem-ipsum"; + +const LOREM_TEXT = + "Lorem ipsum dolor sit amet, consectetur adipiscing elit. " + + "Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. " + + "Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris " + + "nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in " + + "reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla " + + "pariatur. Excepteur sint occaecat cupidatat non proident, sunt in " + + "culpa qui officia deserunt mollit anim id est laborum."; + +// Simulates realistic streaming cadence without hitting the network. +const CHUNK_DELAY_MS = 40; + +// Same ratio as estimateTokens() in index.ts — kept local to avoid a circular import. +const estimate = (text: string) => Math.max(1, Math.ceil(text.length / 4)); + +/** + * Streams lorem ipsum word-by-word without calling any external API. + * Drop-in replacement for streamGeneration() when model === LOREM_MODEL. + */ +export function streamLoremIpsum( + input: GenerateInput, + signal: AbortSignal, +): GenerationStream { + const words = LOREM_TEXT.split(" "); + let streamed = ""; + + async function* read(): AsyncGenerator { + for (const word of words) { + if (signal.aborted) { break; } + const chunk = streamed.length === 0 ? word : ` ${word}`; + streamed += chunk; + yield chunk; + await new Promise((resolve) => setTimeout(resolve, CHUNK_DELAY_MS)); + } + } + + return { + deltas: read(), + streamedTokens: () => estimate(streamed), + settle: async (): Promise => ({ + output: streamed, + inputTokens: estimate(input.prompt), + outputTokens: estimate(streamed), + }), + }; +}