Show HN: A tagged template literal utility for clean LLM prompt generation
4 months ago
18
A lightweight utility for building clean, composable, and maintainable LLM prompts using tagged template literals.
import{prompt}from'llm-prompt-tag';constproblems=["String concatenation","Conditional logic mess","Formatting inconsistencies","Hard to maintain"];constsolutions=["Tagged templates","Conditional sections","Automatic formatting","Composable structure"];constincludeDebugInfo=false;constmsg=prompt()` You are a helpful AI assistant. It can be really annoying to put all the conditional data in your prompts.${prompt('Problems with creating prompts')`${problems}`}${prompt('Solutions from llm-prompt-tag')`${solutions}`}${prompt('Debug Info',includeDebugInfo)`This section only appears when debugging`} Now I can make complex, conditional, formatted prompts I can still read thanks to llm-prompt-tag!`;console.log(msg);
Output:
You are a helpful AI assistant. It can be really annoying to put all the conditional data in your prompts.
==== Problems with creating prompts ====
String concatenation
Conditional logic mess
Formatting inconsistencies
Hard to maintain
==== End of Problems with creating prompts ====
==== Solutions from llm-prompt-tag ====
Tagged templates
Conditional sections
Automatic formatting
Composable structure
==== End of Solutions from llm-prompt-tag ====
Now I can make complex, conditional, formatted prompts I can still read thanks to llm-prompt-tag!
✅ makePrompt generator for type-safe extensibility
✅ Smart array formatting with customizable separators
✅ No dependencies
npm install llm-prompt-tag
import{prompt}from'llm-prompt-tag';constresult=prompt('Instructions')` Write a short, direct note using the user's own words.`;console.log(result);
Output:
==== Instructions ====
Write a short, direct note using the user's own words.
==== End of Instructions ====
constshowHelp=false;constresult=prompt('Help Section',showHelp)` If you get stuck, refer to the user's original notes.`;console.log(result);
Output:
(empty string - no output because condition is false)
With condition true:
constshowHelp=true;constresult=prompt('Help Section',showHelp)` If you get stuck, refer to the user's original notes.`;console.log(result);
Output:
==== Help Section ====
If you get stuck, refer to the user's original notes.
==== End of Help Section ====
🏷️ Semantic Naming Patterns
Some people may prefer to rename the function for two distinct purposes: a simpler tag p for the overall template, and a separate one for sections.
This approach can be more readable and semantic:
import{prompt}from'llm-prompt-tag';// Use 'section' for structured sectionsconstsection=prompt;// Use a plain wrapper for the main contentconstp=prompt();constsomeVariable="User prefers dark mode";constnotes="Remember to save work frequently";constresult=p`You are a helpful AI assistant.${section('User Settings')`${someVariable}`}${section('Notes')`The user's notes are: ${notes}`}Whatever approach feels cleaner to you!`;console.log(result);
Output:
You are a helpful AI assistant.
==== User Settings ====
User prefers dark mode
==== End of User Settings ====
==== Notes ====
The user's notes are: Remember to save work frequently
==== End of Notes ====
Whatever approach feels cleaner to you!
🧱 Extending with makePrompt
If you have custom objects you're putting into your prompts you can make that easier/cleaner by using the makePrompt generator with a list of types and their to-text formatters.
Example:
import{makePrompt}from'llm-prompt-tag';classNote{constructor(publictitle: string,publiccontent: string){}}constnote2Text=(note: Note)=>`• ${note.title}\n${note.content}`;constpromptWithNotes=makePrompt({Note: note2Text});constnote=newNote("LLM Summary","LLMs are transforming software development.");constresult=promptWithNotes('User\'s Notes')` Here's a user note:${note}`;console.log(result);
Output:
==== User's Notes ====
Here's a user note:
• LLM Summary
LLMs are transforming software development.
==== End of User's Notes ====
To keep templates simpler, arrays of registered types are automatically formatted. By default, items are separated with double newlines for clean readability:
==== Project Status ====
Current items:
📝 Meeting: Discuss project timeline
⏳ Review code
==== End of Project Status ====
Prompts can be nested and composed together:
constsystemPrompt=prompt('System')` You are a helpful AI assistant.`;constuserContext=prompt('User Context')` User: Alice Task: Help prioritize work`;constfullPrompt=prompt()`${systemPrompt}${userContext} Please provide helpful guidance.`;console.log(fullPrompt);
Output:
==== System ====
You are a helpful AI assistant.
==== End of System ====
==== User Context ====
User: Alice
Task: Help prioritize work
==== End of User Context ====
Please provide helpful guidance.
The library includes comprehensive tests that demonstrate usage patterns:
import{prompt,makePrompt}from'llm-prompt-tag';// Basic usageconstresult=prompt('Intro')` Hello world.`;// Output: "==== Intro ====\nHello world.\n==== End of Intro ===="// With custom formattersclassNote{constructor(publictitle: string,publiccontent: string){}}constnoteFormatter=(note: Note)=>`• ${note.title}\n${note.content}`;constcustomPrompt=makePrompt({Note: noteFormatter});constnote=newNote("Meeting","Discuss project timeline");constformatted=customPrompt('Notes')`${note}`;// Output: "==== Notes ====\n• Meeting\nDiscuss project timeline\n==== End of Notes ===="
prompt(header?, condition?)
Creates a tagged template literal function for building prompts.
Parameters:
header (optional): String to use as section header
condition (optional): Boolean to conditionally render the section (default: true)
Returns: A tagged template function
Creates a customizable prompt function with type-specific formatters.
Parameters:
formatters: Object with constructor names as keys and formatter functions as values. Special key Array can customize array formatting.
Returns: A prompt function with custom formatting capabilities
Example:
constcustomPrompt=makePrompt({Note: (note)=>`• ${note.title}\n${note.content}`,Task: (task)=>`[${task.completed ? 'x' : ' '}] ${task.name}`,Array: (items,formatter)=>items.map(formatter).join(' | ')// Custom separator for list items});
# Install dependencies
npm install
# Build the library
npm run build
# Run tests
npm test# Development mode with watch
npm run dev
The library consists of two main modules:
Core tagged template implementation with whitespace cleanup and conditional rendering.
Extension mechanism for registering custom object formatters.