Agent skill
prompt-tsx-patterns
Deep dive into prompt-tsx patterns used in vscode-copilot-chat, including component lifecycle, async rendering, priority system, and token budget management
Install this agent skill to your Project
npx add-skill https://github.com/majiayu000/claude-skill-registry/tree/main/skills/development/prompt-tsx-patterns-omermachluf-vscode-copilot-chat
SKILL.md
This skill provides comprehensive guidance on using prompt-tsx in the vscode-copilot-chat extension. It covers the specific patterns and conventions used in this codebase.
What is Prompt-TSX?
Prompt-TSX is a React-like framework for building AI prompts using TypeScript and JSX. It provides:
- Component-based prompt composition
- Token budget management
- Priority-based pruning
- Type-safe prompt generation
Core Concepts
PromptElement Base Class
All prompt components extend PromptElement:
import { PromptElement, BasePromptElementProps } from '@vscode/prompt-tsx';
interface MyPromptProps extends BasePromptElementProps {
readonly userQuery: string;
readonly files?: string[];
}
class MyPrompt extends PromptElement<MyPromptProps> {
render() {
return (
<>
<SystemMessage priority={1000}>
System instructions here<br />
</SystemMessage>
<UserMessage priority={900}>
{this.props.userQuery}
</UserMessage>
</>
);
}
}
Key Points:
- Props must extend
BasePromptElementProps - Render method returns JSX (PromptPiece)
- Can be sync or async
- Components are classes, not functions
The Line Break Rule
CRITICAL: JSX collapses whitespace and newlines!
// ❌ WRONG - These will be on the same line
<SystemMessage priority={1000}>
You are a helpful assistant.
Please follow these guidelines:
1. Be concise
2. Be accurate
</SystemMessage>
// ✅ CORRECT - Use <br /> for line breaks
<SystemMessage priority={1000}>
You are a helpful assistant.<br />
Please follow these guidelines:<br />
1. Be concise<br />
2. Be accurate<br />
</SystemMessage>
Why: Prompt-TSX renders to plain text. Without explicit <br /> tags, all text is concatenated into a single line.
Priority System
Priority controls:
- Rendering order (high priority first)
- Pruning decisions (low priority pruned first when over budget)
Priority Ranges in This Codebase
Based on patterns in src/extension/prompts/:
// Core instructions - always included
const PRIORITY_SYSTEM_INSTRUCTIONS = 1000;
// User's current message - highest user priority
const PRIORITY_USER_MESSAGE = 900;
// Recent conversation - important context
const PRIORITY_RECENT_HISTORY = 800;
// Conversation history - context but can be pruned
const PRIORITY_HISTORY = 700;
// User attachments - files, code snippets
const PRIORITY_ATTACHMENTS = 600;
// Contextual info - workspace, file listings
const PRIORITY_CONTEXT = 500;
// Documentation, examples - helpful but optional
const PRIORITY_BACKGROUND = 100;
Priority Best Practices
- Space by 10s: Use 700, 710, 720 not 700, 701, 702
- Group related content: Similar priority for related pieces
- Consider pruning: What should be removed first?
- Document choices: Comment why you chose a priority
// Good: Clear priority hierarchy
<>
{/* Critical instructions - never prune */}
<SystemMessage priority={1000}>...</SystemMessage>
{/* User query - high priority */}
<UserMessage priority={900}>...</UserMessage>
{/* Recent context - medium priority */}
<History priority={700} flexGrow={1} />
{/* Background info - prune first */}
<Documentation priority={100} />
</>
Token Budget Management
FlexGrow
flexGrow allows components to expand to fill available token space:
// Component with flexGrow will use remaining tokens
<History
priority={700}
flexGrow={1} // Take all remaining space
/>
// Multiple flex components share proportionally
<>
<History priority={700} flexGrow={2} /> // Gets 2/3 of space
<Examples priority={500} flexGrow={1} /> // Gets 1/3 of space
</>
FlexReserve
flexReserve reserves tokens before rendering:
<History
priority={700}
flexGrow={1}
flexReserve="/5" // Reserve 1/5 (20%) of budget before rendering
/>
Use cases:
- When you know minimum tokens needed
- Prevent other components from using all space
- Guarantee space for important but flex content
TextChunk for Large Content
TextChunk enables intelligent truncation:
<TextChunk
breakOn="\n\n" // Break on paragraph boundaries
breakOnWhitespace // Or break on any whitespace
priority={500}
>
{longDocumentation}
</TextChunk>
How it works:
- If content fits in budget: rendered fully
- If too large: truncated at break point
- Preserves readability by breaking cleanly
Async Rendering
Components can perform async operations:
class FileContentPrompt extends PromptElement<FileContentProps> {
async render() {
// Async work happens IN render
const content = await this.readFile(this.props.filePath);
const metadata = await this.getMetadata(this.props.filePath);
return (
<>
<SystemMessage priority={1000}>
File: {this.props.filePath}<br />
Size: {metadata.size} bytes<br />
</SystemMessage>
<TextChunk priority={500} breakOnWhitespace>
{content}
</TextChunk>
</>
);
}
private async readFile(path: string): Promise<string> {
// Implementation
}
}
Key points:
- Use
async render()for async operations - All async work happens in render method
- Don't store promises in state
- Always await before returning JSX
Special Components
Tag
Create XML-like structured content:
<Tag name="context" attrs={{ type: "file", id: "main.ts" }}>
{fileContent}
</Tag>
Renders as:
<context type="file" id="main.ts">
[fileContent]
</context>
Use for:
- Structured data in prompts
- Semantic markup
- Tool result formatting
References
Track variable usage in prompts:
<references value={[new PromptReference({ variableName: 'fileName' })]} />
Purpose: Tell the system which variables are used in the prompt
Meta
Attach metadata that survives pruning:
<meta value={new ToolResultMetadata(toolCallId, result)} />
Purpose: Preserve important metadata even if content is pruned
KeepWith
Keep related content together during pruning:
const KeepWith = useKeepWith();
<>
<KeepWith priority={2}>
<ToolCallRequest>...</ToolCallRequest>
</KeepWith>
<KeepWith priority={1}>
<ToolCallResponse>...</ToolCallResponse>
</KeepWith>
</>
Effect: Both elements pruned together, not separately
Patterns from This Codebase
Pattern: System + User Message
render() {
return (
<>
<SystemMessage priority={1000}>
{this.props.systemInstructions}
</SystemMessage>
<UserMessage priority={900}>
{this.props.userQuery}
</UserMessage>
</>
);
}
Pattern: History with Flex
<History
priority={700}
flexGrow={1}
flexReserve="/5"
messages={this.props.conversationHistory}
/>
Pattern: File Context
<FileContext
priority={600}
flexGrow={2}
files={this.props.attachedFiles}
/>
Pattern: Tool Results
{this.props.toolResults.map((result, i) => (
<ToolResultComponent
key={i}
priority={850} // Higher than history, lower than user message
result={result}
/>
))}
Common Mistakes
1. Forgetting Line Breaks
// ❌ Will render on one line
<SystemMessage priority={1000}>
Line 1
Line 2
</SystemMessage>
// ✅ Explicit line breaks
<SystemMessage priority={1000}>
Line 1<br />
Line 2<br />
</SystemMessage>
2. Priority Conflicts
// ❌ Same priority - unpredictable order
<SystemMessage priority={1000}>...</SystemMessage>
<AnotherMessage priority={1000}>...</AnotherMessage>
// ✅ Different priorities
<SystemMessage priority={1000}>...</SystemMessage>
<AnotherMessage priority={990}>...</AnotherMessage>
3. Async Without Await
// ❌ Promise not awaited
async render() {
const data = this.fetchData(); // Returns Promise!
return <>{data}</>; // Renders "[object Promise]"
}
// ✅ Await the promise
async render() {
const data = await this.fetchData();
return <>{data}</>;
}
4. Large Content Without TextChunk
// ❌ Could exceed token budget
<UserMessage priority={900}>
{hugeDocument}
</UserMessage>
// ✅ Use TextChunk for intelligent truncation
<TextChunk breakOnWhitespace priority={900}>
{hugeDocument}
</TextChunk>
Testing Prompt Components
Manual Testing
-
Create test props:
typescriptconst testProps: MyPromptProps = { userQuery: 'test query', files: ['file1.ts', 'file2.ts'] }; -
Instantiate and render:
typescriptconst prompt = new MyPrompt(testProps); const result = await prompt.render(); -
Inspect output:
- Check priorities are correct
- Verify line breaks appear
- Confirm token usage reasonable
Testing Strategies
- Unit tests: Test component logic
- Integration tests: Test full prompt composition
- Token budget tests: Test with tight budgets
- Priority tests: Verify pruning order
Real Examples from This Codebase
See the references/ directory for:
component-patterns.md- Actual component implementationspriority-examples.md- Priority usage patternsasync-rendering.md- Async rendering examples
These reference files contain real code from this codebase that you can learn from and adapt.
Quick Reference
Must-know rules:
- ✅ Use
<br />for line breaks - ✅ Props extend
BasePromptElementProps - ✅ Higher priority = rendered first, pruned last
- ✅ Use
async render()for async operations - ✅ Use
TextChunkfor large content - ✅ Space priorities by 10s (700, 710, 720)
Common components:
<SystemMessage priority={N}>- System instructions<UserMessage priority={N}>- User input<TextChunk breakOn="...">- Truncatable content<Tag name="..." attrs={{}}>- Structured markup<references value={...} />- Variable tracking<meta value={...} />- Metadata
Remember: Prompt-TSX is your interface to the AI. Master it, and you master how the AI sees and understands requests!
Recommended Agent Skills
Expand your agent's capabilities with these related and highly-rated skills.
agent-ops-spec
Manage specification documents in .agent/specs/. Use when user provides requirements, acceptance criteria, or feature descriptions that need to be tracked and validated against implementation.
agent-ops-state
Maintain .agent state files. Use at session start, after meaningful steps, and before concluding: read/update constitution/memory/focus/issues/baseline consistently.
agent-ops-spec
Manage specification documents in .agent/specs/. Use when user provides requirements, acceptance criteria, or feature descriptions that need to be tracked and validated against implementation.
agent-ops-testing
Test strategy, execution, and coverage analysis. Use when designing tests, running test suites, or analyzing test results beyond baseline checks.
agent-ops-testing
Test strategy, execution, and coverage analysis. Use when designing tests, running test suites, or analyzing test results beyond baseline checks.
agent-ops-state
Maintain .agent state files. Use at session start, after meaningful steps, and before concluding: read/update constitution/memory/focus/issues/baseline consistently.
Didn't find tool you were looking for?