Daydreams Logo

Contexts

Managing state, memory, and behavior for agent interactions.

In Daydreams, a Context represents a specific scope of interaction or task for an agent. It encapsulates the state, memory, available actions, and behavior relevant to that scope. Think of it like a dedicated workspace for the agent to handle a particular conversation, process, or goal.

For example, you might have separate contexts for:

  • Handling a Discord channel (discord:channel).
  • Managing a Telegram chat (telegram:chat).
  • Executing a specific trading strategy (tradingContext).
  • Processing a user's request in a CLI session (cli).

Each running instance of a context maintains its own state and memory, isolated from others.

Defining a Context

Contexts are defined using the context function exported from @daydreamsai/core.

import { context, action, input, output } from "@daydreamsai/core";
import { z } from "zod";
 
// Example: A simple context for a chat session
const chatContext = context({
  // Required: A unique identifier for this type of context
  type: "chat",
 
  // Required: Zod schema defining the arguments needed to identify
  // a specific instance of this context.
  schema: z.object({
    sessionId: z.string(),
    userId: z.string(),
  }),
 
  // Optional: Function to generate a unique instance key from arguments.
  // If not provided, defaults to the 'type'. Useful when 'type' alone isn't unique enough.
  key: ({ sessionId }) => sessionId,
 
  // Optional: Asynchronous function called when a context instance is first created.
  // Use this to set up initial data or options specific to this instance.
  setup: async (args, settings, agent) => {
    const userProfile = await agent.someService.getUserProfile(args.userId);
    return { userProfile }; // This becomes 'options' in ContextState
  },
 
  // Optional: Function to define the structure of the persistent memory
  // specific to this context type (TMemory). Runs if no saved memory exists.
  create: (params, agent) => {
    return {
      messageHistory: [],
      userPreferences: params.options.userProfile?.preferences ?? {},
    };
  },
 
  // Optional: Provides static or dynamic instructions to the LLM within this context.
  instructions: (state) =>
    `You are chatting with ${state.options.userProfile?.name}. Be helpful.`,
 
  // Optional: Provides a description of the context, often used in prompts.
  description: "A chat session with a specific user.",
 
  // Optional: Function to render the context's state for the LLM prompt.
  // The output (string, XML, etc.) is included in the <context> section of the prompt.
  render: (state) => {
    return state.memory.messageHistory
      .slice(-5) // Show last 5 messages
      .map((msg) => `${msg.sender}: ${msg.text}`)
      .join("\\n");
  },
 
  // Optional: Define lifecycle hooks for the context run.
  onStep: async (ctx, agent) => {
    /* Logic to run on each step */
  },
  onRun: async (ctx, agent) => {
    /* Logic to run when the run completes */
  },
  shouldContinue: (ctx) => true, // Determine if the run should continue
  onError: async (error, ctx, agent) => {
    /* Handle errors */
  },
 
  // Optional: Define inputs, outputs, and actions specific to this context type.
  // These are merged with the agent's global definitions.
  inputs: {
    /* ... */
  },
  outputs: {
    /* ... */
  },
  actions: [
    /* ... */
  ],
 
  // Optional: Specify a default LLM for this context type.
  model: undefined, // Defaults to agent's model if undefined
 
  // Optional: Default limits for runs within this context.
  maxSteps: 10,
  maxWorkingMemorySize: 50,
});

Key Parameters:

  • type (string): A unique identifier for the kind of context (e.g., "discord:channel", "trading").
  • schema (Zod Schema): Defines the arguments needed to uniquely identify an instance of this context (e.g., { channelId: z.string() }). The agent uses these arguments to load or create the correct context state.
  • key (Function, optional): Generates a unique string identifier for a context instance based on its arguments. If omitted, the type is used (suitable if only one instance of that type exists).
  • setup (Function, optional): Runs once when a context instance is first initialized. Useful for fetching initial data needed by the context, which becomes available in ContextState.options.
  • create (Function, optional): Defines the initial structure of the context's persistent memory (TMemory) if no saved state is found. The return value is stored and managed by the MemoryStore.
  • instructions / description (string | Function, optional): Provides guidance to the LLM about the context's purpose or state. Can be dynamic based on the current ContextState.
  • render (Function, optional): Determines how the context's current state (ContextState.memory) is represented in the LLM prompt (within the <context> tag).
  • onStep / onRun / shouldContinue / onError (Functions, optional): Lifecycle hooks executed during an agent.run.
  • inputs / outputs / actions (Objects/Array, optional): Define I/O and actions specifically available within this context type. These are merged with the agent's global definitions.
  • model (LanguageModelV1, optional): Override the agent's default model for runs within this context.
  • maxSteps / maxWorkingMemorySize (number, optional): Set default limits for runs within this context.

Context State (ContextState)

When a context is active during an agent.run, its state is represented by the ContextState object. This object is passed to various handlers and functions (like render, onStep, action handlers).

type ContextState<TContext extends AnyContext = AnyContext> = {
  id: string; // Unique identifier for this instance (e.g., "discord:channel:12345")
  key: string; // Key generated by the `key` function (e.g., "12345")
  context: TContext; // The original context definition object
  args: InferSchemaArguments<TContext["schema"]>; // Parsed arguments used to load this instance
  options: InferContextOptions<TContext>; // Result returned by the `setup` function
  memory: InferContextMemory<TContext>; // The current persistent memory state for this instance
  settings: ContextSettings; // Runtime settings (model, limits) for this run
  contexts: string[]; // IDs of other contexts linked to this run
};

Working Memory

Each context run (agent.run) has an associated WorkingMemory. This is distinct from the persistent ContextState.memory. Working Memory holds the temporary logs (InputRef, OutputRef, ActionCall, ActionResult, Thought, etc.) generated during a single run. It's the agent's short-term scratchpad for the current execution cycle and is used to build the prompt for the LLM at each step.

See the Agent Lifecycle for how Working Memory is used in prompt generation.

Agent Interaction

You typically interact with contexts via the Agent instance:

  • agent.getContext({ context: myContext, args: { ... } }): Retrieves an existing ContextState instance or creates a new one if it doesn't exist. Loads memory from the MemoryStore.
  • agent.getContextById(id): Retrieves a ContextState by its full ID (e.g., "discord:channel:12345").
  • agent.saveContext(contextState, optionalWorkingMemory): Persists the ContextState (including its memory) to the configured MemoryStore. WorkingMemory is usually saved internally during agent.run.
  • agent.run({ context: myContext, args: { ... } }): Starts or continues the execution loop for a specific context instance.

Contexts provide the essential structure for managing scoped state, behavior, and memory within the Daydreams framework.

On this page