Skip to content
EngineeringRead as Markdown

How to assemble context from a SemDAG

Socra

· 4 min read

Suppose an agent is about to add invitations to your application. The invitation rules refer to membership, membership refers to an Account, and an Account refers to identity. Reading the invitation rules alone leaves the meaning of each of those terms open to interpretation.

A SemDAG records those prerequisites. Each Module owns a subject, and an edge says that one subject requires another. To prepare the agent for the task, collect the target Module and its dependencies, then arrange them in an order that can be read from the foundations up.

Declare what depends on what

Use this fictional project as an example:

ModuleDirect dependenciesKnowledge it owns
IdentityNoneA person has a stable identifier.
AccountIdentityAn Account defines an organization boundary.
MembershipAccount, IdentityMembership associates a person with an Account.
InvitationsAccount, MembershipAn invitation lets a person join an Account.

Read an edge from the dependent to its prerequisite: Invitations depends on Membership. The reading order goes the other way, because the prerequisite must come first.

The direct Identity dependency on Membership is redundant in this small graph: Account already reaches Identity. It is included here to show why shared prerequisites need deduplication.

Collect the full dependency closure

Begin at Invitations. Follow the dependency to Account, then the dependency from Account to Identity. Identity has no dependencies, so it can be placed in the bundle first. Account can follow it.

Next, visit Membership. Its prerequisites are Account and Identity, both of which are already in the bundle. Include Membership once, then finish with Invitations.

The assembled reading order is:

  1. Identity
  2. Account
  3. Membership
  4. Invitations

Following all paths reaches Identity several times. The assembled bundle still includes its content only once. In a larger graph, independent Modules may have several valid relative orders. What matters is that every dependency comes before the Module that needs it.

Detect a cycle before returning a bundle

Imagine changing Identity to depend on Invitations. You now have a path from Invitations to Account to Identity and back to Invitations. There is no order that satisfies all the prerequisites.

A graph traversal can keep two sets: Modules currently being visited and Modules whose dependencies have been fully visited. Reaching a Module in the first set indicates a cycle. Reaching one in the second means its knowledge is already included.

The following TypeScript example implements that rule. It is teaching code for this article, not the Cortex API or its production implementation.

TypeScript
type KnowledgeModule = {
  name: string;
  dependencies: string[];
  content: string;
};

function assemble(target: string, modules: Map<string, KnowledgeModule>) {
  const visiting = new Set<string>();
  const included = new Set<string>();
  const bundle: KnowledgeModule[] = [];

  function visit(name: string) {
    if (included.has(name)) return;
    if (visiting.has(name)) throw new Error('Dependency cycle: ' + name);
    const module = modules.get(name);
    if (!module) throw new Error('Missing Module: ' + name);
    visiting.add(name);
    for (const prerequisite of module.dependencies) visit(prerequisite);
    visiting.delete(name);
    included.add(name);
    bundle.push(module);
  }

  visit(target);
  return bundle;
}

In this implementation, dependency array order determines the order of otherwise independent branches. The two sets prevent duplicates and detect cycles. A missing Module fails explicitly, so the caller cannot mistake incomplete context for a complete bundle.

Deliver the knowledge before the task

The resulting list describes the assembly order. To supply context, include the content of those Modules in that order. In Cortex, the operation that requests a Module with its dependencies is called a flash.

The graph only knows the dependencies people declare. A correct traversal of an incomplete graph can still leave out knowledge the agent needs. Review the dependency choices as carefully as the text in each Module.

A bundle also has a size. Including each Module once removes repetition inside that bundle, but it does not guarantee the bundle fits every model’s context window. Inspect the assembled content and keep each dependency tied to a real comprehension need.

Keep the example separate from the product

This example demonstrates the SemDAG assembly rule on fictional knowledge. A production system also needs access controls, versioning, failure handling, and a way for people to maintain the graph. Those concerns determine what an agent may receive and how the knowledge stays current.

For the architectural background, read Mike Morton’s Agent Context Needs an Import Statement. For the current product, use the Cortex documentation. The SemDAG overview connects the terminology to the whole approach.