Skip to main content
Every LLM interaction in AFK flows through two typed contracts: LLMRequest (what you send) and LLMResponse (what you get back). These contracts normalize the differences between providers so your agent code never touches provider-specific types.

The flow

The adapter translates between AFK’s normalized contracts and the provider’s native format.

LLMRequest

FieldTypePurpose
messageslist[Message]Conversation history (system, user, assistant, tool)
modelstrModel identifier
toolslist[ToolSchema]Available tool schemas
temperaturefloatSampling temperature (0.0–2.0)
max_tokensint | NoneMax output tokens
top_pfloat | NoneNucleus sampling
response_formatResponseFormat | NoneStructured output format
stoplist[str] | NoneStop sequences

LLMResponse

FieldTypePurpose
contentstr | NoneText response from the model
tool_callslist[ToolCall]Tool calls requested by the model
modelstrModel that generated the response
usageUsageToken counts (prompt, completion, total)
finish_reasonstrWhy generation stopped (stop, tool_calls, length)
latency_msfloatEnd-to-end request latency

Structured output

Request structured JSON output with a Pydantic model:
from pydantic import BaseModel

class Sentiment(BaseModel):
    label: str      # "positive", "negative", "neutral"
    confidence: float
    reasoning: str

request = LLMRequest(
    messages=[Message(role="user", content="I love this product!")],
    model="gpt-5.2-mini",
    response_format=Sentiment,   # ← Forces structured JSON output
)

response = await client.generate(request)
result = Sentiment.model_validate_json(response.content)
print(result.label)       # "positive"
print(result.confidence)  # 0.95

Message types

RolePurposeSource
systemAgent instructionsFrom Agent.instructions
userUser inputFrom user_message parameter
assistantModel responsesGenerated by the LLM
toolTool resultsFrom tool execution

Next steps