> ## Documentation Index > Fetch the complete documentation index at: https://openrouter.ai/docs/llms.txt > Use this file to discover all available pages before exploring further. # Dynamic Parameters > Use async functions for adaptive model behavior across turns ## Basic Usage Any parameter in `callModel` can be a function that computes its value based on conversation context. This enables adaptive behavior - changing models, adjusting temperature, or modifying instructions as the conversation evolves. Pass a function instead of a static value: ```typescript lines theme={null} import { OpenRouter } from '@openrouter/agent'; const openrouter = new OpenRouter({ apiKey: process.env.OPENROUTER_API_KEY, }); const result = openrouter.callModel({ // Dynamic model selection based on turn count model: (ctx) => { return ctx.numberOfTurns > 3 ? 'openai/gpt-5.2' : 'openai/gpt-5-nano'; }, input: 'Hello!', tools: [myTool], }); ``` ## Function Signature Parameter functions receive a `TurnContext` and return the parameter value: ```typescript lines theme={null} type ParameterFunction = (context: TurnContext) => T | Promise; ``` ### TurnContext | Property | Type | Description | | --------------- | -------------------------------------------- | ------------------------------------------------------------- | | `numberOfTurns` | `number` | Current turn number (1-indexed) | | `turnRequest` | `OpenResponsesRequest \| undefined` | Current request object containing messages and model settings | | `toolCall` | `OpenResponsesFunctionToolCall \| undefined` | The specific tool call being executed | ## Async Functions Functions can be async for fetching external data: ```typescript lines theme={null} const result = openrouter.callModel({ model: 'openai/gpt-5-nano', // Fetch user preferences from database temperature: async (ctx) => { const prefs = await fetchUserPreferences(userId); return prefs.preferredTemperature ?? 0.7; }, // Load dynamic instructions instructions: async (ctx) => { const rules = await fetchBusinessRules(); return `Follow these rules:\n${rules.join('\n')}`; }, input: 'Hello!', }); ``` ## Common Patterns ### Progressive Model Upgrade Start with a fast model, upgrade for complex tasks: ```typescript lines theme={null} const result = openrouter.callModel({ model: (ctx) => { // First few turns: fast model if (ctx.numberOfTurns <= 2) { return 'openai/gpt-5-nano'; } // Complex conversations: capable model return 'openai/gpt-5.2'; }, input: 'Let me think through this problem...', tools: [analysisTool], }); ``` ### Adaptive Temperature Adjust creativity based on context: ```typescript lines theme={null} const result = openrouter.callModel({ model: 'openai/gpt-5-nano', temperature: (ctx) => { // Analyze recent messages for task type const lastMessage = JSON.stringify(ctx.turnRequest?.input).toLowerCase(); if (lastMessage.includes('creative') || lastMessage.includes('brainstorm')) { return 1.0; // Creative tasks } if (lastMessage.includes('code') || lastMessage.includes('calculate')) { return 0.2; // Precise tasks } return 0.7; // Default }, input: 'Write a creative story', }); ``` ### Context-Aware Instructions Build instructions based on conversation state: ```typescript lines theme={null} const result = openrouter.callModel({ model: 'openai/gpt-5-nano', instructions: (ctx) => { const base = 'You are a helpful assistant.'; const turnInfo = `This is turn ${ctx.numberOfTurns} of the conversation.`; // Add context based on history length if (ctx.numberOfTurns > 5) { return `${base}\n${turnInfo}\nKeep responses concise - this is a long conversation.`; } return `${base}\n${turnInfo}`; }, input: 'Continue helping me...', tools: [helpTool], }); ``` ### Dynamic Max Tokens Adjust output length based on task: ```typescript lines theme={null} const result = openrouter.callModel({ model: 'openai/gpt-5-nano', maxOutputTokens: (ctx) => { const lastMessage = JSON.stringify(ctx.turnRequest?.input).toLowerCase(); if (lastMessage.includes('summarize') || lastMessage.includes('brief')) { return 200; } if (lastMessage.includes('detailed') || lastMessage.includes('explain')) { return 2000; } return 500; }, input: 'Give me a detailed explanation', }); ``` ### Feature Flags Enable features dynamically: ```typescript lines theme={null} const result = openrouter.callModel({ model: 'anthropic/claude-sonnet-4.5', // Enable thinking for complex turns provider: async (ctx) => { const enableThinking = ctx.numberOfTurns > 2; return enableThinking ? { anthropic: { thinking: { type: 'enabled', budgetTokens: 1000 }, }, } : undefined; }, input: 'Solve this complex problem', tools: [analysisTool], }); ``` ## Combining with Tools Dynamic parameters work alongside tool execution: ```typescript lines theme={null} const smartAssistant = openrouter.callModel({ // Upgrade model if tools have been used model: (ctx) => { const hasToolUse = JSON.stringify(ctx.turnRequest?.input).includes('function_call'); return hasToolUse ? 'anthropic/claude-sonnet-4.5' : 'openai/gpt-5-nano'; }, // Lower temperature after tool execution temperature: (ctx) => { return ctx.numberOfTurns > 1 ? 0.3 : 0.7; }, input: 'Research and analyze this topic', tools: [searchTool, analysisTool], }); ``` ## Execution Order Dynamic parameters are resolved at the start of each turn: ```lines theme={null} 1. Resolve all parameter functions with current TurnContext 2. Build request with resolved values 3. Send to model 4. Execute tools (if any) 5. Check stop conditions 6. Update TurnContext for next turn 7. Repeat from step 1 ``` ## Error Handling Handle errors in async parameter functions: ```typescript lines theme={null} const result = openrouter.callModel({ model: 'openai/gpt-5-nano', instructions: async (ctx) => { try { const rules = await fetchRules(); return `Follow these rules: ${rules}`; } catch (error) { // Fallback on error console.error('Failed to fetch rules:', error); return 'You are a helpful assistant.'; } }, input: 'Hello!', }); ``` ## Best Practices ### Keep Functions Pure Avoid side effects in parameter functions: ```typescript lines theme={null} // Good: Pure function model: (ctx) => ctx.numberOfTurns > 3 ? 'gpt-4' : 'gpt-4o-mini', // Avoid: Side effects model: (ctx) => { logToDatabase(ctx); // Side effect return 'gpt-4'; }, ``` ### Cache Expensive Operations Cache results for repeated calls: ```typescript lines theme={null} let cachedRules: string | null = null; const result = openrouter.callModel({ instructions: async (ctx) => { if (!cachedRules) { cachedRules = await fetchExpensiveRules(); } return cachedRules; }, input: 'Hello!', }); ``` ### Use Sensible Defaults Always have fallback values: ```typescript lines theme={null} model: (ctx) => { const preferredModel = getPreferredModel(); return preferredModel ?? 'openai/gpt-5-nano'; // Default fallback }, ``` ## See Also * **[nextTurnParams](/docs/agent-sdk/call-model/next-turn-params)** - Tool-driven parameter modification * **[Stop Conditions](/docs/agent-sdk/call-model/stop-conditions)** - Dynamic execution control * **[Tools](/docs/agent-sdk/call-model/tools)** - Multi-turn orchestration