LLM prompt engineering plugin for Stampdown
npm install @stampdwn/llmSpecialized Stampdown plugin for LLM prompt templating with multi-provider support.
``bash`
npm install @stampdwn/llm
`typescript
import { Stampdown } from '@stampdwn/core';
import { llmPlugin } from '@stampdwn/llm';
const stampdown = new Stampdown({
plugins: [llmPlugin]
});
const template =
{{#withChat raw=chat}}
{{#eachMessage}}
{{#ifUser}}👤 User: {{#firstText this/}}{{/ifUser}}
{{#ifAssistant}}🤖 Assistant: {{#firstText this/}}{{/ifAssistant}}
{{/eachMessage}}
{{/withChat}};
const result = stampdown.render(template, {
chat: {
provider: 'openai',
model: 'gpt-4',
messages: [
{ role: 'user', content: [{ type: 'text', text: 'Hello!' }] },
{ role: 'assistant', content: [{ type: 'text', text: 'Hi there!' }] }
]
}
});
`
The plugin normalizes messages from different LLM providers via @ai-sdk:
- OpenAI (GPT-3.5, GPT-4, etc.)
- Anthropic (Claude)
- Azure OpenAI
- Google Vertex AI
- Custom providers via @ai-sdk
All providers are normalized to a consistent internal format, so your templates work across any provider.
#### withChat
Normalizes raw chat payload and sets as block context.
`markdown`
{{#withChat raw=chat}}
{{/withChat}}
#### eachMessage
Iterates over all messages with special variables.
`markdown`
{{#eachMessage}}
Message {{@index}}: {{#firstText this/}}
{{/eachMessage}}
#### eachByRole
Iterates over messages filtered by role.
`markdown`
{{#eachByRole role="user"}}
User {{@index}}: {{#firstText this/}}
{{/eachByRole}}
#### ifUser, ifAssistant, ifSystem, ifTool
Conditional rendering based on message role.
`markdown`
{{#eachMessage}}
{{#ifUser}}👤 {{#firstText this/}}{{/ifUser}}
{{#ifAssistant}}🤖 {{#firstText this/}}{{/ifAssistant}}
{{/eachMessage}}
#### eachContent
Iterates over all content items in a message.
`markdown`
{{#eachContent}}
Type: {{type}}, Content: {{#if type === "text"}}{{text}}{{/if}}
{{/eachContent}}
#### eachText
Iterates over text content only.
`markdown`
{{#eachText}}
{{this}}
{{/eachText}}
#### joinText
Joins all text content with separator.
`markdown`
{{#joinText messages sep=" | "/}}
#### firstText, lastText
Gets first or last text content from message.
`markdown`
First: {{#firstText message/}}
Last: {{#lastText message/}}
#### window
Selects message range with optional role filter.
`markdown`
{{#window size=5 from="end" role="user"}}
{{#eachMessage}}...{{/eachMessage}}
{{/window}}
#### tokenCount
Counts tokens in text using gpt-tokenizer.
`markdown`
Tokens: {{#tokenCount text/}}
#### truncateTokens
Truncates by token limit with different modes.
`markdown
{{#truncateTokens text max=100 on="text"/}}
{{#truncateTokens message max=200 on="message"/}}
{{#truncateTokens max=500 on="block"}}
Long content here...
{{/truncateTokens}}
`
#### json, yaml, toon
Stringifies value as JSON, YAML or TOON
`markdown`
{{#json chat/}}
{{#yaml config/}}
{{#toon chat/}}
#### renderChat
Converts chat to provider-specific format.
`markdown`
{{#renderChat chat format="json" shape="openai"/}}
{{#renderChat chat format="yaml" shape="anthropic"/}}
Provide your own tokenization logic:
`typescript
import { llmPlugin, type Tokenizer } from '@stampdwn/llm';
const customTokenizer: Tokenizer = {
count: (text: string) => text.split(/\s+/).length,
truncateByTokens: (text: string, maxTokens: number) => {
const words = text.split(/\s+/);
return words.slice(0, maxTokens).join(' ');
}
};
const stampdown = new Stampdown({
plugins: [
{
...llmPlugin,
options: { tokenizer: customTokenizer }
}
]
});
`
Full API reference: packages/llm/docs/index.md`
This package is part of the Stampdown ecosystem:
- @stampdwn/core - Core templating engine
- @stampdwn/cli - Command-line interface
- @stampdwn/codemirror - Code mirror language support
- @stampdwn/vscode - VS Code extension
MIT