Skip to main content

Agent Framework Overview

Agent Framework Overview

The repository uses a shared descriptor/factory contract while keeping runtime registration in the owning domain or cross-cutting loader. Source and tests are authoritative; generated agent contracts describe the product-domain slice and must not be interpreted as every optional/core/docs agent that could be loaded.

Runtime lifecycle

  1. A module declares an AgentDescriptor containing stable profileId and registryId values plus code-owned defaults.
  2. Its loader configures injected model, voice, storage, and embedding dependencies.
  3. getAgent() reads the current database profile and calculates its effective content hash.
  4. The factory reuses a matching build promise or rebuilds the agent with the resolved prompt, model, tools/browser, voice, and allowed memory settings.
  5. The loader returns the agent under its registryId; the runtime merges all active artifacts with duplicate detection.

profileId keys Core.AgentProfiles. registryId keys the live Mastra registry. They are intentionally allowed to differ.

Current ownership

Agent familySourceRegistration owner
K12packages/domain-k12/src/agents/**K12 loader (loader-core.ts)
SDACpackages/domain-sdac/src/agents/**packages/domain-sdac/src/loader.ts
TAPpackages/domain-tap/src/agents/**packages/domain-tap/src/loader.ts
Handbookpackages/domain-handbook/src/agents/**packages/domain-handbook/src/loader.ts
Shared/coresrc/mastra/agents/shared/**src/mastra/artifacts/core.loader.ts
Docs chatsrc/mastra/agents/shared/docs-chat-agents.tssrc/mastra/artifacts/docs.loader.ts
Reasoning Enginesrc/mastra/agents/reasoning-engine/**src/mastra/artifacts/reasoning-engine.loader.ts

The generated active-domain barrels are build artifacts. Do not register a package-owned agent directly in apps/runtime/src/mastra-runtime.ts and do not edit generated barrels by hand.

Supported module patterns

Most agents expose a descriptor plus five operations:

export const MY_AGENT_DESCRIPTOR: AgentDescriptor = {
profileId: 'example-purpose',
registryId: 'example-purpose-agent',
defaultName: 'Purpose Agent',
defaultPrompt: 'A complete fallback prompt...',
domain: 'Example',
functionalGroup: 'Purpose',
projects: ['testing'],
memoryOptions: null,
};

export function configureMyAgent(deps: AgentDependencies): void;
export function getMyAgentFactory(): IAgentFactory;
export async function getMyAgent(): Promise<Agent>;
export async function buildMyAgentFresh(): Promise<AgentBuildResult>;
export function invalidateMyAgentCache(): void;

Descriptor families may provide keyed versions of those operations. K12 annex agents are the primary family example. A request-specific agent may use buildFresh() when its instructions genuinely depend on request context, but it must still use the shared profile and model resolution path.

Reasoning Engine agents use a transitional family cache. It is supported for that source-owned optional subsystem, but it is not the template for a new package-domain agent.

Profiles, models, and memory

  • Code defaults are always required and are used when the current profile is absent or cannot be read.
  • LlmOverridesJson is parsed through the shared Zod schema. Supported fields include deployment/model/provider selection, common sampling and token settings, reasoning effort, endpoint/protocol fields, and observational memory settings.
  • Model capability validation uses Core.LLMModelCapabilities and current Core.LLMParamsDim data through the provider stack.
  • Memory is created only when the descriptor/profile enables it and a compatible runtime storage dependency exists. Set memoryOptions explicitly; use null/false for agents whose callers manage history.
  • Caller-provided generation instructions remain runtime input. The model wrapper may normalize unsupported parameters, but it must not replace caller instructions with a build-time prompt.

Registry and contract boundaries

The live descriptor registry used by admin seed/reconcile routes is packages/platform-runtime/src/server/routes/agent-registry-descriptor-registry.ts. The static registry in src/mastra/agents/shared/descriptor-registry.ts still supports conformance and memory tests. Keep both aligned until the test registry is migrated.

Runtime discovery is target-specific:

  • GET /agents.json lists currently loaded registry IDs.
  • GET /{domain}/routes.json lists domain-friendly agent routes.
  • POST /{domain}/agents/{slug}/generate and /stream invoke agents through the generated domain route surface.

docs/contracts/runtime-agent-contracts.json is generated from the audited product-domain registry surface. Use live discovery when you need the artifacts loaded by a particular deployment target.

Debugging

Useful flags include:

MASTRA_DEBUG_AGENT_FACTORY=true
MASTRA_DEBUG_AGENT_PROMPT=true
MASTRA_DEBUG_AGENT_PROMPT_FULL=false
AGENT_PROFILES_DEBUG=true

When a prompt or model appears stale, compare the descriptor profileId, the current profile's effective hash, the selected deployment target, and the live /agents.json result. Restarting should not be the first cache-invalidation strategy: getAgent() checks profile content and rebuilds on a hash change.

Verification

Use the owning domain suite plus the shared guards:

npm run test:agents
npm run test:admin
npm run test:contracts
npm run contracts:check
npm run contracts:bruno

Run npm run test:k12, test:sdac, test:tap, or test:handbook for a product agent. Loader/export changes also require the applicable target build or npm run verify:runtime-smoke.