TypeScript AI Prompt Engineering
A developer guide to token budgeting, prompt construction, and provider prompt caching strategies in TypeScript.
TL;DR
- Calculate token counts locally using
js-tiktokenor SDK tokenizers. - Place static instructions at the start of
systemprompts. - Mark Anthropic cache breakpoints using
cache_control: { type: 'ephemeral' }.
Token Counting and Budgeting
js-tiktoken counterCalculate exact token length of strings locally in Node.
import { getEncoding } from 'js-tiktoken';
const enc = getEncoding('cl100k_base');
function countTokens(text: string): number {
return enc.encode(text).length;
}Context window budget guardVerify token budget before initiating network call.
const maxLimit = 8192;
const tokenTotal = countTokens(systemPrompt + prompt);
if (tokenTotal > maxLimit) {
throw new Error(`Exceeds limit: ${tokenTotal}`);
}Sliding window trimmerTrim conversation history to preserve most recent messages.
function trimHistory(msgs: any[], max = 4000) {
let sum = 0;
return msgs.filter(m => {
sum += countTokens(m.content);
return sum <= max;
});
}System Instructions and Composition
XML tagged prompt templateStructure guidelines and few-shot examples with XML tags.
function buildPrompt(task: string, doc: string) {
return `<instructions>\n` +
`Analyze the document cleanly.\n` +
`</instructions>\n` +
`<document>\n${doc}\n</document>\n` +
`<task>\n${task}\n</task>`;
}Strict system constraintsInstruct model on formatting rules and boundary constraints.
const system = [
'You are a senior TypeScript engineer.',
'Only reply with valid TypeScript code.',
'Do not include markdown or explanations.',
].join('\n');Few-shot examples formattingProvide input-output demonstrations to guide style.
const fewShot = [
{ role: 'user' as const, content: 'slug("Test")' },
{ role: 'assistant' as const, content: '"test"' },
];Anthropic Prompt Caching
cache_control breakpointMark system blocks for ephemeral caching in Claude.
const res = await anthropic.messages.create({
model: 'claude-3-5-sonnet-20241022',
max_tokens: 1024,
system: [{
type: 'text', text: docs,
cache_control: { type: 'ephemeral' },
}],
messages: [{ role: 'user', content: 'Hi' }],
});Auditing cache hit metricsInspect response tokens to measure cache savings.
const u = res.usage as any;
const created = u.cache_creation_input_tokens;
console.log('Cache created:', created);Tool cache breakpointCache long tool definitions array using breakpoint.
const tools = [
{
name: 'search_db',
description: 'Search internal records',
input_schema: { type: 'object', properties: {} },
cache_control: { type: 'ephemeral' },
},
];OpenAI Prefix Caching
Prefix stability patternOrder message sequence to maximize automatic cache hits.
const messages = [
{ role: 'system' as const, content: staticSystem },
{ role: 'user' as const, content: staticDocs },
{ role: 'user' as const, content: dynamicQuery },
];Cached tokens usage checkRead cached prompt token statistics from OpenAI response.
const details = res.usage?.prompt_tokens_details;
const cached = details?.cached_tokens ?? 0;
console.log('Tokens read from cache:', cached);Static prefix builderGenerate immutable prefix string for repeated sessions.
function getPrefix(apiDocs: string): string {
return `Docs:\n${apiDocs}\nRules: Be concise.`;
}Tips
- Keep static
systemprompts and tool definitions at the beginning of message arrays to trigger automatic prompt caching across API calls. - Calculate token consumption locally using
js-tiktokenbefore sending prompts to avoid unexpected context window overflow exceptions.
Warnings
- Avoid inserting dynamic values like timestamps into the initial
systemprompt because altering the prefix breaks prompt caching completely. - Remember that Anthropic requires a minimum of 1024 prompt tokens before
cache_controlcan successfully generate reusable cache entries.
In Practice
A reusable prompt builder that calculates token limits and configures Anthropic prompt caching breakpoints.
- Assemble a static system prompt exceeding the 1024 token caching limit.
- Attach the ephemeral cache_control breakpoint to the system block.
- Dispatch the message request to Claude 3.5 Sonnet.
- Inspect usage metadata to confirm cache creation and read hits.
import Anthropic from '@anthropic-ai/sdk';
export async function askWithCache(
context: string,
query: string
) {
const anthropic = new Anthropic();
const res = await anthropic.messages.create({
model: 'claude-3-5-sonnet-20241022',
max_tokens: 500,
system: [{
type: 'text',
text: context,
cache_control: { type: 'ephemeral' },
}],
messages: [{ role: 'user', content: query }],
});
const usage = res.usage as any;
return {
answer: res.content[0].text,
cached: usage.cache_read_input_tokens > 0,
};
}FAQ
OpenAI provides automatic prefix caching when prompts exceed 1024 tokens without requiring special parameters. Anthropic requires you to explicitly place cache_control: { type: 'ephemeral' } on static system or tool message blocks.
Install js-tiktoken and load the target model encoding with getEncoding('cl100k_base'). Call encoding.encode(text).length to calculate exact token counts without making network requests.
Prompt caching operates on an exact prefix match. If you alter a single character, timestamp, or tool definition earlier in the prompt, the entire cached prefix is invalidated.