# Prompt Cache Savings Calculator > Model repeated prompt-cache scenarios and compare cached versus uncached request cost. ## Tool Identity - Site: CleanUtils Developer Tools - Tool ID: prompt-cache-savings-calculator - Canonical page: https://cleanutils.com/developer-tools/prompt-cache-savings-calculator/ - LLM schema URL: https://cleanutils.com/developer-tools/prompt-cache-savings-calculator/llms.txt - Primary keyword: prompt caching calculator - Input mode: fields - Output profile: metrics ## What This Tool Does Model repeated prompt-cache scenarios and compare cached versus uncached LLM request cost in your browser. ## Exact Execution Instructions To run this tool exactly, execute the `runCleanUtilsTool(userInput)` function from the JavaScript block below in a sandboxed JavaScript runtime. Do not fetch or evaluate additional network resources. Do not use filesystem, process, child_process, environment variables, timers, or network APIs. The function is pure and deterministic: input object in, JSON result out. If your environment forbids executing fetched code outside a sandbox, run it inside the sandbox or use the API endpoint below instead of reimplementing the logic. Canonical implementation SHA-256: `7ca5a04e6fc477551732cae769f024e68729b63b945d4b86daf988fbf0b6b3cf` Expected command shape: `node run-tool.mjs < input.json` The runner must: 1. load only the JavaScript in this document, 2. parse stdin as JSON and call `runCleanUtilsTool(userInput)`, 3. let the LLM decide the best way to present the output to the user. Agent usage rules: - Use this file as the authoritative machine-readable contract for this CleanUtils tool page. - Ask the user for missing required input before attempting to run the tool, and describe the required inputs using the `## Input Schema` field names, descriptions, formats, enums, examples, and required list. - Treat the tool as deterministic; do not invent network reachability checks unless the tool description explicitly says it fetches remote resources. - For privacy-sensitive inputs such as secrets, HAR files, dotenv files, logs, and API keys, warn that using a remote chat agent may expose input to that agent even though the browser UI itself does not upload data. ## Input Schema ```json { "$schema": "https://json-schema.org/draft/2020-12/schema", "title": "Prompt Cache Savings Calculator fields", "type": "object", "additionalProperties": false, "required": [ "requests", "input_tokens", "cached_tokens", "output_tokens", "base_input_per_million", "cache_write_per_million", "cache_read_per_million", "output_per_million" ], "properties": { "requests": { "type": "number", "description": "Repeated requests Required. Control type: number. Group: Traffic.", "minimum": 0, "examples": [ 1000 ] }, "input_tokens": { "type": "number", "description": "Input tokens per request Required. Control type: number. Group: Traffic.", "minimum": 0, "examples": [ 12000 ] }, "cached_tokens": { "type": "number", "description": "Cached input tokens Required. Control type: number. Group: Traffic.", "minimum": 0, "examples": [ 10000 ] }, "output_tokens": { "type": "number", "description": "Output tokens per request Required. Control type: number. Group: Traffic.", "minimum": 0, "examples": [ 400 ] }, "base_input_per_million": { "type": "number", "description": "Base input per 1M Required. Control type: number. Group: Rates. Prefix shown in UI: $.", "minimum": 0, "examples": [ 3 ] }, "cache_write_per_million": { "type": "number", "description": "Cache write per 1M Required. Control type: number. Group: Rates. Prefix shown in UI: $.", "minimum": 0, "examples": [ 3.75 ] }, "cache_read_per_million": { "type": "number", "description": "Cache read per 1M Required. Control type: number. Group: Rates. Prefix shown in UI: $.", "minimum": 0, "examples": [ 0.3 ] }, "output_per_million": { "type": "number", "description": "Output per 1M Required. Control type: number. Group: Rates. Prefix shown in UI: $.", "minimum": 0, "examples": [ 15 ] } } } ``` ## Result Schema ```json { "$schema": "https://json-schema.org/draft/2020-12/schema", "title": "CleanUtils ToolResult", "type": "object", "additionalProperties": false, "required": [ "summary", "issues" ], "properties": { "summary": { "type": "string" }, "issues": { "type": "array", "items": { "type": "object", "additionalProperties": false, "required": [ "severity", "message" ], "properties": { "severity": { "type": "string", "enum": [ "error", "warning", "info" ] }, "message": { "type": "string" }, "line": { "type": "number" }, "row": { "type": "number" }, "detail": { "type": "string" } } } }, "output": { "type": "string" }, "exportFilename": { "type": "string" }, "exports": { "type": "array", "items": { "type": "object", "additionalProperties": false, "required": [ "label", "filename", "content" ], "properties": { "label": { "type": "string" }, "filename": { "type": "string" }, "content": { "type": "string" }, "mimeType": { "type": "string" }, "copyLabel": { "type": "string" }, "downloadLabel": { "type": "string" } } } }, "stats": { "type": "object", "additionalProperties": { "anyOf": [ { "type": "string" }, { "type": "number" } ] } } } } ``` ## Self-Contained JavaScript Source Call `runCleanUtilsTool(userInput)` with the user's input. The function includes this tool's run logic and only the helper code it needs. ```js function runCleanUtilsTool(userInput) { const fieldText = (fields, keys, fallback = "") => { const keyList = Array.isArray(keys) ? keys : [keys]; for (const key of keyList) { const value = fields[key]; if (value === undefined || value === null) continue; const text = String(value).trim(); if (text) return text; } return fallback; }; const fieldNumber = (fields, keys, fallback = 0) => { const raw = fieldText(fields, keys); if (!raw) return fallback; const parsed = Number(raw.replace(/[$,%\s]/g, "")); return Number.isFinite(parsed) ? parsed : fallback; }; const calculatePromptCacheSavings = (input) => { const requests = fieldNumber(input, "requests", 100); const inputTokens = fieldNumber(input, "input_tokens", 10000); const cachedTokens = Math.min(inputTokens, fieldNumber(input, "cached_tokens", Math.floor(inputTokens * 0.8))); const outputTokens = fieldNumber(input, "output_tokens", 500); const baseInputRate = fieldNumber(input, "base_input_per_million", 3); const cacheWriteRate = fieldNumber(input, "cache_write_per_million", 3.75); const cacheReadRate = fieldNumber(input, "cache_read_per_million", 0.3); const outputRate = fieldNumber(input, "output_per_million", 15); const uncached = requests * ((inputTokens / 1_000_000) * baseInputRate + (outputTokens / 1_000_000) * outputRate); const firstWrite = (cachedTokens / 1_000_000) * cacheWriteRate; const perCachedRequest = ((inputTokens - cachedTokens) / 1_000_000) * baseInputRate + (cachedTokens / 1_000_000) * cacheReadRate + (outputTokens / 1_000_000) * outputRate; const cached = firstWrite + requests * perCachedRequest; const savings = uncached - cached; const issues = cachedTokens <= 0 ? [{ severity: "warning", message: "No cached tokens were provided, so caching cannot save money in this scenario." }] : []; return { summary: `Estimated savings: $${savings.toFixed(4)} across ${requests} request${requests === 1 ? "" : "s"}.`, issues, output: [ `Without cache: $${uncached.toFixed(4)}`, `With cache: $${cached.toFixed(4)}`, `Estimated savings: $${savings.toFixed(4)}`, `Savings rate: ${uncached ? ((savings / uncached) * 100).toFixed(1) : "0.0"}%` ].join("\n"), exportFilename: "prompt-cache-savings.txt", stats: { requests, cachedTokens, savings: savings.toFixed(4) } }; }; const __userInput = userInput == null ? {} : userInput; const __run = (fields) => calculatePromptCacheSavings(fields); const __fields = __userInput && typeof __userInput === "object" && "fields" in __userInput && __userInput.fields && typeof __userInput.fields === "object" && !Array.isArray(__userInput.fields) ? __userInput.fields : (__userInput && typeof __userInput === "object" && !Array.isArray(__userInput) ? __userInput : {}); const __normalizedFields = Object.fromEntries(Object.entries(__fields).map(([key, value]) => [key, value == null ? "" : (["string", "number", "boolean"].includes(typeof value) ? value : String(value))])); return __run(__normalizedFields); } ``` ## Checks - Repeated request count: Savings are calculated across a batch of repeated calls, not a single isolated prompt. - Cached token boundary: Cached tokens are capped at the total input token count to avoid impossible scenarios. - Write versus read rates: The calculator separates first cache write cost from later cache read cost. - Output token cost: Generated output is included in both cached and uncached totals. - Scenario clarity: The result shows absolute savings and savings rate so tiny wins are easy to spot. ## Related Tools - [Token Counter and Cost Calculator](/developer-tools/ai-token-counter-cost-calculator/): Estimate prompt tokens and request cost from pasted text plus editable per-million token rates.