Runtime Context in Kastrax AI Agents ✅
Kastrax provides a sophisticated runtime context system based on dependency injection that enables you to dynamically configure your AI agents and tools with runtime variables. This powerful feature allows you to create flexible, adaptable agents that can modify their behavior based on runtime conditions without changing their underlying implementation.
Runtime Context Architecture ✅
Kastrax implements a robust dependency injection system that provides several key capabilities:
- Type-safe Configuration: Pass strongly-typed runtime variables to agents through a type-safe context
- Contextual Tool Execution: Access context variables within tool execution environments
- Dynamic Behavior Adaptation: Modify agent behavior at runtime without changing implementation code
- Shared Configuration: Share configuration across multiple tools and components within an agent
- Environment-aware Processing: Adapt agent responses based on deployment environment or user preferences
Basic Usage ✅
Here’s how to use runtime context with a Kastrax AI agent:
import ai.kastrax.core.agent.Agent
import ai.kastrax.core.context.RuntimeContext
import ai.kastrax.core.context.ContextKey
// Define your runtime context keys using the type-safe ContextKey system
object WeatherContextKeys {
val TEMPERATURE_SCALE = ContextKey<String>("temperature-scale")
val LANGUAGE = ContextKey<String>("language")
val LOCATION = ContextKey<String>("location")
}
// Create a runtime context and set values
val runtimeContext = RuntimeContext().apply {
set(WeatherContextKeys.TEMPERATURE_SCALE, "celsius")
set(WeatherContextKeys.LANGUAGE, "en-US")
set(WeatherContextKeys.LOCATION, "New York")
}
// Use the context when generating a response
val response = agent.generate(
input = "What's the weather like today?",
sessionId = "user-123",
conversationId = "weather-session",
context = runtimeContext
)
println(response.text)
This example demonstrates how to create a runtime context with temperature scale, language, and location preferences, then pass it to an agent when generating a response.
Using with Web Services ✅
Kastrax makes it easy to integrate runtime context with web services. Here’s how to dynamically set temperature units based on a user’s location in a Ktor web service:
import ai.kastrax.core.agent.Agent
import ai.kastrax.core.context.RuntimeContext
import ai.kastrax.core.context.ContextKey
import io.ktor.server.application.*
import io.ktor.server.engine.*
import io.ktor.server.netty.*
import io.ktor.server.routing.*
import io.ktor.server.request.*
import io.ktor.server.response.*
// Define context keys
object ContextKeys {
val TEMPERATURE_SCALE = ContextKey<String>("temperature-scale")
val LANGUAGE = ContextKey<String>("language")
}
// Create a Ktor web service
fun main() {
embeddedServer(Netty, port = 8080) {
// Configure the agent
val weatherAgent = getWeatherAgent()
// Add a request interceptor to set context based on headers
intercept(ApplicationCallPipeline.Monitoring) {
// Get country from header (similar to Cloudflare's CF-IPCountry)
val country = call.request.header("X-Country-Code")
// Store the runtime context in call attributes
val runtimeContext = RuntimeContext().apply {
// Set temperature scale based on country
set(ContextKeys.TEMPERATURE_SCALE,
if (country == "US") "fahrenheit" else "celsius")
// Set language based on Accept-Language header
val language = call.request.header("Accept-Language")?.split(",")?.firstOrNull() ?: "en-US"
set(ContextKeys.LANGUAGE, language)
}
// Store context in call attributes for later use
call.attributes.put(RuntimeContextKey, runtimeContext)
}
// Define routes
routing {
post("/ask") {
// Get the user's question from the request
val request = call.receive<WeatherRequest>()
// Get the runtime context from call attributes
val runtimeContext = call.attributes[RuntimeContextKey]
// Generate a response using the agent with the runtime context
val response = weatherAgent.generate(
input = request.question,
sessionId = request.userId,
conversationId = request.conversationId,
context = runtimeContext
)
// Return the response
call.respond(WeatherResponse(text = response.text))
}
}
}.start(wait = true)
}
// Data classes for request/response
data class WeatherRequest(
val question: String,
val userId: String,
val conversationId: String
)
data class WeatherResponse(
val text: String
)
// Key for storing runtime context in call attributes
private val RuntimeContextKey = AttributeKey<RuntimeContext>("RuntimeContext")
This example demonstrates how to create a web service that dynamically configures the agent’s runtime context based on request headers, providing personalized responses to each user.
Creating Context-Aware Tools ✅
Kastrax tools can access runtime context variables to adapt their behavior dynamically. Here’s how to create a weather tool that uses context variables:
import ai.kastrax.core.tool.Tool
import ai.kastrax.core.tool.ToolDefinition
import ai.kastrax.core.tool.ToolResult
import ai.kastrax.core.context.RuntimeContext
import ai.kastrax.core.context.ContextKey
import kotlinx.serialization.Serializable
// Define input and output types
@Serializable
data class WeatherToolInput(
val location: String
)
@Serializable
data class WeatherToolOutput(
val location: String,
val temperature: String,
val conditions: String,
val unit: String
)
// Define context keys
object WeatherContextKeys {
val TEMPERATURE_SCALE = ContextKey<String>("temperature-scale")
val LANGUAGE = ContextKey<String>("language")
}
// Implement the context-aware tool
class WeatherTool : Tool<WeatherToolInput, WeatherToolOutput> {
// Define tool metadata
override val definition = ToolDefinition(
name = "get_weather",
description = "Get the current weather for a specified location",
inputType = WeatherToolInput::class,
outputType = WeatherToolOutput::class
)
// Implement the execution logic with context awareness
override suspend fun execute(
input: WeatherToolInput,
context: RuntimeContext
): ToolResult<WeatherToolOutput> {
return try {
// Get temperature scale from context (with default fallback)
val temperatureScale = context.get(WeatherContextKeys.TEMPERATURE_SCALE) ?: "celsius"
// Get language from context (with default fallback)
val language = context.get(WeatherContextKeys.LANGUAGE) ?: "en-US"
// Fetch weather data using the context variables
val weather = fetchWeatherData(
location = input.location,
temperatureScale = temperatureScale,
language = language
)
// Return the result
ToolResult.Success(weather)
} catch (e: Exception) {
ToolResult.Error("Failed to fetch weather data: ${e.message}")
}
}
// Helper method to fetch weather data
private suspend fun fetchWeatherData(
location: String,
temperatureScale: String,
language: String
): WeatherToolOutput {
// In a real implementation, this would call a weather API
// For demonstration, we're returning mock data
// Format temperature based on scale
val temp = if (temperatureScale == "celsius") "22°C" else "72°F"
// Get conditions in the appropriate language
val conditions = when (language.substringBefore("-")) {
"es" -> "Soleado"
"fr" -> "Ensoleillé"
else -> "Sunny"
}
return WeatherToolOutput(
location = location,
temperature = temp,
conditions = conditions,
unit = temperatureScale
)
}
}
Advanced Context Features ✅
Kastrax’s runtime context system provides several advanced features for more complex scenarios:
Context Inheritance
// Create a base context with common settings
val baseContext = RuntimeContext().apply {
set(CommonKeys.LANGUAGE, "en-US")
set(CommonKeys.TIMEZONE, "America/New_York")
}
// Create a derived context that inherits from the base context
val userContext = RuntimeContext(parent = baseContext).apply {
// Override or add user-specific settings
set(UserKeys.TEMPERATURE_SCALE, "fahrenheit")
set(UserKeys.LOCATION, "New York")
}
// The userContext now has access to both its own settings and those from baseContext
Context Scopes
// Create a scoped context for a specific operation
val result = runtimeContext.withScope { scopedContext ->
// Temporarily modify the context for this scope only
scopedContext.set(OperationKeys.DEBUG_MODE, true)
scopedContext.set(OperationKeys.TIMEOUT, 30000)
// Execute an operation with the scoped context
performOperation(scopedContext)
}
// Changes made in the scope don't affect the original context
Context Observers
// Register an observer to be notified when specific keys change
runtimeContext.addObserver(UserKeys.LANGUAGE) { oldValue, newValue ->
println("Language changed from $oldValue to $newValue")
// Perform any necessary updates when the language changes
updateTranslations(newValue)
}
These advanced features enable sophisticated context management for complex AI agent applications.