Context

Managing context state, working memory, and execution logic for agent interactions.

Context

What is a Context?

A Context represents an isolated execution scope within an agent - similar to a dedicated workspace or session. Each context maintains its own persistent state (ContextState.memory), temporary working memory, and reasoning history.
You can think of it like a browser tab: each tab runs independently, holds its own data, and tracks its own interaction thread.

Contexts enable agents to manage multiple concurrent tasks, users, or domains without state collisions.

Real-World Context Examples in AxiomKit

🧾 Invoice Assistant Context

A context that helps manage invoice generation, tracking, and reminders for individual clients.

const invoiceContext = context({
  type: "invoice",
  schema: z.object({ clientId: z.string() }),
  create: () => ({
    invoices: [],
    lastIssued: null,
    paymentStatus: "unpaid",
  }),
  render: (state) => `
    Client: ${state.args.clientId}
    Outstanding invoices: ${state.memory.invoices.length}
    Last issued: ${state.memory.lastIssued}
    Status: ${state.memory.paymentStatus}
  `,
});

📦 Order Fulfilment Context

Used for ecommerce agents that track and manage the status of a customer’s active order lifecycle.

const orderContext = context({
  type: "order",
  schema: z.object({ orderId: z.string() }),
  create: () => ({
    items: [],
    shippingStatus: "pending",
    estimatedDelivery: null,
  }),
  render: (state) => `
    Order: ${state.args.orderId}
    Items: ${state.memory.items.length}
    Shipping: ${state.memory.shippingStatus}
    ETA: ${state.memory.estimatedDelivery}
  `,
});

🧠 Research Assistant Context

Designed for AI agents that help summarize documents or track literature reviews. Stores what was read and what insights were extracted.

const researchContext = context({
  type: "research_session",
  schema: z.object({ sessionId: z.string() }),
  create: () => ({
    docsReviewed: [],
    keyFindings: [],
    unansweredQuestions: [],
  }),
  render: (state) => `
    Session: ${state.args.sessionId}
    Documents reviewed: ${state.memory.docsReviewed.length}
    Key findings: ${state.memory.keyFindings.length}
    Open questions: ${state.memory.unansweredQuestions.length}
  `,
});

The Problem: Agents Need to Track Separate States

Without contexts, your agent mixes up information across users and domains:

Client A: "Send my invoice again"
Client B: "Has my invoice been paid?"
Agent: "Yes, it was paid yesterday"
// ❌ Mixed up invoices between clients!

Order #123: "Add a new item to my cart"
Order #456: "Where's my package?"
Agent: "You just added a backpack to your cart"
// ❌ Wrong order state—totally different customer!

Research Session A: Reviewing climate data
Research Session B: Reviewing blockchain protocols
Agent: "Summary: Renewable energy is volatile"
// ❌ Pulled insight from the wrong session!

The Solution: Contexts Keep Everything Isolated

With AxiomKit contexts, agents handle each session independently - clean, isolated, and accurate:

Invoice Context - Client A:
- Remembers invoices for Client A only
- Tracks payment status and last issue date

Invoice Context - Client B:
- Completely separate record
- Agent can truthfully say: "No invoice has been paid yet"

Order Context - Order #123:
- Items added: backpack, laptop
- Shipping: not started

Order Context - Order #456:
- Status: In transit, ETA in 2 days
// ✅ No cross-contamination

Research Context - Session A:
- Reviewed climate papers, extracted energy trends

Research Context - Session B:
- Separate literature on Ethereum scaling
// ✅ Accurate domain-specific reasoning

How Contexts Work in Your AxiomKit Agent

Contexts are what make AxiomKit agents stateful. Each context manages its own memory, instructions, and rendering logic - allowing agents to track separate conversations, tasks, sessions, or domains without interference.

1. You Define Context Types

Agents can be configured with multiple context types to handle different interaction scopes:

const agent = createAgent({
  model: groq("meta-llama/llama-4-scout-17b-16e-instruct"),
  contexts: [
     orderContext,      // Tracks individual order fulfillment
    invoiceContext,    // Manages invoices for different clients
    researchContext,   // Keeps memory of research sessions
  ],
});

2. Inputs Route to Specific Context Instances

Inputs are dynamically routed to the correct context based on their type and identifier.

// Route e-commerce order events to orderContext
orderEvents.subscribe((send, agent) => {
  ecommerce.on("orderUpdate", (event) => {
    send(
      orderContext,
      { orderId: event.orderId },
      { update: event.details }
    );
  });
});

// Route document uploads to researchContext
researchBot.on("documentUploaded", (doc) => {
  send(
    researchContext,
    { sessionId: doc.sessionId },
    { documentText: doc.text }
  );
});

3. Separate Memory Per Instance

Each instance of a context maintains its own isolated memory:

cssCopyEditOrder Contexts:
- order:001 → { items: [...], shippingStatus: "shipped" }
- order:002 → { items: [...], shippingStatus: "pending" }

Invoice Contexts:
- invoice:acme → { invoices: [...], paymentStatus: "unpaid" }
- invoice:globex → { invoices: [...], paymentStatus: "paid" }

Research Contexts:
- research:sessionA → { docsReviewed: [...], keyFindings: [...] }
- research:sessionB → { docsReviewed: [...], keyFindings: [...] }

No memory leaks. Each context remembers only what it’s supposed to.

4. Create Your First Context: orderContext

const orderContext = context({
  type: "order",
  schema: z.object({
    orderId: z.string().describe("Order ID"),
  }),
  create: () => ({
    items: [],
    shippingStatus: "pending",
    estimatedDelivery: null,
  }),
  render: (state) => `
    Order: ${state.args.orderId}
    Items: ${state.memory.items.length}
    Status: ${state.memory.shippingStatus}
    ETA: ${state.memory.estimatedDelivery}
  `,
  instructions: "Help track and update order status based on user or system inputs."
});

5. Memory Persists Across Conversations

// First interaction
User: “Add item A to order 001
Memory: order:001 → { items: [A], shippingStatus: "pending" }

// Later interaction
User: “What’s the shipping status of order 001?
→ Memory still contains: { items: [A], shippingStatus: "pending" }

✅ Contexts automatically persist and recall relevant state.


6. Switch Between Contexts Dynamically

<!-- User starts by uploading a document -->
<input type="fileUpload" sessionId="research-123">
  Uploaded: climate-impact-study.pdf
</input>

<!-- Agent routes to researchContext -->
<action_call name="extract-key-findings" context="research_session" args='{"sessionId": "research-123"}'>
  {"document": "climate-impact-study.pdf"}
</action_call>

<!-- Later user inquires about an invoice -->
<input type="chat" clientId="acme">
  “What’s my last issued invoice?”
</input>

→ Agent switches to invoiceContext

7. Context-Specific Actions

Only relevant actions show up in the right context:

const invoiceContextWithActions = invoiceContext.setActions([
  action({
    name: "send-invoice",
    schema: z.object({
      amount: z.number(),
    }),
    handler: async ({ amount }, ctx) => {
      const newInvoice = {
        id: crypto.randomUUID(),
        amount,
        date: new Date().toISOString(),
      };
      ctx.memory.invoices.push(newInvoice);
      ctx.memory.lastIssued = newInvoice.date;

      return {
        success: true,
        message: `Invoice of $${amount} issued.`,
      };
    },
  }),
]);

✅ This action will only appear when the invoiceContext is active.


8. Use Context Lifecycle Hooks

const researchContext = context({
  type: "research_session",
  schema: z.object({ sessionId: z.string() }),

  create: () => ({
    docsReviewed: [],
    keyFindings: [],
    startTime: Date.now(),
  }),

  onStep: async (ctx) => {
    ctx.memory.lastInteraction = Date.now();
  },

  onRun: async (ctx, agent) => {
    const elapsed = Date.now() - ctx.memory.startTime;
    agent.logger.info(`Research session ${ctx.key} ran for ${elapsed}ms`);
  },
});

Best Practices

✅ Clear Contexts

context({ type: "order", schema: z.object({ orderId: z.string() }) });
context({ type: "invoice", schema: z.object({ clientId: z.string() }) });

❌ Avoid Vague Contexts

context({ type: "misc", schema: z.object({ id: z.string() }) }); // unclear purpose

✅ Helpful Render Output

render: (state) => `
  Client: ${state.args.clientId}
  Unpaid invoices: ${state.memory.invoices.length}
  Last issued: ${state.memory.lastIssued}
`;

Key Takeaways

  • Context = Scoped Memory + Logic
    Each session, order, or client interaction runs in isolation.
  • Instance-based Memory
    Same context type, many instances: order:001, order:002, etc.
  • LLM Awareness via render()
    What the agent sees is controlled—so you guide behavior directly.
  • Actions Stay Contextual
    No bloated menus, just the tools that matter in the current state.