Dashboard › sentry › Session 021Gyk1UJOHq
021Gyk1UJOHqLGPhmEvaluate whether we can use Gemma 4 E4B Q8_0 locally for worker tasks.
The user wants to evaluate whether Gemma 4 E4B Q8_0 can be used locally for worker tasks in the Lore project. Let me start by understanding what they're asking about and exploring the codebase.
First, let me understand the context:
Let me explore the codebase to understand:
I should also recall any relevant knowledge from the project first.
I'll evaluate whether Gemma 4 E4B Q8_0 can be used for Lore's worker tasks. Let me start by understanding the project structure and current model usage.
## Recall Results Found 30 results, showing top 15 (score range: 0.068β0.053). ### Strong Matches #### Distilled - <observations> Date: June 7, 2026 * π‘ (15:11) Fix 2 (LOREAI-GATEWAY-1P) in `packages/gateway/src/llm-adapter.ts`: added cast for Anthropic path at line 550 β `rawData` was `unknown`, OpenAI path already had `as OpenAIChatResponse`, Anthropic path needed matching cast * π‘ (15:11) Typecheck passed (5/6 workspace projects); lint had 1 format error + 15 pre-existing warnings in `packages/gateway/src/llm-adapter.ts`; biome formatter fixed 1 file in 255 formatted * π‘ (15:12) All 2287 tests passed (82 test files) in 48.72s for Fix 2 branch `fix/sse-as-json-guard` * π‘ (15:13) Fix 2 committed as `688f863` on branch `fix/sse-as-json-guard`: "fix(gateway): handle SSE response from upstream when stream: false was sent" β 2 files changed, 65 insertions, 3 deletions... ...
<path>/home/byk/Code/opencode-lore</path> <type>directory</type> <entries> .craft.yml .DS_Store .git/ .github/ .gitignore .jj/ .lore.md .opencode/ .plans/ .vendor-build/ AGENTS.md biome.json CHANGELOG.md docs/ LICENSE local_cache/ node_modules/ package.json packages/ pnpm-lock.yaml pnpm-workspace.yaml quality/ README.md scripts/ tsconfig.base.json tsconfig.json vitest.config.ts vitest.evals.config.ts (28 entries) </entries>
Let me get more context on the worker tasks. I need to understand:
Let me explore the codebase in parallel.
[
{
"content": "Identify all worker tasks and their LLM requirements",
"status": "in_progress",
"priority": "high"
},
{
"content": "Understand LLMClient / adapter architecture",
"status": "pending",
"priority": "high"
},
{
"content": "Check current local model support (LocalProvider)",
"status": "pending",
"priority": "high"
},
{
"content": "Evaluate Gemma 4 E4B Q8_0 feasibility (size, capabilities, format)",
"status": "pending",
"priority": "high"
},
{
"content": "Produce final recommendation with evidence",
"status": "pending",
"priority": "high"
}
]
<path>/home/byk/Code/opencode-lore/packages/core/src/types.ts</path>
<type>file</type>
<content>
180: export function isReasoningPart(p: LorePart): p is LoreReasoningPart {
181: return p.type === "reasoning";
182: }
183: export function isToolPart(p: LorePart): p is LoreToolPart {
184: return p.type === "tool";
185: }
186:
187: // ---------------------------------------------------------------------------
188: // Message with parts (the unit that hooks operate on)
189: // ---------------------------------------------------------------------------
190:
191: export type LoreMessageWithParts = {
192: info: LoreMessage;
193: parts: LorePart[];
194: };
195:
196: // ---------------------------------------------------------------------------
197: // LLM Client β the only host API Lore's background tasks need
198: // ---------------------------------------------------------------------------
199:
200: /**
201: * Abstract interface for single-turn LLM promptβresponse. ...
<path>/home/byk/Code/opencode-lore/packages/core/src/worker.ts</path>
<type>file</type>
<content>
1: // Re-export for convenience
2: export type { LLMClient } from "./types";
3:
4: // ---------------------------------------------------------------------------
5: // Shared worker session tracking
6: // ---------------------------------------------------------------------------
7:
8: /** Set of ALL worker session IDs across distillation, curator, and query expansion.
9: * Used by shouldSkip() in host adapters to avoid storing/distilling worker messages. */
10: export const workerSessionIDs = new Set<string>();
11:
12: export function isWorkerSession(sessionID: string): boolean {
13: return workerSessionIDs.has(sessionID);
14: }
(End of file - total 14 lines)
</content>
<path>/home/byk/Code/opencode-lore/packages/gateway/src/llm-adapter.ts</path> <type>file</type> <content> 1: /** 2: * Gateway LLM adapter: implements LLMClient via direct API calls. 3: * Used by Lore's background workers (distillation, curation, query expansion) 4: * running inside the gateway process. 5: * 6: * Supports both Anthropic Messages API and OpenAI Chat Completions API. 7: * The wire protocol is determined by explicit protocol from the session's 8: * UpstreamSnapshot (threaded via opts.protocol), with fallback to the 9: * provider route registry (PROVIDER_ROUTES) and a safe default of 10: * "anthropic" for unknown/aggregator providers: 11: * - Anthropic protocol β POST /v1/messages 12: * - OpenAI protocol β POST /v1/chat/completions 13: * 14: * Protocol is decoupled from provider identity β proxy/aggregator 15: * providers (e.g. OpenCode Zen) that have protocol=null in the route 16: * table receive their protocol from the session snapshot instead. ...
Now I understand the LLMClient interface. The gateway adapter supports both Anthropic and OpenAI Chat Completions protocols. Let me look for any local model support, the config, the worker tasks themselves, and any local provider concept.
Now let me find the local provider and worker task details in parallel.
Found 80 matches
/home/byk/Code/opencode-lore/packages/gateway/src/ui.ts:
Line 834: else{cmp=aT.localeCompare(bT,undefined,{sensitivity:"base"});}
Line 847: try{localStorage.setItem("lore-sort:"+tableId,JSON.stringify({col:idx,dir:dir}));}
Line 866: var raw=localStorage.getItem("lore-sort:"+tableId);
/home/byk/Code/opencode-lore/packages/gateway/src/pipeline.ts:
Line 1002: * - local gateway: keep the cwd path (legacy behavior β gateway shares the
Line 1073: // (local gateway: keep the cwd path from `result` β cwd is meaningful there.)
Line 1616: // (either providerRoute.url or headerUpstream). When url is null (local/
Line 1617: // custom providers like vllm, github-copilot), the protocol should come
/home/byk/Code/opencode-lore/packages/gateway/src/batch-queue.ts:
Line 371: // (e.g. vLLM, local models, MiniMax). Treat as permanent provider-level failure.
Line 540: // (e.g. vLLM, local models, MiniMax). ...
Found 16 matches
/home/byk/Code/opencode-lore/packages/core/src/types.ts:
Line 231: workerID?: string;
/home/byk/Code/opencode-lore/packages/core/src/search.ts:
Line 411: llm.prompt(
Line 417: workerID: "lore-query-expand",
/home/byk/Code/opencode-lore/packages/core/src/pattern-echo.ts:
Line 161: const responseText = await input.llm.prompt(
Line 166: workerID: "lore-pattern-echo",
/home/byk/Code/opencode-lore/packages/core/src/distillation.ts:
Line 994: const responseText = await input.llm.prompt(
Line 999: workerID: "lore-distill",
Line 1250: const responseText = await input.llm.prompt(RECURSIVE_SYSTEM, userContent, {
Line 1252: workerID: "lore-distill",
/home/byk/Code/opencode-lore/packages/core/src/curator.ts:
Line 597: const responseText = await input.llm.prompt(CURATOR_SYSTEM, userContent, {
Line 599: workerID: "lore-curator",
Line 916: const responseText = await input.llm.prompt(
Line ...
<path>/home/byk/Code/opencode-lore/packages/core/src/prompt.ts</path>
<type>file</type>
<content>
1: import type { Root } from "mdast";
2: import { serialize, inline, h, ul, liph, strong, t, root } from "./markdown";
3:
4: // All prompts are locked down β they are our core value offering.
5: // Do not make these configurable.
6:
7: export const DISTILLATION_SYSTEM = `You are a memory observer. Your observations will be the ONLY information an AI assistant has about past interactions. Produce a dense, dated event log β not a summary.
8:
9: CRITICAL: DISTINGUISH USER ASSERTIONS FROM QUESTIONS
10:
11: When the user TELLS you something about themselves, mark it as an assertion (π΄):
12: - "I have two kids" β π΄ (14:30) User stated has two kids
13: - "I work at Acme Corp" β π΄ (14:31) User stated works at Acme Corp
14:
15: When the user ASKS about something, mark it as a question (π‘):
16: - "Can you help me with X?" β π‘ (15:00) User asked for help with X
17:
18: User assertions are ...
<path>/home/byk/Code/opencode-lore/packages/gateway/src/config.ts</path>
<type>file</type>
<content>
1: /**
2: * Gateway configuration β loaded from environment variables with sensible
3: * defaults. No Zod, no file-based config β minimal @loreai/core dependency
4: * (only `normalizeRemoteUrl` for git URL canonicalization).
5: */
6:
7: import {
8: normalizeRemoteUrl,
9: discoverWorkspaceRoot,
10: UNATTRIBUTED_PROJECT_PREFIX,
11: isUnattributedProjectPath,
12: } from "@loreai/core";
13:
14: // ---------------------------------------------------------------------------
15: // Port defaults
16: // ---------------------------------------------------------------------------
17:
18: /**
19: * Default port preference order when LORE_LISTEN_PORT is not set. ...
I now have a good understanding of:
prompt(system, user, opts) with optional model override, workerID, urgent, maxTokens, temperature, thinking, protocol, upstreamUrl, sessionIDLORE_UPSTREAM_<PROVIDER> env var and provider routes (vllm, llamacpp, ollama, lmstudio, jan, localai, tgi, tabbyml, litellm). The gateway already supports OpenAI-compatible local servers for session routing (incoming requests)LORE_WORKER_API_KEY and LORE_WORKER_UPSTREAM for routing workers to a different provider than sessionsNow I need to investigate:
createGatewayLLMClient) honor LORE_WORKER_UPSTREAM?Let me also check:
upstreamUrl / protocol options on ...Now let me investigate worker upstream routing and how the LLMClient is created in the gateway.
Found 23 matches
/home/byk/Code/opencode-lore/packages/gateway/src/pipeline.ts:
Line 137: import { createGatewayLLMClient } from "./llm-adapter";
Line 912: // Worker-specific upstream: when LORE_WORKER_UPSTREAM is set, all worker
Line 914: const workerUpstreams = config.workerUpstream
Line 915: ? { anthropic: config.workerUpstream, openai: config.workerUpstream }
Line 918: if (config.workerApiKey || config.workerUpstream) {
Line 922: `upstream=${config.workerUpstream ?? "default"}`,
Line 926: const rawClient = createGatewayLLMClient(
Line 927: workerUpstreams,
Line 930: { dedicatedWorkerKey: !!workerApiKey },
Line 970: workerUpstreams,
/home/byk/Code/opencode-lore/packages/gateway/src/llm-adapter.ts:
Line 391: export function createGatewayLLMClient(
Line 395: opts?: { dedicatedWorkerKey?: boolean },
Line 397: const hasDedicatedKey = opts?.dedicatedWorkerKey === ...
Found 89 matches
/home/byk/Code/opencode-lore/packages/gateway/src/pipeline.ts:
Line 521: function getModelSpec(model: string): ModelSpec {
Line 2272: model: String(json.model ?? ""),
Line 2336: model: String(json.model ?? ""),
Line 2882: model: req.model,
Line 3196: const summaryText = await llm.prompt(compactPrompt, userContent, {
Line 3197: model: getWorkerModel(sessionUpstream),
Line 3238: setSentryLightContext({ model: req.model, projectPath });
Line 3340: model: "",
Line 3595: setSentryLightContext({ model: req.model });
Line 3867: model: req.model,
Line 5341: model: req.model,
/home/byk/Code/opencode-lore/packages/gateway/src/llm-adapter.ts:
Line 246: model: { providerID: string; modelID: string },
Line 280: model: model.modelID,
Line 316: model: { providerID: string; modelID: string },
Line 333: model: model.modelID,
Line 349: model: string | null;
Line 357: model: ...
<path>/home/byk/Code/opencode-lore/packages/gateway/src/server.ts</path> <type>file</type> <content> 1: /** 2: * HTTP server for the Lore gateway proxy. 3: * 4: * Routes: 5: * POST /v1/messages β Anthropic protocol 6: * POST /v1/chat/completions β OpenAI Chat Completions protocol 7: * POST /v1/responses β OpenAI Responses API protocol 8: * POST /v1/responses/compact β Codex compaction (Responses API) 9: * POST /v1/compact β Explicit compaction summary (Pi plugin, etc.) 10: * GET /v1/models β Passthrough to upstream 11: * GET /health β Health check 12: * 13: * Uses `node:http` `createServer` with Web `Request`/`Response` β the same 14: * code runs under both Bun and the Node.js npm distribution. ...
Now let me read the key file: worker-model.ts which is responsible for resolving the model used for workers, and also look at the pipeline where the LLMClient is created. I also need to understand how getWorkerModel works and if it allows model selection per worker.
<path>/home/byk/Code/opencode-lore/packages/gateway/src/worker-model.ts</path>
<type>file</type>
<content>
1: /**
2: * Gateway model pricing and resolution.
3: *
4: * Fetches per-model pricing from models.dev (open-source model database)
5: * for cost estimation in Sentry metrics and gradient cost-aware capping.
6: *
7: * Worker model resolution delegates to core's simple chain:
8: * explicit config override > session model fallback.
9: */
10:
11: import { workerModel, config as loreConfig, log } from "@loreai/core";
12: import type { ProviderRoute } from "./config";
13: import { upstreamFetch } from "./fetch";
14:
15: // ---------------------------------------------------------------------------
16: // Cost lookup β models.dev
17: // ---------------------------------------------------------------------------
18:
19: /**
20: * models.dev JSON API endpoint β returns all providers/models with pricing.
21: *
22: * Single request replaces N individual TOML fetches. ...
<path>/home/byk/Code/opencode-lore/packages/gateway/src/pipeline.ts</path>
<type>file</type>
<content>
880: }
881: ltmSessionCache.delete(sessionID);
882: ltmPinnedText.delete(sessionID);
883: stableLtmCache.delete(sessionID);
884: cwdWarned.delete(sessionID);
885: },
886: );
887: }
888:
889: log.info(`gateway pipeline initialized: ${projectPath}`);
890: }
891:
892: function getLLMClient(config: GatewayConfig): LLMClient {
893: if (!llmClient) {
894: const cfg = loreConfig();
895: const defaultModel = cfg.model ?? {
896: providerID: "anthropic",
897: modelID: "claude-sonnet-4-6",
898: };
899:
900: // Worker-specific auth: when LORE_WORKER_API_KEY is set, workers use a
901: // dedicated credential instead of the session's client key. This enables
902: // routing workers to a different provider (e.g. MiniMax) while sessions
903: // continue using Anthropic. ...
<path>/home/byk/Code/opencode-lore/packages/gateway/src/pipeline.ts</path>
<type>file</type>
<content>
3180: (d, i) =>
3181: `### Chunk ${i + 1}${d.generation > 0 ? " (consolidated)" : ""}\n${d.observations}`,
3182: )
3183: .join("\n\n");
3184: }
3185:
3186: // 6. Generate the compaction summary via LLM
3187: const userContent = context
3188: ? `${context}\n\n---\n\n${compactPrompt}`
3189: : compactPrompt;
3190:
3191: const compactInputTokens = Math.ceil(userContent.length / 3);
3192: const compactMaxTokens = Math.max(
3193: 2048,
3194: Math.min(Math.ceil(compactInputTokens * 0.5), 20_000),
3195: );
3196: const summaryText = await llm.prompt(compactPrompt, userContent, {
3197: model: getWorkerModel(sessionUpstream),
3198: workerID: "lore-compact",
3199: urgent: true,
3200: maxTokens: compactMaxTokens,
3201: temperature: 0,
3202: });
3203:
3204: return summaryText ?? ...
Now I have a clear picture of the architecture. Let me also check the curators, distillation worker prompt sizes, and a few more things to evaluate feasibility. Let me also check the workerModel config in core and any existing local model examples.
Now let me check worker input sizes, and whether there's any local model benchmark/eval infrastructure.
Found 104 matches (showing first 100) /home/byk/Code/opencode-lore/packages/core/src/types.ts: Line 281: * - Gateway: uses as `max_tokens` in the API request body Line 282: * - Pi: passes as `maxTokens` to `complete()` Line 283: * - OpenCode: cannot honor β SDK has no maxTokens on session.prompt(); Line 286: maxTokens?: number; /home/byk/Code/opencode-lore/packages/core/src/gradient.ts: Line 498: // NOTE: this cap of 32K matches what @ai-sdk/anthropic sends as max_tokens for Line 500: // the generic claude-opus-4- pattern with maxOutputTokens=32K). If the SDK is Line 1832: // maxInput = absolute ceiling the API enforces: input_tokens + max_tokens <= context /home/byk/Code/opencode-lore/packages/core/src/embedding.ts: Line 1292: * `batch.length Γ max_tokens_in_batch`. We greedily add rows until the Line 1297: let maxTokens = 0; Line 1305: const newMax = Math.max(maxTokens, estTokens); Line 1311: maxTokens = ...
Found 28 matches
/home/byk/Code/opencode-lore/packages/gateway/src/pipeline.ts:
Line 479: if (cost >= 5) return Math.min(base * 3, 0.2); // opus: 15%
/home/byk/Code/opencode-lore/packages/gateway/src/worker-model.ts:
Line 80: prefix: "claude-opus-4",
Line 89: prefix: "gpt-5.4",
Line 98: prefix: "gpt-5.5",
Line 117: prefix: "gpt-5.4-mini",
Line 286: * First tries exact match, then prefix match (e.g. "claude-opus-4-6-20260101"
Line 287: * matches "claude-opus-4-6"), then falls back to hardcoded defaults.
Line 371: // Anthropic: sonnet-4-6 matches opus quality on distillation at 40% lower cost
Line 377: // OpenAI: gpt-5.4-mini matched gpt-5.4 exactly (24 obs each) at 70% lower cost
Line 380: modelID: "gpt-5.4-mini",
Line 386: modelID: "gpt-5.4-mini", // default; overridden by _resolveGitHubCopilotWorker
Line 409: modelID: "gpt-5.4-mini",
Line 425: return { providerID: "github-copilot", modelID: "gpt-5.4-mini" ...
<path>/home/byk/Code/opencode-lore/packages/core/src/distillation.ts</path>
<type>file</type>
<content>
975: const first = input.messages[0];
976: const date = first
977: ? new Date(first.created_at).toLocaleDateString("en-US", {
978: year: "numeric",
979: month: "long",
980: day: "numeric",
981: })
982: : "unknown date";
983: const userContent = distillationUser({
984: priorObservations: prior,
985: date,
986: messages: text,
987: pinnedAssertions,
988: toolFailures,
989: });
990:
991: const model = input.model ?? config().model;
992: const sourceTokens = input.messages.reduce((sum, m) => sum + m.tokens, 0);
993: const maxTokens = distillTokenBudget(sourceTokens);
994: const responseText = await input.llm.prompt(
995: DISTILLATION_SYSTEM,
996: userContent,
997: {
998: model,
999: workerID: "lore-distill",
1000: thinking: false,
1001: urgent: input.urgent,
1002: ...
<path>/home/byk/Code/opencode-lore/packages/core/src/curator.ts</path>
<type>file</type>
<content>
580: // sessions, so the curator can decide whether they warrant a gotcha entry.
581: let toolFailureContext = "";
582: try {
583: toolFailureContext = buildToolFailureContext(
584: input.projectPath,
585: input.sessionID,
586: );
587: } catch (err) {
588: log.warn("tool failure context failed (non-fatal):", err);
589: }
590:
591: const userContent =
592: baseUserContent +
593: crossSessionContext +
594: actionTagContext +
595: toolFailureContext;
596: const model = input.model ?? cfg.model;
597: const responseText = await input.llm.prompt(CURATOR_SYSTEM, userContent, {
598: model,
599: workerID: "lore-curator",
600: thinking: false,
601: sessionID: input.sessionID,
602: maxTokens: 2048,
603: temperature: 0,
604: });
605: if (!responseText)
606: return {
607: created: 0,
608: updated: ...
No files found
/home/byk/Code/opencode-lore/vitest.evals.config.ts
Please address this message and continue with your tasks. </system-reminder>
The user wants me to research Gemma 4 E4B Q8_0 performance characteristics online to evaluate fit. Let me search the internet for recent reviews and benchmarks.
Key things to find:
Let me search.
[
{
"content": "Identify all worker tasks and their LLM requirements",
"status": "completed",
"priority": "high"
},
{
"content": "Understand LLMClient / adapter architecture",
"status": "completed",
"priority": "high"
},
{
"content": "Check current local model support (LocalProvider)",
"status": "completed",
"priority": "high"
},
{
"content": "Research Gemma 4 E4B Q8_0 capabilities (web)",
"status": "in_progress",
"priority": "high"
},
{
"content": "Evaluate Gemma 4 E4B Q8_0 feasibility for each worker",
"status": "pending",
"priority": "high"
},
{
"content": "Produce final recommendation with evidence",
"status": "pending",
"priority": "high"
}
]
Google Search Please click [here](/httpservice/retry/enablejs?sei=csglasThMc_Ji-gPz6_CkQU) if you are not redirected within a few seconds. If you're having trouble accessing Google Search, pleaseΒ [click here](/search?q=Gemma+4+E4B+release+benchmark+2026&sca_esv=26d9fb2b0a4b5cca&emsg=SG_REL&sei=csglasThMc_Ji-gPz6_CkQU), or sendΒ [feedback](https://support.google.com/websearch).
Google Search Please click [here](/httpservice/retry/enablejs?sei=c8glap3dD4qOi-gPg4SEgAU) if you are not redirected within a few seconds. If you're having trouble accessing Google Search, pleaseΒ [click here](/search?q=%22Gemma+4%22+E4B+Q8_0+GGUF+context+window+benchmark&sca_esv=26d9fb2b0a4b5cca&emsg=SG_REL&sei=c8glap3dD4qOi-gPg4SEgAU), or sendΒ [feedback](https://support.google.com/websearch).
The Google search requires JS. Let me try direct sources β Hugging Face, Ollama, Reddit, and DuckDuckGo.
unsloth/gemma-4-E4B-it-GGUF Β· Hugging Face
[ Hugging Face](/)
- [Models](/models)
- [Datasets](/datasets)
- [Spaces](/spaces)
- [Buckets new](/storage)
- [Docs](/docs)
- [Enterprise](/enterprise)
- [Pricing](/pricing)
- - Website
- [Tasks](/tasks)
- [HuggingChat](/chat)
- [Collections](/collections)
- [Languages](/languages)
- [Organizations](/organizations)
- Community
- [Blog](/blog)
- [Posts](/posts)
- [Daily Papers](/papers)
- [Learn](/learn)
- [Discord](/join/discord)
- [Forum](https://discuss.huggingface.co/)
- [GitHub](https://github.com/huggingface)
- Solutions
- [Team & Enterprise](/enterprise)
- [Hugging Face PRO](/pro)
- [Enterprise Support](/support)
- [Inference ...
gemma4:e4b
[](/)
[Models](/search) [Docs](/docs) [Pricing](/pricing)
[Sign in](/signin) [Download](/download)
[Models](/search) [Download](/download) [Docs](/docs) [Pricing](/pricing) [Sign in](/signin)
[gemma4](/library/gemma4 "gemma4"):e4b
12.3M Β Downloads UpdatedΒ 2 days ago
## Gemma 4 models are designed to deliver frontier-level performance at each size. They are well-suited for reasoning, agentic workflows, coding, and multimodal understanding.
Gemma 4 models are designed to deliver frontier-level performance at each size. They are well-suited for reasoning, agentic workflows, coding, and multimodal understanding.
Cancel
vision tools thinking audio cloud e2b e4b 12b 26b 31b
CLI cURL Python JavaScript
[Documentation](https://github.com/ollama/ollama-python) [Documentation](https://github.com/ollama/ollama-js)
ollama run gemma4:e4b
curl http://localhost:11434/api/chat \\
-d '{
"model": ...
Gemma 4 E4B release benchmark context window at DuckDuckGo [](/html/ "DuckDuckGo") All Regions Argentina Australia Austria Belgium (fr) Belgium (nl) Brazil Bulgaria Canada (en) Canada (fr) Catalonia Chile China Colombia Croatia Czech Republic Denmark Estonia Finland France Germany Greece Hong Kong Hungary Iceland India (en) Indonesia (en) Ireland Israel (en) Italy Japan Korea Latvia Lithuania Malaysia (en) Mexico Netherlands New Zealand Norway Pakistan (en) Peru Philippines (en) Poland Portugal Romania Russia Saudi Arabia Singapore Slovakia Slovenia South Africa Spain (ca) Spain (es) Sweden Switzerland (de) Switzerland (fr) Taiwan Thailand (en) Turkey US (English) US (Spanish) Ukraine United Kingdom Vietnam (en) Any Time Past Day Past Week Past Month Past Year ## [Gemma 4 E4B Benchmarks, Pricing & Context ...
"Gemma 4" "E4B" benchmark review at DuckDuckGo [](/html/ "DuckDuckGo") All Regions Argentina Australia Austria Belgium (fr) Belgium (nl) Brazil Bulgaria Canada (en) Canada (fr) Catalonia Chile China Colombia Croatia Czech Republic Denmark Estonia Finland France Germany Greece Hong Kong Hungary Iceland India (en) Indonesia (en) Ireland Israel (en) Italy Japan Korea Latvia Lithuania Malaysia (en) Mexico Netherlands New Zealand Norway Pakistan (en) Peru Philippines (en) Poland Portugal Romania Russia Saudi Arabia Singapore Slovakia Slovenia South Africa Spain (ca) Spain (es) Sweden Switzerland (de) Switzerland (fr) Taiwan Thailand (en) Turkey US (English) US (Spanish) Ukraine United Kingdom Vietnam (en) Any Time Past Day Past Week Past Month Past Year ## [Gemma 4 E4B - Intelligence, Performance & Price ...
Excellent! I have a lot of solid data now. Let me dig into the most relevant review/benchmark for our purposes β especially the one on RTX 3070 (real-world local) and the E4B enterprise benchmark. Let me also check the local RAG and distillation-related aspects.
Now let me read the most relevant hands-on benchmark β the RTX 3070 local E2B vs E4B review, which is the most relevant for our use case.
Gemma 4 E2B vs E4B Benchmark: The Hidden Thinking Mode That Makes the Smaller Model 20Γ Slower β the KodeLab
[the KodeLab](/en/)
- [Posts](/en/posts/)
- [Tags](/en/tags/)
[Search](/en/search/ "Search") Switch to dark mode
# Gemma 4 E2B vs E4B Benchmark: The Hidden Thinking Mode That Makes the Smaller Model 20Γ Slower
April 11, 2026 Β· 2,902 words Β· 15 min read Β·
- [AI](/en/tags/ai/)
- [LLM](/en/tags/llm/)
- [Gemma](/en/tags/gemma/)
- [Ollama](/en/tags/ollama/)
- [Benchmark](/en/tags/benchmark/)

Table of contents
1. [Test setup](#test-setup)
2. [Raw TPS benchmark](#raw-tps-benchmark)
1. [Does context length hurt speed?](#does-context-length-hurt-speed)
3. [Time to first token](#time-to-first-token)
4. [E2B vs E4B raw speed](#e2b-vs-e4b-raw-speed)
5. [Quality on hard tasks](#quality-on-hard-tasks)
6. ...
Gemma 4 E4B vs the Gemma Family: Enterprise Benchmark Showdown β aiexplorer.dev [aiexplorer*.*dev](/) - [Blog](/blog) - [Courses](/courses) - [Radar](/radar) - [About](/about) - [Subscribe](/subscribe) [Subscribe](/subscribe) [Home](/)/[Blog](/blog)/Gemma 4 E4B vs the Gemma Family: Enterprise Benchmark Showdown BenchmarksPart 1 Β· Gemma 4 Benchmarks # Gemma 4 E4B vs the Gemma Family: Enterprise Benchmark Showdown Google's newest 4B model tested across 8 enterprise task suites against Gemma 2 2B, Gemma 3 4B, and Gemma 3 12B. Run locally on Apple Silicon. **aiexplorer.dev**Apr 202612 min read Scope & limitations β read first 4 Gemma models (2B, 4B, E4B, 12B) Β· 8 enterprise test suites Β· ~50 test cases Β· Apple Silicon (MPS) Β· temperature 0.0 Β· deterministic runs Β· local inference via Hugging Face Transformers Google released Gemma 4 E4B in early 2026 β a 4-billion parameter model positioned as a strong efficiency play for on-device and edge deployment. ...
Gemma 4 E4B vs 26B on an RTX 4070 Ti: Benchmarks, RAG, and a Real Webapp Test | Alfonso Fortunato [DevFortunato](/) [Blog](/blog/)[Projects](/projects/)[About](/about/)[Contact](/contact/) [Blog](/blog/) # Gemma 4 E4B vs 26B on an RTX 4070 Ti: Benchmarks, RAG, and a Real Webapp Test I benchmarked Gemma 4 E4B and Gemma 4 26B locally with llama.cpp on an RTX 4070 Ti to see which one is better for local RAG, web retrieval, and grounded⦠Apr 4, 202618 min readAILLMGemma 4llama.cppLocal AIBenchmarksRTX 4070 TiHomelabOpen Source  I have been spending more and more time testing local AI lately, but not for privacy reasons. I do not really believe in that argument anymore. The real reason is cost. ...
I have rich data now. Let me also quickly check how each Lore worker task maps to the published benchmark data points, and check whether Gemma 4 supports the OpenAI Chat Completions API well via llama.cpp (since the E4B review used --jinja chat template). Let me also see if there are any reviews of it doing extraction/JSON-style work, which is critical for the curator.
Actually I already have what I need. Let me consolidate the findings and produce the final evaluation.
Key findings from web research:
I have enough data now. Let me produce the evaluation.
[
{
"content": "Identify all worker tasks and their LLM requirements",
"status": "completed",
"priority": "high"
},
{
"content": "Understand LLMClient / adapter architecture",
"status": "completed",
"priority": "high"
},
{
"content": "Check current local model support (LocalProvider)",
"status": "completed",
"priority": "high"
},
{
"content": "Research Gemma 4 E4B Q8_0 capabilities (web)",
"status": "completed",
"priority": "high"
},
{
"content": "Evaluate Gemma 4 E4B Q8_0 feasibility for each worker",
"status": "completed",
"priority": "high"
},
{
"content": "Produce final recommendation with evidence",
"status": "completed",
"priority": "high"
}
]
Gemma 4 E4B (Google DeepMind, Apr 2026, Apache 2.0) β 4.5B effective / 8B total params (Per-Layer Embeddings), 42 layers, hybrid sliding-window (512) + global attention, 128K context, text+image+audio. Q8_0 GGUF is 8.19 GB and fits on 8 GB consumer GPUs (RTX 3070/4070) or unified-memory Macs.
| Workload | Throughput | |---|---| | Prompt processing (pp512) | 6,757 t/s | | Prompt processing (pp16K) | 5,993 t/s | | Generation (tg128/tg256) | ~70 t/s | | TTFT short prompt (warm) | ~390 ms | | Cold start | ~2.4 s | | Context scaling 4Kβ64K | no speed loss (compute-bound, not memory-bound) |
| Benchmark | E4B | Note | |---|---|---| | MMLU Pro | 69.4% | Solid general reasoning | | LiveCodeBench v6 | 52.0% | Adequate for code-aware tasks | | MRCR v2 8-needle @ 128K | 25.4% | Weak long-context retrieval | | JSON parse success (enterprise test) | 100% | Critical for curator/consolidation/query-expand | | JSON schema compliance | 90% | Drops to 50% only on deeply-nested schemas | | Classification / RAG grounding | 92.9% / 91.7% | Specialist sweet spot | | Summarization faithfulness | 80% hallucination-free | Excellent | | Multi-turn (5+ turns) | 0% | Catastrophic β irrelevant for us (workers are single-turn) | | Function calling | 75% | Mid |
Two important operational gotchas (from hands-on reviews):
temperature=0 E4B enters degenerate repetition loops on ~40% of short prompts. Mitigation: repetition_penalty=1.15 (must be set server-side).,,) in JSON; consumers must clean up before parsing. Our existing parseResponse in curator.ts:614 is permissive enough, but worth a test.All workers use the single-turn LLMClient.prompt(system, user) surface β no tool ...
Would it be possible to integrate this into Lore so users don't need to setup their own servers and configure Lore?
That's an interesting question. Let me think through what "integrated local model" means concretely for Lore's architecture.
The fundamental challenge is: Lore currently delegates all LLM work to external servers (cloud APIs or user-managed local servers). Embedding a model inside the Lore process would be a different kind of integration entirely.
Let me explore the options and their feasibility.
[
{
"content": "Explore integration options for bundled local model in Lore",
"status": "in_progress",
"priority": "high"
},
{
"content": "Check existing local embedding infrastructure (already exists)",
"status": "pending",
"priority": "high"
},
{
"content": "Evaluate runtime options: llama.cpp binding, ONNX, subprocess",
"status": "pending",
"priority": "high"
},
{
"content": "Assess binary size / packaging impact",
"status": "pending",
"priority": "high"
},
{
"content": "Produce recommendation with architecture sketch",
"status": "pending",
"priority": "high"
}
]
Let me first look at how Lore already handles local embeddings β that's a proven precedent for bundling ML inference inside the process.
<path>/home/byk/Code/opencode-lore/packages/core/src/embedding-worker.ts</path> <type>file</type> <content> 1: /** 2: * Embedding worker thread β runs ONNX inference via @huggingface/transformers 3: * off the main thread. 4: * 5: * This file is the entry point for a `node:worker_threads` Worker spawned by 6: * `LocalProvider` in `embedding.ts`. It owns the transformers.js pipeline 7: * and processes embed requests sequentially from a priority queue. Moving 8: * inference here keeps the main thread's event loop free β HTTP requests, 9: * SSE streams, and session APIs are no longer blocked during embedding. 10: * 11: * Communication uses `parentPort` message passing with structured clone. 12: * Float32Array vectors are sent back directly (Bun preserves identity). 13: * 14: * The worker applies Nomic's recommended post-processing: 15: * 1. Mean pooling (via pipeline option) 16: * 2. Layer normalization 17: * 3. ...
<path>/home/byk/Code/opencode-lore/packages/core/src/embedding.ts</path>
<type>file</type>
<content>
1: /**
2: * Embedding integration for vector search.
3: *
4: * Supports multiple embedding providers behind a common interface:
5: * - "local" (default): @huggingface/transformers + nomic-embed-text-v1.5
6: * (768 dims, Matryoshka-capable). Runs ONNX inference in a worker thread.
7: * - "voyage": Voyage AI API (voyage-code-3, 1024 dims)
8: * - "openai": OpenAI API (text-embedding-3-small, 1536 dims)
9: *
10: * Provides embedding generation, pure-JS cosine similarity, and vector search
11: * over the knowledge and distillation tables. All operations are gated behind
12: * `search.embeddings.enabled` config + the provider's API key env var β falls
13: * back silently to FTS-only when unavailable.
14: */
15:
16: import { db } from "./db";
17: import { config } from "./config";
18: import * as log from "./log";
19: import { vendorModelInfo } from ...
<path>/home/byk/Code/opencode-lore/packages/gateway/src/cli/sea-entry.ts</path>
<type>file</type>
<content>
1: /**
2: * Fossilize binary entry.
3: *
4: * This is the single entry point that fossilize bundles into the SEA.
5: *
6: * Architecture:
7: * - The native loader shim (auto-injected by esbuild's `inject:`)
8: * runs FIRST and extracts the WASM runtime files to a per-pid
9: * tmp dir.
10: * - This file (sea-entry.ts) reads the embedding worker source
11: * from a SEA asset and exposes it via
12: * `globalThis.__LORE_WORKER_SOURCE__` so `embedding.ts` can
13: * pass it to `new Worker(source, { eval: true, filename, workerData })`.
14: * - If vendoring is enabled, we materialize the model files from
15: * SEA assets to `~/.lore/embeddings-vendored/`.
16: * - We hand off to the main CLI in `bin.ts`. ...
No files found
Now let me check the binary build process and size to understand the packaging constraints.
task_id: ses_15c5e397affeycuMT2p63MyCRz (for resuming to continue this task if needed) <task_result> Now I have all the information needed. Here is a comprehensive report. --- ## Build & Binary Packaging Infrastructure Report ### 1. How the Standalone Binary is Built The build is a **4-step pipeline** orchestrated by `packages/gateway/script/build-binary-sea.ts`: | Step | What happens | |------|-------------| | **Step 1a** | **esbuild** bundles `src/cli/sea-entry.ts` into a single CJS file (`sea-entry.cjs`), targeting Node 22. Key transforms: `onnxruntime-node` is redirected to `onnxruntime-web` (WASM backend), `sharp` is stubbed out, `@sentry/bun` is redirected to `@sentry/node`, and `transformers.js` is patched to read WASM paths from `globalThis.__LORE_VENDOR_WASM_PATHS__` instead of CDN. | | **Step 1b** | **esbuild** bundles the embedding worker (`packages/core/src/embedding-worker.ts`) into a separate CJS file (`worker.cjs`), with the same transforms. ...
task_id: ses_15c5e1b9effe6KR6qBwQruqdOY (for resuming to continue this task if needed) <task_result> Now I have all the data needed. Here's the structured comparison: --- ## llama.cpp Inference in Node.js/Bun β Feasibility Report ### Option 1: `node-llama-cpp` (Native Addon β Clear Winner) | Attribute | Details | |---|---| | **Package** | [`node-llama-cpp`](https://github.com/withcatai/node-llama-cpp) v3.18.1 | | **Weekly downloads** | **184,257** | | **License** | MIT | | **Node requirement** | >= 20.0.0, ESM-only (`"type": "module"`) | | **JS package size** | 32.3 MB (unpacked, includes templates, docs, CLI, git bundle of llama.cpp source) | | **Native binary sizes** | See below | **Prebuilt binary sizes (per-platform optional deps):** | Platform package | Unpacked size | |---|---| | `@node-llama-cpp/mac-arm64-metal` | **5.5 MB** | | `@node-llama-cpp/linux-x64` | 21.3 MB | | `@node-llama-cpp/linux-x64-vulkan` | 78.8 MB | | `@node-llama-cpp/linux-x64-cuda` | **159.5 MB** | | ...
[
{
"content": "Explore integration options for bundled local model in Lore",
"status": "completed",
"priority": "high"
},
{
"content": "Check existing local embedding infrastructure (already exists)",
"status": "completed",
"priority": "high"
},
{
"content": "Evaluate runtime options: llama.cpp binding, ONNX, subprocess",
"status": "completed",
"priority": "high"
},
{
"content": "Assess binary size / packaging impact",
"status": "completed",
"priority": "high"
},
{
"content": "Produce recommendation with architecture sketch",
"status": "in_progress",
"priority": "high"
}
]
[
{
"content": "Explore integration options for bundled local model in Lore",
"status": "completed",
"priority": "high"
},
{
"content": "Check existing local embedding infrastructure (already exists)",
"status": "completed",
"priority": "high"
},
{
"content": "Evaluate runtime options: llama.cpp binding, ONNX, subprocess",
"status": "completed",
"priority": "high"
},
{
"content": "Assess binary size / packaging impact",
"status": "completed",
"priority": "high"
},
{
"content": "Produce recommendation with architecture sketch",
"status": "completed",
"priority": "high"
}
]
| Factor | Value | |---|---| | Current Lore binary (uncompressed) | ~230 MB (with 132 MB vendored embedding model) | | Current Lore binary (gzipped) | ~30 MB | | Gemma 4 E4B Q8_0 model file | 8.19 GB | | Gemma 4 E4B Q4_K_M (smallest usable) | 4.98 GB | | Local embeddings (already vendored) | 132 MB ONNX model in SEA assets | | Delta patch CI limit | 50% of gzipped binary |
The fundamental problem: the model alone is 8 GB. Bundling it would turn a 30 MB download into a 8+ GB download. That's not viable for a CLI tool.
lore auto-downloads and manages llama-server (or Ollama) as a sidecar, like how Docker Desktop manages its VM.
lore start
ββ detects: no ANTHROPIC_API_KEY, no LORE_WORKER_*
ββ checks: ~/.lore/models/gemma-4-e4b-q8_0.gguf exists?
ββ no β prompts: "Download Gemma 4 E4B (8 GB) for free local workers? [Y/n]"
β ββ downloads from HuggingFace Hub to ~/.lore/models/
ββ yes β spawns: llama-server -m ~/.lore/models/... --port <random> -ngl 999 --jinja
ββ sets: internal workerUpstream = http://127.0.0.1:<port>
ββ sets: internal workerApiKey = "local"
ββ sets: internal workerModel = { providerID: "llamacpp", modelID: "gemma-4-e4b" }
ββ worker LLM calls route to local server transparently
Pros:
~/.lore/models/llama-server is a single static binary (~5 MB CPU, ~35 MB with CUDA) β easy to vendor or auto-download/v1/chat/completions β already works with createGatewayLLMClientFile option A as an exploratory issue
<skill_content name="jj-guide"> # Skill: jj-guide # jj Guide for AI Agents Jujutsu (jj) is a Git-compatible VCS with mutable commits, automatic snapshotting, no staging area, and first-class conflicts. This skill teaches you how to use it safely from a non-interactive agent environment. If `.jj/` exists in the repo root, this is a jj repo. **Use `jj` commands, not `git`.** In a colocated repo (`.jj/` *and* `.git/`), git tools can read the state, but mutations should go through `jj` so the operation log stays consistent. ## Critical Rules - **NEVER** use interactive flags (`-i`, `--interactive`). TUI prompts hang in agent environments. This applies to `jj split -i`, `jj squash -i`, `jj commit -i`, `jj resolve`, `jj diffedit`, etc. - **ALWAYS** pass `-m "msg"` when describing/committing. Without `-m`, an editor opens and hangs. - **VERIFY** mutations with `jj st` and `jj log` after `squash`, `abandon`, `rebase`, `restore`, `commit`. ...
Let me create the GitHub issue.
https://github.com/BYK/loreai/issues/607
Filed as #607 β "Explore: Zero-config local LLM workers via managed llama-server subprocess".