@pstdio/prompt-utils 
Tiny utilities for building high-quality LLM prompts and working with JSON streams. This package provides a comprehensive set of tools for creating well-formatted prompts, handling incomplete JSON data, and working with various data transformations commonly needed in LLM workflows.
Install 
npm i @pstdio/prompt-utilsOverview 
The @pstdio/prompt-utils package consists of three main categories of utilities:
- Template Functions: For building clean, well-formatted prompts
- JSON Utilities: For handling streaming and partial JSON data
- Helper Utilities: For common data processing tasks
Template Functions 
These utilities help you build clean, properly formatted prompts with consistent indentation and spacing.
prompt 
A template tag for creating multiline prompts with automatic indentation cleanup.
Features:
- Strips common indentation from all lines
- Trims outer blank lines
- Collapses 3+ consecutive blank lines into 2
- Preserves relative indentation within the content
import { prompt } from "@pstdio/prompt-utils";
const instructions = prompt`
  You are a helpful assistant.
  
  Please follow these guidelines:
    - Be concise and clear
    - Provide examples when helpful
  
  
  
  Always maintain a professional tone.
`;
console.log(instructions);
// Output:
// You are a helpful assistant.
//
// Please follow these guidelines:
//   - Be concise and clear
//   - Provide examples when helpful
//
// Always maintain a professional tone.Variable Interpolation:
const topic = "machine learning";
const complexity = "beginner";
const prompt = prompt`
  Explain ${topic} concepts for a ${complexity} audience.
  
  Use simple examples and avoid jargon.
`;line 
A template tag for creating single-line content by normalizing whitespace and newlines.
import { line } from "@pstdio/prompt-utils";
const title = line`
  Summarize the following
  customer   feedback    and
  identify key themes
`;
console.log(title);
// Output: "Summarize the following customer feedback and identify key themes"listAnd and listOr 
Oxford-style list joiners for creating natural language lists.
import { listAnd, listOr } from "@pstdio/prompt-utils";
// listAnd examples
console.log(listAnd(["apple"])); // "apple"
console.log(listAnd(["apple", "banana"])); // "apple and banana"
console.log(listAnd(["apple", "banana", "cherry"])); // "apple, banana and cherry"
// listOr examples
console.log(listOr(["red", "green", "blue"])); // "red, green or blue"
// Single line option for multi-line templates
const items = ["task A", "task B", "task C"];
const instruction = prompt`
  Complete ${listAnd(items, true)} before proceeding.
  
  Each task should be done carefully.
`;section 
Wraps content in labeled XML-like tags while preserving inner formatting.
import { section, prompt } from "@pstdio/prompt-utils";
const context = prompt`
  The user is asking about TypeScript.
  They are a beginner programmer.
`;
const instructions = prompt`
  Provide a clear explanation.
  Use simple examples.
`;
const fullPrompt = prompt`
  ${section("CONTEXT", context)}
  
  ${section("INSTRUCTIONS", instructions)}
`;
console.log(fullPrompt);
// Output:
// <CONTEXT>
// The user is asking about TypeScript.
// They are a beginner programmer.
// </CONTEXT>
//
// <INSTRUCTIONS>
// Provide a clear explanation.
// Use simple examples.
// </INSTRUCTIONS>JSON Utilities 
These utilities help handle JSON data, especially in streaming scenarios where data might be incomplete.
parseJSONStream 
Attempts to parse potentially incomplete JSON streams by trying progressively shorter prefixes and auto-closing unclosed structures.
import { parseJSONStream } from "@pstdio/prompt-utils";
// Complete JSON - works normally
parseJSONStream('{"name": "John", "age": 30}');
// Returns: { name: "John", age: 30 }
// Incomplete object - salvages valid parts
parseJSONStream('{"name": "John", "age": 30, "email"');
// Returns: { name: "John", age: 30 }
// Incomplete nested object
parseJSONStream('{"user": {"id": 123, "name": "John"');
// Returns: { user: { id: 123 } }
// Incomplete array
parseJSONStream("[1, 2, 3,");
// Returns: [1, 2, 3]
// Invalid JSON
parseJSONStream("not valid json");
// Returns: null
// Empty string
parseJSONStream("");
// Returns: nullUse Cases:
- Processing streaming LLM responses that output JSON
- Handling network timeouts during JSON transfer
- Debugging partial JSON data
getSchema 
Generates a simple JSON-like schema from any JavaScript value.
import { getSchema } from "@pstdio/prompt-utils";
// Primitive types
getSchema("hello"); // { type: "string" }
getSchema(42); // { type: "number" }
getSchema(true); // { type: "boolean" }
getSchema(null); // { type: "null" }
// Arrays
getSchema([1, 2, 3]);
// { type: "array", items: { type: "number" } }
getSchema([]);
// { type: "array", items: { type: "any" } }
// Objects
getSchema({
  name: "John",
  age: 30,
  active: true,
});
// {
//   type: "object",
//   properties: {
//     name: { type: "string" },
//     age: { type: "number" },
//     active: { type: "boolean" }
//   }
// }
// Complex nested structures
getSchema({
  users: [{ id: 1, name: "Alice", tags: ["admin", "active"] }],
});
// {
//   type: "object",
//   properties: {
//     users: {
//       type: "array",
//       items: {
//         type: "object",
//         properties: {
//           id: { type: "number" },
//           name: { type: "string" },
//           tags: { type: "array", items: { type: "string" } }
//         }
//       }
//     }
//   }
// }safeParse 
JSON.parse that gracefully falls back to the original string on failure.
import { safeParse } from "@pstdio/prompt-utils";
// Valid JSON
safeParse<{ name: string }>('{"name": "John"}');
// Returns: { name: "John" }
// Invalid JSON - returns original string
safeParse("not json");
// Returns: "not json"
// TypeScript support
interface User {
  id: number;
  name: string;
}
const result = safeParse<User>('{"id": 123, "name": "Alice"}');
// Type: User | stringsafeStringify 
Stable JSON stringification with BigInt support and numeric string normalization.
import { safeStringify } from "@pstdio/prompt-utils";
const data = {
  id: BigInt(123456789012345),
  count: "42", // String that looks like a number
  name: "test",
  quote: 'He said "hello"',
};
safeStringify(data);
// Returns consistent string representation
// BigInts converted to numbers
// Numeric strings converted to numbers
// Quotes handled safelyHelper Utilities 
hashString 
Fast FNV-1a 32-bit hash function that works in both browser and Node.js.
import { hashString } from "@pstdio/prompt-utils";
await hashString("hello world");
// Returns: "b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9"
await hashString("different input");Use Cases:
- Creating cache keys
- Generating deterministic IDs
- Content deduplication
shortUID 
Generates short, LLM-friendly unique identifiers.
import { shortUID } from "@pstdio/prompt-utils";
shortUID();
// Returns: "r4k2m8" (6 random chars with default "r" prefix)
shortUID("task");
// Returns: "task7n3x1q"
shortUID("user");
// Returns: "user9m4k2p"Features:
- Uses LLM-friendly alphabet (no confusing characters like 0/O, 1/l)
- Short length (6 characters + prefix)
- Customizable prefix for categorization
Real-World Examples 
Building Complex Prompts 
import { prompt, section, listAnd } from "@pstdio/prompt-utils";
function createCodeReviewPrompt(language: string, concerns: string[], codeSnippet: string) {
  const context = prompt`
    Language: ${language}
    Review Focus: ${listAnd(concerns)}
  `;
  const instructions = prompt`
    1. Analyze the code for the specified concerns
    2. Provide specific, actionable feedback
    3. Suggest improvements with examples
    4. Rate overall code quality (1-10)
  `;
  const code = section("CODE", codeSnippet);
  return prompt`
    ${section("CONTEXT", context)}
    
    ${section("INSTRUCTIONS", instructions)}
    
    ${code}
  `;
}
const reviewPrompt = createCodeReviewPrompt(
  "TypeScript",
  ["performance", "security", "maintainability"],
  `
    function processUser(data: any) {
      return data.users.map(u => u.name.toUpperCase());
    }
  `,
);Processing Streaming JSON from LLMs 
import { parseJSONStream } from "@pstdio/prompt-utils";
// Simulate processing a streaming response
function processStreamingResponse(chunks: string[]) {
  let accumulated = "";
  for (const chunk of chunks) {
    accumulated += chunk;
    // Try to parse the current accumulated data
    const parsed = parseJSONStream(accumulated);
    if (parsed) {
      console.log("Successfully parsed:", parsed);
      // Process the valid JSON...
    }
  }
}
// Example chunks from streaming response
processStreamingResponse([
  '{"analysis": {',
  '"sentiment": "positive",',
  '"confidence": 0.8',
  // Stream might end abruptly here
]);Schema-Driven Validation 
import { getSchema, safeStringify } from "@pstdio/prompt-utils";
function validateAndDescribeData(data: unknown) {
  const schema = getSchema(data);
  return {
    data: safeStringify(data),
    schema: safeStringify(schema),
    summary: `Data contains ${schema.type} with ${
      schema.properties
        ? Object.keys(schema.properties).length + " properties"
        : schema.items
          ? "items of type " + schema.items.type
          : "primitive value"
    }`,
  };
}Best Practices 
Template Functions 
- Use promptfor multi-line content that needs clean formatting
- Use linefor titles, labels, and single-line content
- Use sectionto create clearly delimited blocks in your prompts
- Combine with listAnd/listOrfor natural language lists
JSON Utilities 
- Use parseJSONStreamwhen dealing with potentially incomplete data
- Use safeParsewhen you want to handle both JSON and plain text
- Use getSchemato understand the structure of dynamic data
- Use safeStringifyfor consistent serialization
Helper Utilities 
- Use hashStringfor creating deterministic keys or IDs
- Use shortUIDwhen you need human/LLM-readable unique identifiers
TypeScript Support 
All functions include full TypeScript definitions:
// Template tags
function prompt(strings: TemplateStringsArray, ...values: any[]): string;
function line(strings: TemplateStringsArray, ...values: any[]): string;
// List functions
function listAnd(items: string[], singleLine?: boolean): string;
function listOr(items: string[], singleLine?: boolean): string;
// Section function
function section(label: string, body: string): string;
// JSON utilities
function parseJSONStream(input: string): any | null;
function getSchema(input: any): Schema;
function safeParse<T = object>(str: string): T | string;
function safeStringify(result: object): string;
// Helper utilities
function hashString(str: string): Promise<string>;
function shortUID(prefix?: string): string;ESM-only package - use import syntax.