Kahani supports two modes for interacting with language models:
- Chat Completion API - Standard message-based format (default)
- Text Completion API - Raw prompt format with custom templates (new)
This guide covers everything you need to know about using Text Completion mode.
- Your model doesn't support Chat Completion API properly
- You're using instruction-tuned local models (Llama, Mistral, Qwen, GLM)
- You need full control over prompt formatting
- Chat mode produces poor results or errors
- Your backend only exposes
/v1/completionsendpoint - You want to use models with specific prompt templates
- Using OpenAI, Anthropic, or other major API providers
- Your model explicitly supports the Chat Completion format
- Using Ollama (it handles formatting automatically)
- You prefer standardized message-based interactions
In Settings Modal (Quick Settings):
- Click the Settings icon in the story interface
- Navigate to LLM Settings section
- Find "Completion API Mode"
- Select "Text Completion API"
- Choose a template preset or customize
In Settings Page (Full Settings):
- Go to Settings from the main menu
- Select "LLM Settings" tab
- Scroll to "Completion API Mode"
- Select "Text Completion API"
- Configure your template
Kahani includes 5 pre-built templates:
<|begin_of_text|><|start_header_id|>system<|end_header_id|>
{system_prompt}<|eot_id|><|start_header_id|>user<|end_header_id|>
{user_instruction}<|eot_id|><|start_header_id|>assistant<|end_header_id|>
Compatible Models:
- Llama 3, 3.1, 3.2 Instruct
- Llama 3.3 Instruct
- Fine-tunes based on Llama 3 architecture
<s>[INST] {system_prompt}
{user_instruction} [/INST]
Compatible Models:
- Mistral 7B Instruct
- Mixtral 8x7B Instruct
- Mistral Small/Medium/Large Instruct
<|im_start|>system
{system_prompt}<|im_end|>
<|im_start|>user
{user_instruction}<|im_end|>
<|im_start|>assistant
Compatible Models:
- Qwen2 Instruct (all sizes)
- Qwen2.5 Instruct (all sizes)
- QwQ (reasoning model)
[gMASK]<sop><|system|>
{system_prompt}<|user|>
{user_instruction}<|assistant|>
Compatible Models:
- ChatGLM2
- ChatGLM3
- GLM-4
### System:
{system_prompt}
### Instruction:
{user_instruction}
### Response:
Compatible Models:
- Alpaca-style models
- Vicuna models
- Other instruction-tuned models without specific formatting
If the presets don't match your model, create a custom template:
- Select "Custom" from the preset dropdown
- Click "Customize" to edit the template
- Configure these fields:
Template Components:
| Field | Description | Example |
|---|---|---|
bos_token |
Beginning of sequence token | `< |
eos_token |
End of sequence token | `< |
system_prefix |
Text before system prompt | `< |
system_suffix |
Text after system prompt | `< |
instruction_prefix |
Text before user instruction | `< |
instruction_suffix |
Text after user instruction | `< |
response_prefix |
Text before assistant response | `< |
Available Variables:
{{system}}- System prompt content{{user_prompt}}- User instruction content{{bos}}- Beginning of sequence token{{eos}}- End of sequence token
Before using in production:
- Click "Test Template" in the editor
- Enter sample system and user prompts
- Review the assembled prompt in the preview pane
- Verify it matches your model's expected format
- Test with actual generation to confirm
Some models (especially reasoning models) include internal "thinking" or "reasoning" in their output:
<think>
Let me analyze the user's request...
The story needs more tension...
</think>
The character stepped into the dark room...
Kahani automatically detects and strips these tags:
Supported Patterns:
<think>...</think>(DeepSeek)<reasoning>...</reasoning>(Qwen)[THINKING]...[/THINKING][System]...[/System][no_think]...[/no_think]- And more...
Result:
The character stepped into the dark room...
If your model uses different thinking tags:
- Open
backend/app/services/llm/thinking_parser.py - Add your pattern to the
THINKING_PATTERNSlist:
THINKING_PATTERNS = [
# ... existing patterns ...
(r'<your_tag>.*?</your_tag>', re.DOTALL | re.IGNORECASE),
]- Restart the backend
Templates are stored as JSON in the database:
{
"name": "Llama 3 Instruct",
"bos_token": "<|begin_of_text|>",
"eos_token": "<|eot_id|>",
"system_prefix": "<|start_header_id|>system<|end_header_id|>\n\n",
"system_suffix": "<|eot_id|>",
"instruction_prefix": "<|start_header_id|>user<|end_header_id|>\n\n",
"instruction_suffix": "<|eot_id|>",
"response_prefix": "<|start_header_id|>assistant<|end_header_id|>\n\n"
}For programmatic access:
Get Available Presets:
GET /api/settings/text-completion/presets
Authorization: Bearer YOUR_TOKENGet Preset Template:
GET /api/settings/text-completion/template/{preset_name}
Authorization: Bearer YOUR_TOKENTest Template Rendering:
POST /api/settings/text-completion/test-render
Authorization: Bearer YOUR_TOKEN
Content-Type: application/json
{
"template": {...},
"test_system": "You are a storyteller",
"test_user": "Write a scene"
}Symptoms:
- Output doesn't make sense
- Model ignores instructions
- Produces random tokens
Solutions:
- Verify template matches model's training format
- Check model documentation for correct prompt format
- Try a different preset template
- Ensure you're using the instruction-tuned version of the model
Symptoms:
- Empty or very short output
- Generation ends after a few tokens
Solutions:
- Check
response_prefixis correct - Verify BOS/EOS tokens match the model's tokenizer
- Some models are sensitive to exact spacing and newlines
- Try removing or adjusting the
response_prefix
Symptoms:
- Model's reasoning appears in the story
- Tags like
<think>visible to users
Solutions:
- Thinking tags should be auto-stripped
- Check
backend/logs/kahani.logfor parser errors - Add custom pattern in
thinking_parser.py - Report the pattern so we can add it to defaults
Symptoms:
- "Connection failed" error
- "Invalid response format" error
Solutions:
- Verify your backend supports
/v1/completionsendpoint - Test endpoint:
curl http://your-api/v1/completions - Check if backend requires specific headers
- Try Chat Completion mode instead
- For TabbyAPI/LM Studio, ensure text completion is enabled
Symptoms:
- Sometimes works, sometimes doesn't
- Quality varies significantly
Solutions:
- Check generation parameters (temperature, top_p, etc.)
- Verify template is consistently applied
- Test with simpler prompts first
- Check model's context length isn't exceeded
- Always try a preset template first
- Only customize if necessary
- Document any custom templates you create
- Use the "Test Template" feature
- Try with simple prompts first
- Verify output quality with actual story generation
- Check for thinking tags leaking through
- Watch for formatting issues
- Adjust template if needed
- Use instruction-tuned models, not base models
- Match template to model family
- Check model documentation for prompt format
- Keep Chat Completion as fallback
- Document which mode works best for your setup
- Test both modes when trying new models
| Model Family | Mode | Preset | Quality | Notes |
|---|---|---|---|---|
| GPT-3.5/4 | Chat | N/A | ⭐⭐⭐⭐⭐ | Use Chat mode |
| Claude | Chat | N/A | ⭐⭐⭐⭐⭐ | Use Chat mode |
| Llama 3.x Instruct | Text | Llama 3 | ⭐⭐⭐⭐⭐ | Excellent with template |
| Mistral Instruct | Text | Mistral | ⭐⭐⭐⭐ | Works well |
| Qwen2/2.5 Instruct | Text | Qwen | ⭐⭐⭐⭐⭐ | Excellent with template |
| ChatGLM | Text | GLM | ⭐⭐⭐⭐ | Works well |
| DeepSeek | Text | Generic | ⭐⭐⭐⭐ | Thinking tags auto-removed |
| Ollama (any) | Chat | N/A | ⭐⭐⭐⭐ | Ollama handles formatting |
| Vicuna | Text | Generic | ⭐⭐⭐ | May need custom template |
| Alpaca | Text | Generic | ⭐⭐⭐ | Basic instruction format |
- Configure your API endpoint (e.g., LM Studio, TabbyAPI)
- Load Llama 3.1 Instruct model
- In Kahani Settings:
- API Type: OpenAI Compatible
- API URL:
http://localhost:1234 - Model Name: Your model name
- Completion Mode: Text Completion API
- Preset: Llama 3
- Test with a simple scene generation
- Verify output quality
- Select "Custom" preset
- Click "Customize"
- Configure:
bos_token: "" eos_token: "</s>" system_prefix: "A chat between a curious user and an assistant. " system_suffix: "\n\n" instruction_prefix: "USER: " instruction_suffix: "\n" response_prefix: "ASSISTANT: " - Test template
- Save settings
- Configure DeepSeek API endpoint
- Select "Generic" preset
- Generate content
- Thinking tags are automatically removed
- Only the final output is shown to users
Q: Can I switch between Chat and Text modes? A: Yes! You can switch anytime in Settings. Your choice is saved per user.
Q: Will my existing stories work with Text Completion? A: Yes! The mode only affects new generations, not existing content.
Q: Can I use different templates for different stories? A: Currently, the template is a global user setting. All stories use the same mode/template.
Q: Do I need to restart after changing templates? A: No, template changes take effect immediately.
Q: Can I export/import custom templates? A: Not yet, but you can copy the JSON from the editor and save it externally.
Q: What if my model isn't listed? A: Try the Generic preset first, then customize if needed. Check your model's documentation for the correct prompt format.
Q: Does this work with streaming? A: Yes! Text Completion supports streaming just like Chat Completion.
Q: Are thinking tags removed in real-time during streaming? A: Yes, thinking tag removal works for both streaming and non-streaming responses.
If you encounter issues:
- Check the troubleshooting section above
- Review
backend/logs/kahani.logfor errors - Test with a known-working preset (e.g., Llama 3)
- Open an issue on GitHub with:
- Model name and version
- Template configuration
- Error messages
- Example prompts that fail
Planned features:
- Per-story template selection
- Template import/export
- More pre-built templates
- Template validation UI
- Community template sharing
- Multi-turn conversation templates
- Template versioning
Last Updated: October 31, 2025 Version: 1.0