Acts of Emergence

013: Agent/Scopes

Think of a scope as a set of blinders for an AI. It's a rule that lets a task see only a specific part of the information it needs, blocking out everything else. The _scopes property is like a VIP list, saying exactly what data a Call is allowed to look at.

The Scoped context idea is a core rule for managing what an AI can see when it performs a task, or Call. In a big AI system, a task doesn't just happen on its own; it needs information from its surroundings, like what a user asked for, what happened in previous steps, or the current situation. Scopes provide a safe and clear way to control what information gets passed along.

By limiting what the AI sees, scopes make the system safer, prevent it from accidentally sharing private data, and help the AI focus. This makes its actions more predictable and saves money. This controlled view is also a key reason why different parts of the system, like Ideas and Activities, can be built like self-contained and reusable tools. This document explains how scopes work and how they fit together with other AI abilities.

Giving vs. Asking For Information

Information for the Tool

The AI's Command

All Available Information

User's Input

Current Situation

Scope: only 'input' allowed

Run the Tool

A human can check here

Depending on how you set up the _scopes rule, the AI can either be given the information it needs automatically, or it can ask for it when it's running.

  • Static Scopes (Giving Information): If the _scopes rule has a const (constant) value, it means the information is pre-approved and given. The programmer has decided ahead of time the exact information the tool is allowed to see.

    {
      "_scopes": {
        "const": ["input"]
      }
    }
    
  • Dynamic Scopes (Asking For Information): The _scopes rule can also be flexible, which lets the AI ask for the information it needs. The AI looks at the situation and decides which of the allowed pieces of info it needs to do its job.

    {
      "_scopes": {
        "type": "array",
        "items": {
          "enum": ["state", "input"]
        }
      }
    }
    

    This asking pattern is really useful when you have a person check the AI's work. The AI can ask, "Can I see this piece of information?" and a human can approve it, adding an important layer of safety and control.

How Scopes Help Different Tasks Work Together

The _scopes property is the main way to control what an AI Call can see. It's like a permission slip that filters out all the unneeded information, giving the task a very limited and focused view. This is essential for how different kinds of tasks work, from simple thinking to using pre-built tools.

  • Latent Execution (AI Thinking): When the AI is just thinking and figuring things out, _scopes act like a friendly hint to focus its attention on the important stuff. It's a gentle guide, not a strict rule, but it's very helpful for making the AI's thinking more reliable and cheaper by cutting out distracting information. See the Focusing on the Right User example.

  • Explicit Execution (Using a Tool): When a Call uses a pre-programmed tool, or Activity, the scope's job is much more direct. The information it points to is handed directly to the tool as a package of extra data. This gives the tool all the context it needs to work, even if that info wasn't directly part of the AI's main command. See the Giving a Tool Extra Information example.

  • Instancing (Working on a Batch): Imagine you ask the AI to do the same task on a list of 10 items. Scopes make sure that when the AI is working on item #5, it only sees the information for item #5. This is super important to keep data separate and prevent information from one task from spilling over and confusing another. It's like giving each worker their own separate desk with only their assigned papers.

  • Delegated Isolation (Asking another AI for Help): When one AI agent asks a specialized agent (a Delegate) to handle a task, scopes act like a gatekeeper. They decide what information from the first agent's world gets added to the specialist's world. Nothing gets through unless it's on the list, making sure the specialist agent works in its own secure bubble. See the Giving Information to a Specialist Agent and Handling Batches with Specialist Agents examples.

The _scopes property is the bridge that connects a task to the information it needs. We've seen how this one simple idea changes its role for different situations—from gently guiding the AI's thoughts to strictly defining the information for a specialist tool. This flexibility is what makes it a key part of building smart, safe, and well-organized AI systems.

Examples

Example: Focusing on the Right User

Confusing Situation

In this example, the situation is confusing. There are two users: the currentUser (Alice) who is using the app, and a mentionedUser (Bob) in her message. The AI is asked to send a message, but it's not clear to whom.

[
  {
    "type": "state",
    "currentUser": { "id": "user_A", "name": "Alice" }
  },
  {
    "type": "input",
    "mentionedUser": { "id": "user_B", "name": "Bob" },
    "instruction": "Send a welcome message to the user mentioned above."
  }
]

`Call` with a Scope

By adding _scopes: ["input"], the person making the request gives the AI a big clue. It tells the AI to only pay attention to the input message. This clears up the confusion and makes sure the message is sent to the right person, Bob.

{
  "_tool": "sendMessage",
  "_scopes": ["input"],
  "recipientId": "user_B",
  "message": "Welcome, Bob!"
}

Example: Giving a Tool Extra Information

Here, a pre-programmed tool (Activity) needs to know something that isn't one of its main inputs. The logEvent tool only asks for an eventName, but the code behind it also needs to know the userId to work properly.

`Call` with a Scope

The Call is simple; it just gives the eventName. But the _scopes: ["state"] part tells the system to also hand the entire state object to the tool.

{
  "_tool": "logEvent",
  "_scopes": ["state"],
  "eventName": "user_login"
}

How the Tool's Code Works (TypeScript)

The tool is set up so its code can grab information directly from both the main command and the extra scoped data. This gives it easy access to both the eventName and the userId from the state.

// The code is set up to grab 'eventName' from the main command
// and 'state' from the extra scoped information.
Activity.register('logEvent', async ({ eventName }, { state }) => {
  const userId = state.userId;
  await analytics.track(eventName, { userId });
});

Example: Giving Information to a Specialist Agent

When one agent asks another for help, _scopes decide what information from the first agent gets added to the specialist's own world. Here, a main Orchestrator agent asks a specialized Summarizer agent to do a task, passing it the whole state object.

Main Agent's `Call` with Scope

The Orchestrator agent has its own information. When it calls for help, it uses a scope to include its state so the specialist can see it.

// The Orchestrator's information and its call for help
[
  {
    "type": "state",
    "articleText": "A long and complex article..."
  },
  {
    "_tool": "summarizeArticle",
    "_delegate": "SummarizerAgent",
    "_scopes": ["state"]
  }
]

Specialist Agent's View

The Summarizer's world is built from its own internal rules plus the specific information passed to it by the main agent. This lets agents be separate and specialized while still sharing the info they need to work together.

// The information the Summarizer sees for its task
[
  // The Summarizer's own built-in instructions
  {
    "type": "system",
    "message": "You are an expert summarizer."
  },
  // The scoped information from the main agent is added
  {
    "type": "state",
    "articleText": "A long and complex article..."
  }
]

Example: Handling Batches with Specialist Agents

This example shows how _scopes and _instance work together so one main agent can manage several separate tasks by specialist agents all at once.

Main Agent's Data & Plan

The main agent has two different pieces of text to translate, marked as instance and . It creates a plan with two Calls to a translatorDelegate specialist. Each call points to a different instance and correctly includes only the state for that specific instance.

// MAIN AGENT'S DATA
[
  { "type": "state", "_instance": "①", "text": "Hello" },
  { "type": "state", "_instance": "②", "text": "Bonjour" }
]

// THE AI'S PLAN
{
  "calls": [
    {
      "_tool": "translate",
      "_delegate": "translatorDelegate",
      "_instance": "①",
      "_scopes": ["state"]
    },
    {
      "_tool": "translate",
      "_delegate": "translatorDelegate",
      "_instance": "②",
      "_scopes": ["state"]
    }
  ]
}

Specialist Agents' Views

The system automatically creates two separate jobs. The _instance and _scopes rules work together to make sure that each specialist only gets the information for its assigned task.

// INFORMATION FOR SPECIALIST ①
[
  { "type": "system", "message": "You are a translator." },
  { "type": "state", "text": "Hello" }
]

// INFORMATION FOR SPECIALIST ②
[
  { "type": "system", "message": "You are a translator." },
  { "type": "state", "text": "Bonjour" }
]