Agent Prompts
Enhance your agent's system prompt dynamically using the @prompt decorator. Prompt functions execute before each LLM call and contribute contextual information to the system message.
Prompts run in priority order (lower runs first) and support scope-based access control. Use them for dynamic context, user-specific information, or system status updates.
Overview
Prompt functions generate dynamic content that gets appended to the agent's system message before LLM execution. They're perfect for injecting real-time context, user information, or environmental data.
Key features:
- Dynamic system-prompt enhancement
- Priority-based execution order
- Scope-based access control
- Context injection
- Automatic string concatenation
- Sync and async support
Basic Usage
Simple Prompt
import { BaseAgent, Skill, prompt } from 'webagents';
import type { Context } from 'webagents';
class StatusPrompts extends Skill {
readonly name = 'status-prompts';
@prompt()
systemStatus(ctx: Context): string {
return 'System Status: Online - All services operational';
}
}
const agent = new BaseAgent({
name: 'assistant',
model: 'openai/gpt-4o',
skills: [new StatusPrompts()],
});The agent's effective system message becomes:
You are a helpful AI assistant.
System Status: Online - All services operational
Your name is assistant, you are an AI agent in the Internet of Agents.
Current time: 2024-01-15T10:30:00Priority-Based Execution
class ContextPrompts extends Skill {
readonly name = 'context-prompts';
@prompt({ priority: 5 })
timePrompt(ctx: Context): string {
return `Current Time: ${new Date().toISOString()}`;
}
@prompt({ priority: 10 })
systemStatusPrompt(ctx: Context): string {
return `System Status: ${getSystemStatus()}`;
}
@prompt({ priority: 20 })
userContextPrompt(ctx: Context): string {
const userId = ctx.auth?.userId ?? 'anonymous';
return `Current User: ${userId}`;
}
}Prompts execute in ascending priority order (5 → 10 → 20).
Scope-Based Access Control
Control which callers see specific prompt content:
class ScopedPrompts extends Skill {
readonly name = 'scoped-prompts';
@prompt({ scope: 'all' })
publicPrompt(ctx: Context): string {
return 'Public system information';
}
@prompt({ scope: 'owner' })
ownerPrompt(ctx: Context): string {
return `Owner Dashboard: ${getOwnerStats()}`;
}
@prompt({ scope: 'admin' })
adminPrompt(ctx: Context): string {
return `DEBUG MODE: ${getDebugInfo()}`;
}
@prompt({ scope: ['premium', 'enterprise'] })
premiumPrompt(ctx: Context): string {
return 'Premium features enabled';
}
}Context Access
Access request context for dynamic content:
class UserPrompts extends Skill {
readonly name = 'user-prompts';
@prompt({ priority: 10 })
async userContextPrompt(ctx: Context): Promise<string> {
const userId = ctx.auth?.userId ?? 'anonymous';
const userData = await getUserData(userId);
return `User Context:
- Name: ${userData.name}
- Role: ${userData.role}
- Preferences: ${userData.preferences}`;
}
@prompt({ priority: 20 })
async dynamicDataPrompt(ctx: Context): Promise<string> {
const [market, weather] = await Promise.all([
fetchMarketData(),
fetchWeather(),
]);
return `Real-time Context:
- Market: ${market.status}
- Weather: ${weather.condition}`;
}
}Skill Integration
Use prompts within skills for modular functionality:
import { Skill, prompt } from 'webagents';
import type { Context } from 'webagents';
class AnalyticsSkill extends Skill {
readonly name = 'analytics';
@prompt({ priority: 15, scope: 'owner' })
async analyticsPrompt(ctx: Context): Promise<string> {
const stats = await this.getAnalyticsData();
return `Analytics Summary:
- Active Users: ${stats.activeUsers}
- Revenue Today: $${stats.dailyRevenue}
- System Load: ${stats.cpuUsage}%`;
}
@prompt({ priority: 25 })
async performancePrompt(ctx: Context): Promise<string> {
const metrics = await this.getPerformanceMetrics();
return `Performance: ${metrics.responseTime}ms avg`;
}
private async getAnalyticsData() {
return { activeUsers: 1250, dailyRevenue: 5420, cpuUsage: 23 };
}
private async getPerformanceMetrics() {
return { responseTime: 150 };
}
}
const agent = new BaseAgent({
name: 'analytics-agent',
model: 'openai/gpt-4o',
skills: [new AnalyticsSkill()],
});Advanced Patterns
Conditional Prompts
@prompt({ priority: 10 })
conditionalPrompt(ctx: Context): string {
const userRole = (ctx.metadata.user_role as string) ?? 'guest';
if (userRole === 'admin') return 'ADMIN MODE: Full system access enabled';
if (userRole === 'premium') return 'PREMIUM MODE: Enhanced features available';
return 'STANDARD MODE: Basic features';
}
@prompt({ priority: 15 })
timeBasedPrompt(ctx: Context): string {
const hour = new Date().getHours();
if (hour >= 6 && hour < 12) return 'Good morning! System ready for daily operations.';
if (hour >= 12 && hour < 18) return 'Good afternoon! Peak usage period - optimized for performance.';
return 'Good evening! Running in power-save mode.';
}Error Handling
@prompt({ priority: 5 })
async safePrompt(ctx: Context): Promise<string> {
try {
const externalData = await fetchExternalService();
return `External Status: ${externalData.status}`;
} catch (e) {
console.warn('External service unavailable', e);
return 'External Status: Offline (using cached data)';
}
}
@prompt({ priority: 10 })
async resilientAsyncPrompt(ctx: Context): Promise<string> {
try {
const data = await Promise.race([
fetchSlowService(),
new Promise<never>((_, r) => setTimeout(() => r(new Error('timeout')), 2000)),
]);
return `Live Data: ${data.value}`;
} catch (e) {
return (e as Error).message === 'timeout'
? 'Live Data: Timeout (using fallback)'
: 'Live Data: Service unavailable';
}
}Best Practices
Keep Prompts Concise
// Good — concise and focused
@prompt()
statusPrompt(ctx: Context): string {
return `Status: ${getStatus()}`;
}
// Avoid — too verbose, burns tokens on every callUse Appropriate Priorities
@prompt({ priority: 5 }) // Core system info first
systemPrompt(ctx: Context) { /* ... */ }
@prompt({ priority: 10 }) // User context second
userPrompt(ctx: Context) { /* ... */ }
@prompt({ priority: 15 }) // Specific features last
featurePrompt(ctx: Context) { /* ... */ }Handle Failures Gracefully
Wrap external calls; never let a prompt throw — the agent will fall back to its base instructions but you lose the contextual signal.
Integration Examples
With Authentication
@prompt({ priority: 10, scope: 'owner' })
authContextPrompt(ctx: Context): string {
const user = ctx.auth?.user;
if (user) return `Authenticated as: ${user.name} (${user.email})`;
return 'Authentication: Guest user';
}With Payment Skills
@prompt({ priority: 15, scope: 'owner' })
async billingContextPrompt(ctx: Context): Promise<string> {
const balance = await getUserBalance(String(ctx.auth?.userId));
const usage = await getCurrentUsage(String(ctx.auth?.userId));
return `Billing Status:
- Balance: $${balance.toFixed(2)}
- Usage Today: ${usage} credits`;
}With Discovery Skills
@prompt({ priority: 20 })
async networkStatusPrompt(ctx: Context): Promise<string> {
const connected = await countConnectedAgents();
return `Network: ${connected} agents connected`;
}