TypeScript AI Prompt Engineering

A developer guide to token budgeting, prompt construction, and provider prompt caching strategies in TypeScript.

TL;DR

  1. Calculate token counts locally using js-tiktoken or SDK tokenizers.
  2. Place static instructions at the start of system prompts.
  3. Mark Anthropic cache breakpoints using cache_control: { type: 'ephemeral' }.

Token Counting and Budgeting

    js-tiktoken counter

    Calculate 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 guard

    Verify 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 trimmer

    Trim 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 template

    Structure 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 constraints

    Instruct 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 formatting

    Provide 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 breakpoint

    Mark 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 metrics

    Inspect 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 breakpoint

    Cache 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 pattern

    Order 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 check

    Read 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 builder

    Generate immutable prefix string for repeated sessions.

    function getPrefix(apiDocs: string): string {
      return `Docs:\n${apiDocs}\nRules: Be concise.`;
    }

Tips

  1. Keep static system prompts and tool definitions at the beginning of message arrays to trigger automatic prompt caching across API calls.
  2. Calculate token consumption locally using js-tiktoken before sending prompts to avoid unexpected context window overflow exceptions.

Warnings

  1. Avoid inserting dynamic values like timestamps into the initial system prompt because altering the prefix breaks prompt caching completely.
  2. Remember that Anthropic requires a minimum of 1024 prompt tokens before cache_control can successfully generate reusable cache entries.

In Practice

FAQ