Skip to main content

Context Blocks

Context blocks are dynamic prompt blocks that fetch live data before an agent request. They are useful for stable conversation/session context such as CRM profile data, task counts, field mappings, personalization, user memory, and catalogs of available KBs, skills, and artifacts. Most built-in context blocks are:
message=system
type=dynamic
mode=cached
scope=conversation
Turn-specific context, such as selected records or current page state, should usually be sent as inline prompt_blocks or context_refs on the chat request. AgentFlow persists those as hidden system_context with the turn.

How It Works

  1. prompts/<name>/PROMPT.py registers a local async function with @prompt_block.
  2. AgentFlow builds a PromptContext with tenant, user, agent, request scope, auth, and safe API helpers.
  3. Eligible dynamic blocks run in parallel.
  4. Each block returns body text, or None / blank text to skip.
  5. AgentFlow wraps the body in <name>...</name>.
  6. Cacheable blocks are stored in the process-local prompt-block cache.
  7. Wrapped blocks are ordered and injected into the model request.
Dynamic block functions return inner body text, not the outer XML tag.
from framework.prompts.block_registry import PromptContext, prompt_block


@prompt_block(scope="conversation", tags=["tasks", "context"], ttl=300)
async def tasks_overview(ctx: PromptContext) -> str | None:
    """Outstanding and overdue task counts."""
    overview = await load_task_overview(ctx)
    if overview.total == 0:
        return None
    return f"open_tasks: {overview.total}\noverdue_tasks: {overview.overdue}"
AgentFlow injects:
<tasks_overview>
open_tasks: 12
overdue_tasks: 3
</tasks_overview>

Built-In Blocks

BlockScopeTypical TTLWhat it provides
available_knowledge_basesconversation5 minAssigned KB catalog, not full KB contents
available_artifactsconversation5 minAssigned artifact type catalog and how to use artifacts
available_skillsconversation5 minAssigned skill catalog, not full skill files
crm_contextconversation30 minCRM user/account context from GraphQL-backed sources
crm_field_mappingsconversation60 minCRM object field-to-locator mappings
personalizationconversation10 minProfile, custom instructions, style/tone preferences
tasks_overviewconversation5 minOutstanding and overdue task counts
user_memoryconversation10 minCore user/agent memory
Catalog blocks use progressive disclosure: they explain what exists and how to fetch more detail, rather than dumping full content.

Progressive Disclosure Shape

Catalog items should stay small:
name: renewal_playbook
description: Renewal risk and expansion workflow guidance.
when_to_use: Use when planning next steps for an account renewal.
how_to_use: Search this KB before making policy-specific recommendations.
Use the same shape for KBs, skills, artifacts, and future asset/file catalogs. For memory, use it for a high-level memory index; inject specific recalled archival memory as current-turn system_reminders only when relevant.

Request Scope

Chat requests can narrow catalogs:
Request fieldAffects
knowledge_basesavailable_knowledge_bases
skillsavailable_skills
artifactsavailable_artifacts
These fields narrow what the agent sees; they do not grant access to resources not assigned to the agent.

Preloading

Preloading means calling the same cacheable block builders before the user sends a prompt, usually when the chat UI opens.
from agentflow import AsyncAgentFlow

async with AsyncAgentFlow.from_profile("prod") as client:
    agent_id = (await client.agents.by_name("MainAgent")).id

    await client.agents.preload_context(agent_id)
    response = await client.agents.run(agent_id=agent_id, message="What's my pipeline look like?")
The REST route is still:
POST /api/v1/agent/{agent_id}/context/preload
The context cache is process-local. A preload request benefits later requests that land on the same API worker. Use session affinity if cross-worker warmth matters.

Inspecting Blocks

blocks = await client.agents.list_context_blocks(agent_id)
for block in blocks:
    print(block.name, block.tags, block.ttl)

rendered = await client.agents.build_context(agent_id, include_content=True)
for name, body in rendered.content_by_name.items():
    print(f"--- {name} ---")
    print(body[:200])
SDK methodREST endpoint
client.agents.list_context_blocks(agent_id)GET /api/v1/agent/{agent_id}/context/blocks
client.agents.build_context(agent_id)POST /api/v1/agent/{agent_id}/context/blocks/build
client.agents.preload_context(agent_id)POST /api/v1/agent/{agent_id}/context/preload

Turn Context

Not every dynamic context source should be a conversation-scoped context block.
SourceRecommended placement
Current pageInline turn prompt block or built-in page context
Current selectionInline turn prompt block
Datetime/timezoneBuilt-in current-turn system context
Resolved CRM/Slack refscontext_refs, resolved into turn system_context
KB retrieval snippetsTurn system_context
AttachmentsTurn system_context
Archival memory recallTurn system_reminders
Artifact actions/summariessystem_events
Conversation compaction noticesystem_events
Use context blocks for stable, reusable conversation context. Use turn system_context for details tied to the current message. Use turn system_reminders for bounded system reminders like automatic archival recall. Use system_events for durable system actions that must replay across future turns.

Cache Behavior

PropertyValue
Key{tenant_id}:{user_id}:{agent_name}:{block_name} plus scope inputs when configured
StorageProcess-local in-memory cache
TTLPer block; defaults are intentionally short for live catalogs
Empty resultSkipped and not injected
Error/timeoutSkipped for the request and not cached
InvalidationPOST /api/v1/prompt-blocks/{name}/invalidate-cache