Documentation/Task Agents
v2.0.0-beta.1Snapshot bebdcd1Markdown ↗

Task Agents

Task Agents

Autonomous agents with planning and memory

CheckpointManager class

📍 src/capabilities/taskAgent/CheckpointManager.ts:36

Manages state checkpointing for persistence and recovery

Constructor

constructor

typescript
constructor(storage: IAgentStorage, strategy: CheckpointStrategy = DEFAULT_CHECKPOINT_STRATEGY)

Parameters:

  • storage: IAgentStorage
  • strategy: CheckpointStrategy (optional) (default: DEFAULT_CHECKPOINT_STRATEGY)
Methods

setCurrentState()

Set the current agent state (for interval checkpointing)

typescript
setCurrentState(state: AgentState): void

Parameters:

  • state: AgentState

Returns: void

onToolCall()

Record a tool call (may trigger checkpoint)

typescript
async onToolCall(state: AgentState): Promise<void>

Parameters:

  • state: AgentState

Returns: Promise<void>

onLLMCall()

Record an LLM call (may trigger checkpoint)

typescript
async onLLMCall(state: AgentState): Promise<void>

Parameters:

  • state: AgentState

Returns: Promise<void>

checkpoint()

Force a checkpoint

typescript
async checkpoint(state: AgentState, reason: string): Promise<void>

Parameters:

  • state: AgentState
  • reason: string

Returns: Promise<void>

flush()

Wait for all pending checkpoints to complete

typescript
async flush(): Promise<void>

Returns: Promise<void>

cleanup()

Cleanup resources

typescript
async cleanup(): Promise<void>

Returns: Promise<void>


ExternalDependencyHandler class

📍 src/capabilities/taskAgent/ExternalDependencyHandler.ts:21

Handles external task dependencies

Constructor

constructor

typescript
constructor(tools: ToolFunction[] = [])

Parameters:

  • tools: ToolFunction<any, any>[] (optional) (default: [])
Methods

startWaiting()

Start handling a task's external dependency

typescript
async startWaiting(task: Task): Promise<void>

Parameters:

  • task: Task

Returns: Promise<void>

stopWaiting()

Stop waiting on a task's external dependency

typescript
stopWaiting(task: Task): void

Parameters:

  • task: Task

Returns: void

triggerWebhook()

Trigger a webhook

typescript
async triggerWebhook(webhookId: string, data: unknown): Promise<void>

Parameters:

  • webhookId: string
  • data: unknown

Returns: Promise<void>

completeManual()

Complete a manual task

typescript
async completeManual(taskId: string, data: unknown): Promise<void>

Parameters:

  • taskId: string
  • data: unknown

Returns: Promise<void>

cleanup()

Cleanup all active dependencies

typescript
cleanup(): void

Returns: void

updateTools()

Update available tools

typescript
updateTools(tools: ToolFunction[]): void

Parameters:

  • tools: ToolFunction<any, any>[]

Returns: void


InContextMemoryPluginNextGen class

📍 src/core/context-nextgen/plugins/InContextMemoryPluginNextGen.ts:89

Constructor

constructor

typescript
constructor(config: InContextMemoryConfig = {})

Parameters:

  • config: InContextMemoryConfig (optional) (default: {})
Methods

getInstructions()

typescript
getInstructions(): string

Returns: string

getContent()

typescript
async getContent(): Promise<string | null>

Returns: Promise<string | null>

getContents()

typescript
getContents(): Map<string, InContextEntry>

Returns: Map<string, InContextEntry>

getTokenSize()

typescript
getTokenSize(): number

Returns: number

getInstructionsTokenSize()

typescript
getInstructionsTokenSize(): number

Returns: number

isCompactable()

typescript
isCompactable(): boolean

Returns: boolean

compact()

typescript
async compact(targetTokensToFree: number): Promise<number>

Parameters:

  • targetTokensToFree: number

Returns: Promise<number>

getTools()

typescript
getTools(): ToolFunction[]

Returns: ToolFunction<any, any>[]

destroy()

typescript
destroy(): void

Returns: void

getState()

typescript
getState(): SerializedInContextMemoryState

Returns: SerializedInContextMemoryState

restoreState()

typescript
restoreState(state: unknown): void

Parameters:

  • state: unknown

Returns: void

set()

Store or update a key-value pair

typescript
set(key: string, description: string, value: unknown, priority?: InContextPriority, showInUI?: boolean): void

Parameters:

  • key: string
  • description: string
  • value: unknown
  • priority: InContextPriority | undefined (optional)
  • showInUI: boolean | undefined (optional)

Returns: void

get()

Get a value by key

typescript
get(key: string): unknown | undefined

Parameters:

  • key: string

Returns: unknown

has()

Check if a key exists

typescript
has(key: string): boolean

Parameters:

  • key: string

Returns: boolean

delete()

Delete an entry

typescript
delete(key: string): boolean

Parameters:

  • key: string

Returns: boolean

list()

List all entries with metadata

typescript
list(): Array<{ key: string; description: string; priority: InContextPriority; updatedAt: number; showInUI: boolean }>

Returns: { key: string; description: string; priority: InContextPriority; updatedAt: number; showInUI: boolean; }[]

clear()

Clear all entries

typescript
clear(): void

Returns: void

getStoreSchema()

typescript
getStoreSchema(): StoreEntrySchema

Returns: StoreEntrySchema

storeGet()

typescript
async storeGet(key?: string, _context?: ToolContext): Promise<StoreGetResult>

Parameters:

  • key: string | undefined (optional)
  • _context: ToolContext | undefined (optional)

Returns: Promise<StoreGetResult>

storeSet()

typescript
async storeSet(key: string, data: Record<string, unknown>, _context?: ToolContext): Promise<StoreSetResult>

Parameters:

  • key: string
  • data: Record<string, unknown>
  • _context: ToolContext | undefined (optional)

Returns: Promise<StoreSetResult>

storeDelete()

typescript
async storeDelete(key: string, _context?: ToolContext): Promise<StoreDeleteResult>

Parameters:

  • key: string
  • _context: ToolContext | undefined (optional)

Returns: Promise<StoreDeleteResult>

storeList()

typescript
async storeList(_filter?: Record<string, unknown>, _context?: ToolContext): Promise<StoreListResult>

Parameters:

  • _filter: Record<string, unknown> | undefined (optional)
  • _context: ToolContext | undefined (optional)

Returns: Promise<StoreListResult>

Properties
Property Type Description
name name: "in_context_memory" -

InMemoryAdapter class

📍 src/memory/adapters/inmemory/InMemoryAdapter.ts:55

Constructor

constructor

typescript
constructor(opts: InMemoryAdapterOptions = {})

Parameters:

  • opts: InMemoryAdapterOptions (optional) (default: {})
Methods

createEntity()

typescript
async createEntity(input: NewEntity): Promise<IEntity>

Parameters:

  • input: NewEntity

Returns: Promise<IEntity>

createEntities()

typescript
async createEntities(inputs: NewEntity[]): Promise<IEntity[]>

Parameters:

  • inputs: NewEntity[]

Returns: Promise<IEntity[]>

updateEntity()

typescript
async updateEntity(entity: IEntity): Promise<void>

Parameters:

  • entity: IEntity

Returns: Promise<void>

getEntity()

typescript
async getEntity(id: EntityId, scope: ScopeFilter): Promise<IEntity | null>

Parameters:

  • id: string
  • scope: ScopeFilter

Returns: Promise<IEntity | null>

getEntities()

typescript
async getEntities(ids: EntityId[], scope: ScopeFilter): Promise<Array<IEntity | null>>

Parameters:

  • ids: string[]
  • scope: ScopeFilter

Returns: Promise<(IEntity | null)[]>

findEntitiesByIdentifier()

typescript
async findEntitiesByIdentifier(
    kind: string,
    value: string,
    scope: ScopeFilter,
  ): Promise<IEntity[]>

Parameters:

  • kind: string
  • value: string
  • scope: ScopeFilter

Returns: Promise<IEntity[]>

atomicCreateOrFindByNormalizedName()

Atomic find-or-create by (type, normalizedDisplayName, scope). See the interface contract. JS event-loop atomicity: the body has a single await (the createEntity call); the find-by-normalized phase runs synchronously over the in-memory map, so two concurrent invocations cannot both pass the find without one observing the other's insert.

typescript
async atomicCreateOrFindByNormalizedName(
    input: NewEntity,
    scope: ScopeFilter,
  ): Promise<{ entity: IEntity; created: boolean }>

Parameters:

  • input: NewEntity
  • scope: ScopeFilter

Returns: Promise<{ entity: IEntity; created: boolean; }>

findEntitiesByNormalizedName()

typescript
async findEntitiesByNormalizedName(
    type: string | undefined,
    normalized: string,
    scope: ScopeFilter,
    opts?: { matchAliases?: boolean; limit?: number },
  ): Promise<IEntity[]>

Parameters:

  • type: string | undefined
  • normalized: string
  • scope: ScopeFilter
  • opts: { matchAliases?: boolean | undefined; limit?: number | undefined; } | undefined (optional)

Returns: Promise<IEntity[]>

searchEntities()

typescript
async searchEntities(
    query: string,
    opts: EntitySearchOptions,
    scope: ScopeFilter,
  ): Promise<Page<IEntity>>

Parameters:

  • query: string
  • opts: EntitySearchOptions
  • scope: ScopeFilter

Returns: Promise<Page<IEntity>>

listEntities()

typescript
async listEntities(
    filter: EntityListFilter,
    opts: ListOptions,
    scope: ScopeFilter,
  ): Promise<Page<IEntity>>

Parameters:

  • filter: EntityListFilter
  • opts: ListOptions
  • scope: ScopeFilter

Returns: Promise<Page<IEntity>>

archiveEntity()

typescript
async archiveEntity(id: EntityId, scope: ScopeFilter): Promise<void>

Parameters:

  • id: string
  • scope: ScopeFilter

Returns: Promise<void>

deleteEntity()

typescript
async deleteEntity(id: EntityId, scope: ScopeFilter): Promise<void>

Parameters:

  • id: string
  • scope: ScopeFilter

Returns: Promise<void>

createFact()

typescript
async createFact(input: NewFact): Promise<IFact>

Parameters:

  • input: NewFact

Returns: Promise<IFact>

createFacts()

typescript
async createFacts(inputs: NewFact[]): Promise<IFact[]>

Parameters:

  • inputs: NewFact[]

Returns: Promise<IFact[]>

getFact()

typescript
async getFact(id: FactId, scope: ScopeFilter): Promise<IFact | null>

Parameters:

  • id: string
  • scope: ScopeFilter

Returns: Promise<IFact | null>

findFacts()

typescript
async findFacts(
    filter: FactFilter,
    opts: FactQueryOptions,
    scope: ScopeFilter,
  ): Promise<Page<IFact>>

Parameters:

  • filter: FactFilter
  • opts: FactQueryOptions
  • scope: ScopeFilter

Returns: Promise<Page<IFact>>

updateFact()

typescript
async updateFact(id: FactId, patch: Partial<IFact>, scope: ScopeFilter): Promise<void>

Parameters:

  • id: string
  • patch: Partial<IFact>
  • scope: ScopeFilter

Returns: Promise<void>

rewriteEntityPrincipal()

Rewrite entity:<from> → entity:<to> access grants across stored entities + facts. In-place mutation of the backing maps (reads return clones, so callers never see partial state). Mirrors MongoMemoryAdapter.rewriteEntityPrincipal — scoped to the caller's tenant (scope.groupId) for parity + defense-in-depth.

typescript
async rewriteEntityPrincipal(
    fromEntityId: EntityId,
    toEntityId: EntityId,
    scope: ScopeFilter,
  ): Promise&lt;void&gt;

Parameters:

  • fromEntityId: string
  • toEntityId: string
  • scope: ScopeFilter

Returns: Promise&lt;void&gt;

countFacts()

typescript
async countFacts(filter: FactFilter, scope: ScopeFilter): Promise&lt;number&gt;

Parameters:

  • filter: FactFilter
  • scope: ScopeFilter

Returns: Promise&lt;number&gt;

traverse()

typescript
async traverse(
    startId: EntityId,
    opts: TraversalOptions,
    scope: ScopeFilter,
  ): Promise&lt;Neighborhood&gt;

Parameters:

  • startId: string
  • opts: TraversalOptions
  • scope: ScopeFilter

Returns: Promise&lt;Neighborhood&gt;

semanticSearch()

typescript
async semanticSearch(
    queryVector: number[],
    filter: FactFilter,
    opts: SemanticSearchOptions,
    scope: ScopeFilter,
  ): Promise&lt;Array&lt;{ fact: IFact; score: number }&gt;&gt;

Parameters:

  • queryVector: number[]
  • filter: FactFilter
  • opts: SemanticSearchOptions
  • scope: ScopeFilter

Returns: Promise&lt;{ fact: IFact; score: number; }[]&gt;

semanticSearchEntities()

typescript
async semanticSearchEntities(
    queryVector: number[],
    filter: EntitySemanticSearchFilter,
    opts: SemanticSearchOptions & { minScore?: number; embeddingField?: EntityEmbeddingField },
    scope: ScopeFilter,
  ): Promise&lt;Array&lt;{ entity: IEntity; score: number }&gt;&gt;

Parameters:

  • queryVector: number[]
  • filter: EntitySemanticSearchFilter
  • opts: SemanticSearchOptions & { minScore?: number | undefined; embeddingField?: EntityEmbeddingField | undefined; }
  • scope: ScopeFilter

Returns: Promise&lt;{ entity: IEntity; score: number; }[]&gt;

destroy()

typescript
destroy(): void

Returns: void


InMemoryAgentStateStorage class

📍 src/infrastructure/storage/InMemoryStorage.ts:140

In-memory implementation of IAgentStateStorage

Methods

save()

typescript
async save(state: AgentState): Promise&lt;void&gt;

Parameters:

  • state: AgentState

Returns: Promise&lt;void&gt;

load()

typescript
async load(agentId: string): Promise&lt;AgentState | undefined&gt;

Parameters:

  • agentId: string

Returns: Promise&lt;AgentState | undefined&gt;

delete()

typescript
async delete(agentId: string): Promise&lt;void&gt;

Parameters:

  • agentId: string

Returns: Promise&lt;void&gt;

list()

typescript
async list(filter?: { status?: AgentStatus[] }): Promise&lt;AgentState[]&gt;

Parameters:

  • filter: { status?: AgentStatus[] | undefined; } | undefined (optional)

Returns: Promise&lt;AgentState[]&gt;

patch()

typescript
async patch(agentId: string, updates: Partial&lt;AgentState&gt;): Promise&lt;void&gt;

Parameters:

  • agentId: string
  • updates: Partial&lt;AgentState&gt;

Returns: Promise&lt;void&gt;


InMemoryEvidenceStorage class

📍 src/infrastructure/storage/EvidenceStorage.ts:202

Bounded process-local store. Share the instance explicitly when resuming in-process.

Methods

inventory()

typescript
protected async inventory(): Promise&lt;Array&lt;{ id: string; bytes: number }&gt;&gt;

Returns: Promise&lt;{ id: string; bytes: number; }[]&gt;

writeBlob()

typescript
protected async writeBlob(id: string, bytes: Buffer): Promise&lt;void&gt;

Parameters:

  • id: string
  • bytes: Buffer&lt;ArrayBufferLike&gt;

Returns: Promise&lt;void&gt;

readBlob()

typescript
protected async readBlob(id: string): Promise&lt;Buffer | null&gt;

Parameters:

  • id: string

Returns: Promise&lt;Buffer&lt;ArrayBufferLike&gt; | null&gt;

removeBlob()

typescript
protected async removeBlob(id: string): Promise&lt;boolean&gt;

Parameters:

  • id: string

Returns: Promise&lt;boolean&gt;

Properties
Property Type Description
durability durability: "process" -
queueKey queueKey: ${string}-${string}-${string}-${string}-${string}`` -

InMemoryHistoryStorage class

📍 src/infrastructure/storage/InMemoryHistoryStorage.ts:17

In-memory history storage implementation

Methods

addMessage()

typescript
async addMessage(message: HistoryMessage): Promise&lt;void&gt;

Parameters:

  • message: HistoryMessage

Returns: Promise&lt;void&gt;

getMessages()

typescript
async getMessages(): Promise&lt;HistoryMessage[]&gt;

Returns: Promise&lt;HistoryMessage[]&gt;

getRecentMessages()

typescript
async getRecentMessages(count: number): Promise&lt;HistoryMessage[]&gt;

Parameters:

  • count: number

Returns: Promise&lt;HistoryMessage[]&gt;

removeMessage()

typescript
async removeMessage(id: string): Promise&lt;void&gt;

Parameters:

  • id: string

Returns: Promise&lt;void&gt;

removeOlderThan()

typescript
async removeOlderThan(timestamp: number): Promise&lt;number&gt;

Parameters:

  • timestamp: number

Returns: Promise&lt;number&gt;

clear()

typescript
async clear(): Promise&lt;void&gt;

Returns: Promise&lt;void&gt;

getCount()

typescript
async getCount(): Promise&lt;number&gt;

Returns: Promise&lt;number&gt;

getState()

typescript
async getState(): Promise&lt;SerializedHistoryState&gt;

Returns: Promise&lt;SerializedHistoryState&gt;

restoreState()

typescript
async restoreState(state: SerializedHistoryState): Promise&lt;void&gt;

Parameters:

  • state: SerializedHistoryState

Returns: Promise&lt;void&gt;


InMemoryMetrics class

📍 src/infrastructure/observability/Metrics.ts:83

In-memory metrics aggregator (testing/development)

Methods

increment()

typescript
increment(metric: string, value: number = 1, tags?: MetricTags): void

Parameters:

  • metric: string
  • value: number (optional) (default: 1)
  • tags: MetricTags | undefined (optional)

Returns: void

gauge()

typescript
gauge(metric: string, value: number, tags?: MetricTags): void

Parameters:

  • metric: string
  • value: number
  • tags: MetricTags | undefined (optional)

Returns: void

timing()

typescript
timing(metric: string, duration: number, tags?: MetricTags): void

Parameters:

  • metric: string
  • duration: number
  • tags: MetricTags | undefined (optional)

Returns: void

histogram()

typescript
histogram(metric: string, value: number, tags?: MetricTags): void

Parameters:

  • metric: string
  • value: number
  • tags: MetricTags | undefined (optional)

Returns: void

getMetrics()

Get all metrics (for testing)

typescript
getMetrics(): {
    counters: Map&lt;string, number&gt;;
    gauges: Map&lt;string, number&gt;;
    timings: Map&lt;string, number[]&gt;;
    histograms: Map&lt;string, number[]&gt;;
  }

Returns: { counters: Map&lt;string, number&gt;; gauges: Map&lt;string, number&gt;; timings: Map&lt;string, number[]&gt;; histograms: Map&lt;string, number[]&gt;; }

clear()

Clear all metrics

typescript
clear(): void

Returns: void

getTimingStats()

Get summary statistics for timings

typescript
getTimingStats(metric: string, tags?: MetricTags): {
    count: number;
    min: number;
    max: number;
    mean: number;
    p50: number;
    p95: number;
    p99: number;
  } | null

Parameters:

  • metric: string
  • tags: MetricTags | undefined (optional)

Returns: { count: number; min: number; max: number; mean: number; p50: number; p95: number; p99: number; } | null


InMemoryPlanStorage class

📍 src/infrastructure/storage/InMemoryStorage.ts:70

In-memory implementation of IPlanStorage

Methods

savePlan()

typescript
async savePlan(plan: Plan): Promise&lt;void&gt;

Parameters:

  • plan: Plan

Returns: Promise&lt;void&gt;

getPlan()

typescript
async getPlan(planId: string): Promise&lt;Plan | undefined&gt;

Parameters:

  • planId: string

Returns: Promise&lt;Plan | undefined&gt;

updateTask()

typescript
async updateTask(planId: string, task: Task): Promise&lt;void&gt;

Parameters:

  • planId: string
  • task: Task

Returns: Promise&lt;void&gt;

addTask()

typescript
async addTask(planId: string, task: Task): Promise&lt;void&gt;

Parameters:

  • planId: string
  • task: Task

Returns: Promise&lt;void&gt;

deletePlan()

typescript
async deletePlan(planId: string): Promise&lt;void&gt;

Parameters:

  • planId: string

Returns: Promise&lt;void&gt;

listPlans()

typescript
async listPlans(filter?: { status?: PlanStatus[] }): Promise&lt;Plan[]&gt;

Parameters:

  • filter: { status?: PlanStatus[] | undefined; } | undefined (optional)

Returns: Promise&lt;Plan[]&gt;

findByWebhookId()

typescript
async findByWebhookId(webhookId: string): Promise&lt;{ plan: Plan; task: Task } | undefined&gt;

Parameters:

  • webhookId: string

Returns: Promise&lt;{ plan: Plan; task: Task; } | undefined&gt;


InMemoryStorage class

📍 src/infrastructure/storage/InMemoryStorage.ts:15

In-memory implementation of IMemoryStorage

Methods

get()

typescript
async get(key: string): Promise&lt;MemoryEntry | undefined&gt;

Parameters:

  • key: string

Returns: Promise&lt;MemoryEntry | undefined&gt;

set()

typescript
async set(key: string, entry: MemoryEntry): Promise&lt;void&gt;

Parameters:

  • key: string
  • entry: MemoryEntry

Returns: Promise&lt;void&gt;

delete()

typescript
async delete(key: string): Promise&lt;void&gt;

Parameters:

  • key: string

Returns: Promise&lt;void&gt;

has()

typescript
async has(key: string): Promise&lt;boolean&gt;

Parameters:

  • key: string

Returns: Promise&lt;boolean&gt;

getAll()

typescript
async getAll(): Promise&lt;MemoryEntry[]&gt;

Returns: Promise&lt;MemoryEntry[]&gt;

getByScope()

typescript
async getByScope(scope: MemoryScope): Promise&lt;MemoryEntry[]&gt;

Parameters:

  • scope: MemoryScope

Returns: Promise&lt;MemoryEntry[]&gt;

clearScope()

typescript
async clearScope(scope: MemoryScope): Promise&lt;void&gt;

Parameters:

  • scope: MemoryScope

Returns: Promise&lt;void&gt;

clear()

typescript
async clear(): Promise&lt;void&gt;

Returns: Promise&lt;void&gt;

getTotalSize()

typescript
async getTotalSize(): Promise&lt;number&gt;

Returns: Promise&lt;number&gt;


InvalidTaskTransitionError class

📍 src/memory/MemorySystem.ts:222

Thrown when transitionTaskState is called with validate: 'strict' and the (from, to) pair is not allowed by the caller-supplied transition matrix.

Constructor

constructor

typescript
constructor(taskId: EntityId, from: string | undefined, to: string)

Parameters:

  • taskId: string
  • from: string | undefined
  • to: string
Properties
Property Type Description
from `from: string undefined`
to to: string -
taskId taskId: string -

MemoryConnectorStorage class

📍 src/connectors/storage/MemoryConnectorStorage.ts:20

Methods

save()

typescript
async save(name: string, stored: StoredConnectorConfig): Promise&lt;void&gt;

Parameters:

  • name: string
  • stored: StoredConnectorConfig

Returns: Promise&lt;void&gt;

get()

typescript
async get(name: string): Promise&lt;StoredConnectorConfig | null&gt;

Parameters:

  • name: string

Returns: Promise&lt;StoredConnectorConfig | null&gt;

delete()

typescript
async delete(name: string): Promise&lt;boolean&gt;

Parameters:

  • name: string

Returns: Promise&lt;boolean&gt;

has()

typescript
async has(name: string): Promise&lt;boolean&gt;

Parameters:

  • name: string

Returns: Promise&lt;boolean&gt;

list()

typescript
async list(): Promise&lt;string[]&gt;

Returns: Promise&lt;string[]&gt;

listAll()

typescript
async listAll(): Promise&lt;StoredConnectorConfig[]&gt;

Returns: Promise&lt;StoredConnectorConfig[]&gt;

clear()

Clear all stored configs (useful for testing)

typescript
clear(): void

Returns: void

size()

Get the number of stored configs

typescript
size(): number

Returns: number


MemoryEvictionCompactor class

📍 src/infrastructure/context/compactors/MemoryEvictionCompactor.ts:10

Constructor

constructor

typescript
constructor(private estimator: ITokenEstimator)

Parameters:

  • estimator: ITokenEstimator
Methods

canCompact()

typescript
canCompact(component: IContextComponent): boolean

Parameters:

  • component: IContextComponent

Returns: boolean

compact()

typescript
async compact(component: IContextComponent, targetTokens: number): Promise&lt;IContextComponent&gt;

Parameters:

  • component: IContextComponent
  • targetTokens: number

Returns: Promise&lt;IContextComponent&gt;

estimateSavings()

typescript
estimateSavings(component: IContextComponent): number

Parameters:

  • component: IContextComponent

Returns: number

Properties
Property Type Description
name name: "memory-eviction" -
priority priority: 8 -

MemoryPluginNextGen class

📍 src/core/context-nextgen/plugins/MemoryPluginNextGen.ts:361

Constructor

constructor

typescript
constructor(config: MemoryPluginConfig)

Parameters:

  • config: MemoryPluginConfig
Methods

getInstructions()

typescript
getInstructions(): string

Returns: string

prepare()

Force lazy bootstrap to complete.

The plugin resolves userEntityId / agentEntityId / groupEntityId lazily on first getContent(). That's fine when the agent starts with an LLM turn — getContent() runs as part of building the first prompt.

It's NOT fine when the agent starts with deterministic pre-steps (e.g. routines: preSteps execute before the first LLM turn). A pre-step invoking memory_recall({ subject: 'me' }) calls getOwnSubjectIds().userEntityId — undefined → "no user scope" error.

prepare() is the contract for "make sure your lazy state is ready before any tool you contribute is invoked". The routine runner calls it once after building the agent and before pre-steps fire. Idempotent.

typescript
async prepare(): Promise&lt;void&gt;

Returns: Promise&lt;void&gt;

getContent()

typescript
async getContent(): Promise&lt;string | null&gt;

Returns: Promise&lt;string | null&gt;

getContents()

typescript
getContents(): unknown

Returns: unknown

getTokenSize()

typescript
getTokenSize(): number

Returns: number

getInstructionsTokenSize()

typescript
getInstructionsTokenSize(): number

Returns: number

isCompactable()

typescript
isCompactable(): boolean

Returns: boolean

compact()

typescript
async compact(_targetTokensToFree: number): Promise&lt;number&gt;

Parameters:

  • _targetTokensToFree: number

Returns: Promise&lt;number&gt;

getTools()

typescript
getTools(): ToolFunction[]

Returns: ToolFunction&lt;any, any&gt;[]

destroy()

typescript
destroy(): void

Returns: void

getState()

typescript
getState(): unknown

Returns: unknown

restoreState()

typescript
restoreState(state: unknown): void

Parameters:

  • state: unknown

Returns: void

getBootstrappedIds()

Entity IDs created (or resolved) during bootstrap. Undefined before bootstrap. Always returns the variant agent entity id (keyed by system_agent_id), even when a persona is configured — for "what was actually bootstrapped" use this; for "what 'me' / 'this_agent' resolve to in tools" use getOwnSubjectIds().

typescript
getBootstrappedIds(): {
    userEntityId?: string;
    agentEntityId?: string;
    groupEntityId?: string;
  }

Returns: { userEntityId?: string | undefined; agentEntityId?: string | undefined; groupEntityId?: string | undefined; }

getOwnSubjectIds()

Subject ids for LLM-facing 'me' / 'this_agent' token resolution, used by both this plugin's read tools and (via AgentContextNextGen's wiring) MemoryWritePluginNextGen's write tools. agentEntityId here is persona-aware: if a personaEntityId was configured, this returns the persona, so memory_set_agent_rule writes and rule-block reads share one subject across every variant carrying the same persona.

Use getBootstrappedIds() instead when you need the variant agent entity id (analytics, factContextIds, snapshots).

typescript
getOwnSubjectIds(): { userEntityId?: string; agentEntityId?: string }

Returns: { userEntityId?: string | undefined; agentEntityId?: string | undefined; }

Properties
Property Type Description
name name: "memory" -

MemoryStorage class

📍 src/connectors/oauth/infrastructure/storage/MemoryStorage.ts:9

Methods

storeToken()

typescript
async storeToken(key: string, token: StoredToken): Promise&lt;void&gt;

Parameters:

  • key: string
  • token: StoredToken

Returns: Promise&lt;void&gt;

getToken()

typescript
async getToken(key: string): Promise&lt;StoredToken | null&gt;

Parameters:

  • key: string

Returns: Promise&lt;StoredToken | null&gt;

deleteToken()

typescript
async deleteToken(key: string): Promise&lt;void&gt;

Parameters:

  • key: string

Returns: Promise&lt;void&gt;

hasToken()

typescript
async hasToken(key: string): Promise&lt;boolean&gt;

Parameters:

  • key: string

Returns: Promise&lt;boolean&gt;

clearAll()

Clear all tokens (useful for testing)

typescript
clearAll(): void

Returns: void

size()

Get number of stored tokens

typescript
size(): number

Returns: number

listKeys()

List all storage keys (for account enumeration)

typescript
async listKeys(): Promise&lt;string[]&gt;

Returns: Promise&lt;string[]&gt;


MemorySystem class

📍 src/memory/MemorySystem.ts:304

Constructor

constructor

typescript
constructor(config: MemorySystemConfig)

Parameters:

  • config: MemorySystemConfig
Methods

upsertEntity()

typescript
async upsertEntity(
    input: Partial&lt;IEntity&gt; & {
      identifiers: Identifier[];
      displayName: string;
      type: string;
      /**
       * How `input.metadata` is folded into an existing entity on resolve.
       * Default: undefined → metadata is ignored on resolve (current behavior,
       * backward-compatible).
       *  - `'fillMissing'`: only set keys absent from stored metadata; existing
       *    values are never overwritten. Safe for LLM-driven re-extraction.
       *  - `'overwrite'`: shallow-merge — incoming keys win. Use when the
       *    caller is authoritative (calendar API for events, sync from system
       *    of record).
       *
       * On create (no match) all keys are set verbatim regardless of this option.
       */
      metadataMerge?: 'fillMissing' | 'overwrite';
      /**
       * Optional whitelist applied when `metadataMerge` is set: only these
       * top-level keys are touched. Other incoming keys are ignored. Lets the
       * caller pin the merge to a known set (e.g. `['startTime','endTime',
       * 'status']` for events) without leaking unrelated extracted fields.
       *
       * Has no effect when `metadataMerge` is unset.
       */
      metadataMergeKeys?: string[];
    },
    scope: ScopeFilter,
    options?: {
      /**
       * Allow a resolve-and-update to mutate an existing entity owned by a
       * different user WITHIN THE SAME GROUP/TENANT. Default `false`.
       *
       * When `true`: if the best-match entity shares `scope.groupId`, the
       * per-owner `assertCanAccess(write)` check is skipped — so trusted
       * server-side consolidation (e.g. the signal pipeline converging a
       * group-visible Person/Organization that another user in the same group
       * created) can enrich it without re-owning it first. Mirrors the
       * `allowCrossOwner` option on `mergeEntities`.
       *
       * Tenancy invariant is preserved: a cross-tenant best-match (different
       * `groupId`) still goes through `assertCanAccess`, which denies it — the
       * flag never enables cross-tenant writes. The host is responsible for
       * gating which callers may pass it (server pipeline code only — never an
       * agent/tool surface).
       */
      allowCrossOwner?: boolean;
    },
  ): Promise&lt;UpsertEntityResult&gt;

Parameters:

  • input: Partial&lt;IEntity&gt; & { identifiers: Identifier[]; displayName: string; type: string; metadataMerge?: "fillMissing" | "overwrite" | undefined; metadataMergeKeys?: string[] | undefined; }
  • scope: ScopeFilter
  • options: { allowCrossOwner?: boolean | undefined; } | undefined (optional)

Returns: Promise&lt;UpsertEntityResult&gt;

getEntity()

typescript
getEntity(id: EntityId, scope: ScopeFilter): Promise&lt;IEntity | null&gt;

Parameters:

  • id: string
  • scope: ScopeFilter

Returns: Promise&lt;IEntity | null&gt;

getEntities()

Batch fetch. Returned array aligns with ids positionally; missing ids / scope-filtered-out entries become null. Intended for call sites that need to resolve many EntityId references cheaply (e.g. rendering fact.objectId as a displayName in the system message).

typescript
getEntities(ids: EntityId[], scope: ScopeFilter): Promise&lt;Array&lt;IEntity | null&gt;&gt;

Parameters:

  • ids: string[]
  • scope: ScopeFilter

Returns: Promise&lt;(IEntity | null)[]&gt;

findEntitiesByIdentifier()

Return every entity visible at scope whose identifier list contains (kind, value). Thin pass-through to the store — exposed so callers that need to detect bootstrap duplicates (e.g. MemoryPluginNextGen) don't have to reach into store directly.

typescript
findEntitiesByIdentifier(
    kind: string,
    value: string,
    scope: ScopeFilter,
  ): Promise&lt;IEntity[]&gt;

Parameters:

  • kind: string
  • value: string
  • scope: ScopeFilter

Returns: Promise&lt;IEntity[]&gt;

searchEntities()

typescript
searchEntities(
    query: string,
    opts: { types?: string[]; limit?: number; cursor?: string },
    scope: ScopeFilter,
  )

Parameters:

  • query: string
  • opts: { types?: string[] | undefined; limit?: number | undefined; cursor?: string | undefined; }
  • scope: ScopeFilter

Returns: Promise&lt;Page&lt;IEntity&gt;&gt;

listEntities()

List entities by type + optional metadata equality filter. Thin pass-through to the store's listEntities — exposed on MemorySystem so tool layers don't need to reach into the store directly.

Read-side date coercion: ISO-8601 strings inside metadataFilter are coerced to Date here (once, at the public boundary) so adapters always see Date-typed values in range/equality clauses. Without it, callers (LLM tools especially) writing the natural shape — { startTime: { $gte: "2026-05-14T00:00:00Z" } } — would silently get zero matches against metadata.startTime (BSON Date), because Mongo and the InMemory comparator treat String and Date as distinct types in range comparisons. Adapters do not re-coerce — DRY, single point of responsibility across all backends.

typescript
listEntities(
    filter: import('./types.js').EntityListFilter,
    opts: import('./types.js').ListOptions,
    scope: ScopeFilter,
  )

Parameters:

  • filter: EntityListFilter
  • opts: ListOptions
  • scope: ScopeFilter

Returns: Promise&lt;Page&lt;IEntity&gt;&gt;

findFacts()

Enumerate facts directly. Pass-through to the store's findFacts so tool layers can list raw facts without reaching into the store. For ranked/ retrieval-oriented queries prefer getContext or semanticSearch.

typescript
findFacts(
    filter: FactFilter,
    opts: import('./types.js').FactQueryOptions,
    scope: ScopeFilter,
  )

Parameters:

  • filter: FactFilter
  • opts: FactQueryOptions
  • scope: ScopeFilter

Returns: Promise&lt;Page&lt;IFact&gt;&gt;

getFact()

Fetch a single fact by id. Returns null when the fact does not exist or is not visible to the caller's scope.

typescript
getFact(id: FactId, scope: ScopeFilter)

Parameters:

  • id: string
  • scope: ScopeFilter

Returns: Promise&lt;IFact | null&gt;

resolveEntity()

Resolve a surface form ("Microsoft", "Q3 Planning", "John") to ranked candidate entities. Matching tiers: strong identifier → exact displayName → exact alias → fuzzy → semantic (identityEmbedding). Returns candidates sorted by confidence; empty if nothing meets opts.threshold (default 0.5).

typescript
resolveEntity(
    query: ResolveEntityQuery,
    scope: ScopeFilter,
    opts?: ResolveEntityOptions,
  ): Promise&lt;EntityCandidate[]&gt;

Parameters:

  • query: ResolveEntityQuery
  • scope: ScopeFilter
  • opts: ResolveEntityOptions | undefined (optional)

Returns: Promise&lt;EntityCandidate[]&gt;

upsertEntityBySurface()

Upsert-or-resolve by surface form. If the top candidate clears autoResolveThreshold (default conservative 0.90), returns that entity with the new surface + identifiers merged in (alias accumulation). Otherwise creates a new entity and reports near-matches as mergeCandidates for deferred human review.

typescript
async upsertEntityBySurface(
    input: UpsertBySurfaceInput,
    scope: ScopeFilter,
    opts?: UpsertBySurfaceOptions,
  ): Promise&lt;UpsertBySurfaceResult&gt;

Parameters:

  • input: UpsertBySurfaceInput
  • scope: ScopeFilter
  • opts: UpsertBySurfaceOptions | undefined (optional)

Returns: Promise&lt;UpsertBySurfaceResult&gt;

mergeEntities()

Merge two entities — copy loser's identifiers + aliases onto winner, rewrite every fact whose subject or object is the loser to point at the winner, and archive the loser.

Scope-window limitation (defence-in-depth, by design): the rewrite step only touches facts visible to the caller's scope. Facts scoped more narrowly than the caller (e.g. other users' private facts on either entity) are left untouched and will continue to reference the archived loser. This prevents a user from rewriting data they cannot see, but means a "complete" merge requires a caller with broad-enough scope to see every referencing fact.

typescript
async mergeEntities(
    winnerId: EntityId,
    loserId: EntityId,
    scope: ScopeFilter,
    options?: {
      /**
       * Allow merging entities owned by different users within the same
       * group/tenant. Default `false`.
       *
       * When `true`: the per-entity `assertCanAccess(write)` check is
       * skipped (both winner and loser may be owned by users other than
       * `scope.userId`), AND the same bypass is applied while rewriting
       * fact references so the graph stays coherent post-merge.
       *
       * Tenancy invariant is preserved: the call refuses if
       * `winner.groupId !== loser.groupId`. The host is responsible for
       * gating which callers may pass the flag (typically a group/super
       * admin running a legitimate consolidation pass).
       *
       * The owner of the surviving winner is unchanged either way — only
       * the loser is archived, so its ownerId becomes irrelevant after.
       */
      allowCrossOwner?: boolean;
    },
  ): Promise&lt;IEntity&gt;

Parameters:

  • winnerId: string
  • loserId: string
  • scope: ScopeFilter
  • options: { allowCrossOwner?: boolean | undefined; } | undefined (optional)

Returns: Promise&lt;IEntity&gt;

setAccess()

Replace the explicit acl on an entity or fact and re-materialize its readPrincipals/writePrincipals in place. The sanctioned exception to fact-immutability for ACCESS changes (same category as the merge rewrite). Caller must have write on the record.

Backs host grant/revoke surfaces. Returns the updated record.

typescript
async setAccess(
    kind: 'entity' | 'fact',
    id: string,
    acl: ACLEntry[],
    scope: ScopeFilter,
  ): Promise&lt;IEntity | IFact&gt;

Parameters:

  • kind: "entity" | "fact"
  • id: string
  • acl: ACLEntry[]
  • scope: ScopeFilter

Returns: Promise&lt;IEntity | IFact&gt;

archiveEntity()

Archive an entity (soft delete). Cascades to facts where the entity is subjectId or objectId — those get archived too.

Tombstone semantics for contextIds (NO cascade): facts whose contextIds array references this entity, and other entities whose top-level contextIds references this one, are LEFT UNCHANGED. The reference becomes a dangling pointer — readers resolving the id see null (archived), the referencing record stays live. Symmetric across fact-contextIds (long-standing behavior) and entity-contextIds. Rationale: contextIds is a soft multi-anchor binding, not a hard structural edge; force-removing it on archive would destructively mutate consumer records the caller may not even own. Hosts that want a stronger semantic should run a sweep after archive.

typescript
async archiveEntity(id: EntityId, scope: ScopeFilter): Promise&lt;void&gt;

Parameters:

  • id: string
  • scope: ScopeFilter

Returns: Promise&lt;void&gt;

deleteEntity()

Delete an entity. Soft (default): same cascade rules as archiveEntity. Hard (opts.hard: true): the entity row is removed; facts where it's subject/object are archived. Same tombstone rule for contextIds: contextIds references — fact-level and entity-level — are left as dangling pointers. See archiveEntity JSDoc for rationale.

typescript
async deleteEntity(
    id: EntityId,
    scope: ScopeFilter,
    opts: { hard?: boolean } = {},
  ): Promise&lt;void&gt;

Parameters:

  • id: string
  • scope: ScopeFilter
  • opts: { hard?: boolean | undefined; } (optional) (default: {})

Returns: Promise&lt;void&gt;

canonicalizePredicate()

Normalize a predicate string to its canonical form. When no registry is configured, returns the input unchanged.

Used by ExtractionResolver and available to external callers that want to pre-normalize predicates before querying.

typescript
canonicalizePredicate(input: string): string

Parameters:

  • input: string

Returns: string

hasPredicateRegistry()

True when a predicate registry is configured on this MemorySystem.

typescript
hasPredicateRegistry(): boolean

Returns: boolean

getPredicateRegistry()

Return the configured predicate registry, or undefined when none is set. Exposed so prompt-rendering layers (e.g. MemoryWritePluginNextGen) can generate LLM-facing predicate vocabulary from the same source of truth — avoids hand-maintained predicate lists drifting out of sync with what the storage layer actually accepts and ranks.

typescript
getPredicateRegistry(): PredicateRegistry | undefined

Returns: PredicateRegistry | undefined

ensureAdapterIndexes()

H7: ensure the configured adapter has all recommended indexes. No-op for adapters that don't expose ensureIndexes (InMemoryAdapter has nothing to index). Delegates to the adapter's own method — typically MongoMemoryAdapter.ensureIndexes(). Idempotent.

Call from your migration system, not from application hot paths. Index creation on production collections can be expensive; the library intentionally does not call this automatically at construction time.

See docs/MEMORY_PERMISSIONS.md (or the memory README) for the full list of recommended indexes and why each matters. Cross-process deployments with MemoryPluginNextGen additionally need a unique index on {identifiers.kind: 1, identifiers.value: 1} (partial, filtered on identifiers.$.value: {$exists: true}) — this one is not created by ensureIndexes() because adding a unique index to a collection with existing duplicates fails hard; callers should build + verify it explicitly in a migration.

typescript
async ensureAdapterIndexes(): Promise&lt;void&gt;

Returns: Promise&lt;void&gt;

assertEnterpriseReady()

Surface configuration drift that would make this MemorySystem unsafe for enterprise multi-tenant deployment. Returns a list of human-readable failings rather than throwing — hosts gate startup on findings.length.

Two readiness tiers — ok is not "fully enterprise ready":

  • ok === true → the MINIMUM-SAFETY tier passed: data integrity invariants are held + tenant isolation is enforceable. No severity: 'error' findings remain. The host can boot without risking cross-tenant data leaks, owner-required violations, or permission-denial bypasses, but the LLM-writer ergonomics may still be lax.
  • ok === true AND findings.every(f => f.severity !== 'warn') → the FULL enterprise-readiness tier. Adds the strict-vocabulary guarantee (LLM writers can't invent predicates), enables Mongo's fast paths for vector search, and confirms the adapter is fully tuned. This is what production deployments should actually gate on.

Operators who want the stricter gate:

ts
const { ok, findings } = memory.assertEnterpriseReady();
const enterpriseReady = ok && findings.every((f) => f.severity !== 'warn');
if (!enterpriseReady) throw new Error(`Memory not fully ready: ${JSON.stringify(findings)}`);

Severity rationale:

  • 'error' is reserved for invariant violations — config that lets bad data into the store or leaks across tenants (no visibilityPolicy, no PredicateRegistry at all).
  • 'warn' covers quality / ergonomics — config that hurts retrieval, consistency, or LLM-write hygiene but doesn't compromise integrity (permissive predicate mode, missing vector index names).

What's checked:

  • error — PredicateRegistry is configured. Without one, predicates remain free-form strings; fragmentation is guaranteed under any LLM-driven write path.
  • error — visibilityPolicy is set. Library defaults grant world-read to every entity/fact (644-style) — unsafe by default for enterprise. A policy that returns { world: 'none' } (private) or { world: 'none', group: 'read' } (group-readable) is the typical enterprise baseline.
  • warn — predicateMode === 'strict'. Permissive mode + LLM writers fragments the predicate vocabulary over time (prefers vs prefer vs preference), eroding dedup and ranking quality. Not an error because the data still has owners + permissions; only the vocabulary hygiene is at risk.
  • warn — Mongo adapter: vectorIndexName is set (drives Atlas Vector Search fast paths). Skipped for InMemoryAdapter.
  • warn — Mongo adapter + embedder present: entityContentVectorIndexName is set. Without it findSimilarOpenTasks, document search, and any composer-driven retrieval fall back to the slow path.

What's NOT checked (require side effects the library shouldn't trigger from a readonly probe):

  • Whether the Mongo unique partial index on {identifiers.kind, identifiers.value} actually exists. Run a migration-side probe (db.entities.getIndexes()).
  • Whether the unique normalized-name partial index from ensureNormalizedNameUniqueIndex exists. Same — migration-side.
  • Whether ensureVectorSearchIndexes() has been called against Atlas. Idempotent to call again from your migration; that's the supported path.
typescript
assertEnterpriseReady(): {
    ok: boolean;
    findings: Array&lt;{ severity: 'error' | 'warn'; code: string; message: string }&gt;;
  }

Returns: { ok: boolean; findings: { severity: "error" | "warn"; code: string; message: string; }[]; }

backfillNormalizedFields()

Backfill normalizedDisplayName + normalizedAliases on entities written before v0.8.0 (or by adapter paths that bypassed the storage-boundary stamp). Iterates entities in scope in batches, recomputes the fields from each entity's current displayName / aliases, and writes when the stored value differs.

Idempotent — running twice with the same data is a no-op. Run before ensureNormalizedNameUniqueIndex (the unique partial index would fail to build if pre-backfill dups exist).

Returns { scanned, updated, skipped } for caller observability:

  • scanned — total entities visited.
  • updated — wrote an entity because at least one field differed.
  • skipped — entity already had both fields populated and consistent; no write performed.

Concurrency caveat: the backfill uses updateEntity (optimistic concurrency on version). Concurrent writers bumping the version between read and write trigger a retry once; further conflicts surface as OptimisticConcurrencyError on the helper.

Force mode: pass { force: true } to write every scanned entity regardless of whether the stored value differs. Useful when normalizeSurface has been tweaked and the entire population needs re-stamping. Default is the cheaper differ-only path.

typescript
async backfillNormalizedFields(
    scope: ScopeFilter,
    opts?: { batchSize?: number; force?: boolean },
  ): Promise&lt;{ scanned: number; updated: number; skipped: number }&gt;

Parameters:

  • scope: ScopeFilter
  • opts: { batchSize?: number | undefined; force?: boolean | undefined; } | undefined (optional)

Returns: Promise&lt;{ scanned: number; updated: number; skipped: number; }&gt;

backfillAccessPrincipals()

Backfill readPrincipals / writePrincipals on every entity + fact (live AND archived) written before the principal model — or by any path that predates the storage-boundary stamp. Recomputes each row's arrays from its ownerId / groupId / permissions / acl and writes when they differ.

THE MIGRATION GATE: a host MUST run this to completion before it starts passing scope.principals. Query-time (Mongo) filtering has NO legacy fallback for rows lacking readPrincipals — an un-backfilled row is simply invisible to a principal caller (see ScopeFilter.principals).

Idempotent — re-running with the same data is a no-op (arrays are recomputed deterministically and compared before writing). { force: true } rewrites every row regardless (use after the materialization rules change).

Entities go through updateEntity (the storage boundary re-stamps the arrays) with the same retry-once optimistic-concurrency handling as backfillNormalizedFields. Facts are patched directly with the computed arrays (no updateFact recompute is triggered — the patch carries the arrays, not the access-source fields).

typescript
async backfillAccessPrincipals(
    scope: ScopeFilter,
    opts?: { batchSize?: number; force?: boolean },
  ): Promise&lt;{
    entitiesScanned: number;
    entitiesUpdated: number;
    factsScanned: number;
    factsUpdated: number;
  }&gt;

Parameters:

  • scope: ScopeFilter
  • opts: { batchSize?: number | undefined; force?: boolean | undefined; } | undefined (optional)

Returns: Promise&lt;{ entitiesScanned: number; entitiesUpdated: number; factsScanned: number; factsUpdated: number; }&gt;

hoistContextIdsFromFactsToEntities()

Migration helper — for every fact with the given predicate, hoist the fact's contextIds array onto the target entity's contextIds (union merge). Target entity is the fact's subject or object depending on entitySide.

Reference recipe — hoist legacy committed_to(person, task) linkage onto task entities (the v10-era pattern that v11+ writes natively as task.contextIds):

ts
await memory.hoistContextIdsFromFactsToEntities({
  predicate: 'committed_to',
  entitySide: 'object',
  entityType: 'task',
  archiveSource: false, // keep originals as provenance until host confirms
}, scope);

Idempotent — addEntityContextIds deduplicates against existing values. Safe to re-run. Skips facts with empty contextIds, missing target id, or where the target entity type doesn't match entityType.

Performance. O(facts-with-this-predicate). Pass batchSize to tune memory pressure vs round-trips (default 200, hard ceiling 1000).

Source archival. When archiveSource: true, the source fact is archived after the hoist succeeds for that fact. Defaults to false because hosts often want to keep the original fact for provenance — the migration is informational, not destructive.

typescript
async hoistContextIdsFromFactsToEntities(
    opts: {
      predicate: string;
      entitySide: 'subject' | 'object';
      entityType?: string;
      batchSize?: number;
      dryRun?: boolean;
      archiveSource?: boolean;
    },
    scope: ScopeFilter,
  ): Promise&lt;{
    scannedFacts: number;
    /** Facts that triggered a real entity write (added &gt;= 1 new contextId). */
    hoistedEntities: number;
    /**
     * Facts where the target entity already had every contextId — no write
     * performed. Important for migration planning: re-runs of an idempotent
     * migration are expected to land entirely in this bucket. Also bumped on
     * dry-run when the simulated hoist would have been a no-op.
     */
    skippedAlreadyHoisted: number;
    skippedNoContextIds: number;
    skippedWrongType: number;
    skippedNoTarget: number;
    archivedFacts: number;
    errors: number;
  }&gt;

Parameters:

  • opts: { predicate: string; entitySide: "object" | "subject"; entityType?: string | undefined; batchSize?: number | undefined; dryRun?: boolean | undefined; archiveSource?: boolean | undefined; }
  • scope: ScopeFilter

Returns: Promise&lt;{ scannedFacts: number; hoistedEntities: number; skippedAlreadyHoisted: number; skippedNoContextIds: number; skippedWrongType: number; skippedNoTarget: number; archivedFacts: number; errors: number; }&gt;

getPredicateDefinition()

Lookup a predicate definition (by canonical name or alias). Null when no registry or unknown.

typescript
getPredicateDefinition(nameOrAlias: string): PredicateDefinition | null

Parameters:

  • nameOrAlias: string

Returns: PredicateDefinition | null

resolveUnknownPredicate()

H5: the configured drift policy + closest known predicate for an unknown. Returns { policy: 'fuzzy_map', mappedTo? } / { policy: 'keep' } / { policy: 'drop' }. mappedTo is only present when the policy is 'fuzzy_map' AND a close registry match exists. Intended for callers (ExtractionResolver) that want to apply the policy themselves and record the decision in their result payload.

typescript
resolveUnknownPredicate(canonical: string): {
    policy: 'fuzzy_map' | 'keep' | 'drop';
    mappedTo?: string;
    distance?: number;
  }

Parameters:

  • canonical: string

Returns: { policy: "fuzzy_map" | "keep" | "drop"; mappedTo?: string | undefined; distance?: number | undefined; }

addFact()

typescript
async addFact(
    input: Partial&lt;IFact&gt; & {
      subjectId: EntityId;
      predicate: string;
      kind: IFact['kind'];
      /**
       * When true: before inserting, look for a non-archived fact with the same
       * (subjectId, canonicalized predicate, kind) and matching (value, objectId).
       * On match → bump `observedAt` on the existing fact and return it — NO new
       * row is inserted. Used by the session ingestor to prevent bloat across
       * repeated observations ("anton works_at everworker" re-extracted).
       * Details merging is the caller's responsibility (see updateFactDetails).
       * Defaults to false for backward-compatibility.
       */
      dedup?: boolean;
    },
    scope: ScopeFilter,
  ): Promise&lt;IFact&gt;

Parameters:

  • input: Partial&lt;IFact&gt; & { subjectId: string; predicate: string; kind: FactKind; dedup?: boolean | undefined; }
  • scope: ScopeFilter

Returns: Promise&lt;IFact&gt;

addFacts()

typescript
async addFacts(
    inputs: Array&lt;
      Partial&lt;IFact&gt; & { subjectId: EntityId; predicate: string; kind: IFact['kind'] }
    &gt;,
    scope: ScopeFilter,
  ): Promise&lt;IFact[]&gt;

Parameters:

  • inputs: (Partial&lt;IFact&gt; & { subjectId: string; predicate: string; kind: FactKind; })[]
  • scope: ScopeFilter

Returns: Promise&lt;IFact[]&gt;

supersedeFact()

typescript
supersedeFact(
    oldId: FactId,
    newInput: Partial&lt;IFact&gt; & { predicate: string; kind: IFact['kind']; subjectId: EntityId },
    scope: ScopeFilter,
  ): Promise&lt;IFact&gt;

Parameters:

  • oldId: string
  • newInput: Partial&lt;IFact&gt; & { predicate: string; kind: FactKind; subjectId: string; }
  • scope: ScopeFilter

Returns: Promise&lt;IFact&gt;

archiveFact()

typescript
async archiveFact(id: FactId, scope: ScopeFilter): Promise&lt;void&gt;

Parameters:

  • id: string
  • scope: ScopeFilter

Returns: Promise&lt;void&gt;

expireFacts()

Scheduled lifecycle sweep — archives facts whose validUntil is in the past relative to asOf (defaults to "now"). Host applications call this on a daily cadence to keep the visible graph trimmed.

Contract:

  • Only affects facts that already have validUntil set. Facts without validUntil are valid forever and never touched.
  • Only archives facts that are NOT already archived.
  • Archived facts remain queryable via archivedOnly / includeArchived paths — this is soft archive, not hard delete.
  • Scope-bounded: the caller's scope determines which facts are visible. Multi-tenant schedulers iterate over scopes and call once per scope.
  • Emits BOTH fact.archive and fact.expire per archived fact. The fact.archive event preserves the "any archival" contract that existing subscribers (cache invalidators, audit appenders) depend on; fact.expire is the lifecycle-specific signal carrying predicate + validUntil for observability that wants to distinguish automatic expiry from operator/agent archives.

Returns the count of facts archived in this sweep. Paginated internally to bound memory; pageSize defaults to 500.

typescript
async expireFacts(
    opts: {
      /** Cutoff. Facts with `validUntil &lt; asOf` are eligible. Defaults to `new Date()`. */
      asOf?: Date;
      /**
       * Restrict to specific predicates. When omitted, all expired facts in
       * scope are archived. Pass `[]` to short-circuit to 0 (no-op).
       */
      predicates?: string[];
      /** Maximum number of facts to archive in this call. Defaults to unbounded. */
      limit?: number;
      /** Internal page size for findFacts. Defaults to 500. */
      pageSize?: number;
    },
    scope: ScopeFilter,
  ): Promise&lt;{ archived: number }&gt;

Parameters:

  • opts: { asOf?: Date | undefined; predicates?: string[] | undefined; limit?: number | undefined; pageSize?: number | undefined; }
  • scope: ScopeFilter

Returns: Promise&lt;{ archived: number; }&gt;

restoreFact()

Reverse of archiveFact — restore a previously-archived fact so it participates in queries again. Used by the memory_restore tool to give agents an undo path for mistaken archives.

F1 guard: if the target fact was archived as part of a supersession (i.e. another non-archived fact has supersedes: targetId), restoring it would create two "current" facts for the same (subject, predicate) pair. Throws FactSupersededError with the successor's id so callers can handle the successor first. The tool layer surfaces this as a structured error to the LLM.

typescript
async restoreFact(id: FactId, scope: ScopeFilter): Promise&lt;void&gt;

Parameters:

  • id: string
  • scope: ScopeFilter

Returns: Promise&lt;void&gt;

updateFactDetails()

Update an existing fact's details field in place. Intended for merging narrative context when the session ingestor finds a duplicate fact and produces an LLM-merged details string. Recomputes isSemantic (the merged text may cross the length threshold), clears the stale embedding, and re-embeds if an embedder is configured.

This mutates the fact — the prior details is lost. Use supersession if you need the full audit chain.

typescript
async updateFactDetails(
    id: FactId,
    details: string,
    scope: ScopeFilter,
  ): Promise&lt;IFact&gt;

Parameters:

  • id: string
  • details: string
  • scope: ScopeFilter

Returns: Promise&lt;IFact&gt;

applyEntityReconciliationOps()

Apply entity-anchored reconciliation operations (Pillar 2).

Caller has:

  1. Built an entityReconciliationPrompt for ONE entity's non-archived facts.
  2. Run that prompt through an extractor (LLM call).
  3. Parsed the LLM output into ReconciliationOp[] via parseExtractionWithStatus.

This method dispatches the resulting ops against the fact graph:

  • update → updateFact (value / details / observedAt patch).
  • archive → archiveFact.
  • create ops are REJECTED (counted as rejectedHallucinated in the outcome) — Pillar 2 only resolves, never creates.

factId validation: every update/archive op's factId MUST appear in priorFacts. Hallucinations are rejected with a warn-level log entry.

Returns op-level counts so callers can log decisions + emit activity-log entries (per feedback_log_every_decision).

typescript
async applyEntityReconciliationOps(
    ops: ReconciliationOp[],
    priorFacts: IFact[],
    scope: ScopeFilter,
    opts?: {
      /** Optional skeptic filter — return false to drop an op with logging. */
      skepticFilter?: (op: ReconciliationOp) =&gt; boolean;
      /**
       * Source signal id to stamp on `updateFact` patches. Optional — entity
       * reconciliation isn't bound to a single source signal (that's the
       * point), so callers may leave it undefined.
       */
      sourceSignalId?: string;
    },
  ): Promise&lt;OperationOutcome&gt;

Parameters:

  • ops: ReconciliationOp[]
  • priorFacts: IFact[]
  • scope: ScopeFilter
  • opts: { skepticFilter?: ((op: ReconciliationOp) =&gt; boolean) | undefined; sourceSignalId?: string | undefined; } | undefined (optional)

Returns: Promise&lt;OperationOutcome&gt;

applyReconciliationOps()

Apply signal-reconciliation operations (the SECOND pass — see signalReconciliationPrompt). Generic over signal source: the caller has extracted NEW facts/tasks in pass 1, loaded the PRIOR facts/tasks (deterministic + semantic, de-duplicated), run signalReconciliationPrompt, and parsed the output via parseSignalReconciliationOpsWithStatus.

Dispatch:

  • FACT ops are delegated to {@link applyEntityReconciliationOps} — archive supersedes, update mutates in place, create is rejected (the pass reconciles, it does not create — pass 1 owns creation). Every fact op's factId is validated against context.priorFacts.
  • task_update ops mutate the task in place: newState routes through {@link transitionTaskState} (state + stateHistory + completedAt), and narrative / dueAt / assigneeId patch the metadata. Every taskId is validated against context.priorTasks; hallucinated ids are rejected. When newState moves the task into a TERMINAL state, the task metadata is stamped with AI-resolution provenance (aiResolved, aiResolutionReason, aiResolutionEvidenceQuote, aiResolvedAt) so the host can distinguish AI auto-resolution from user action.

Returns op-level counts (fact creates/updates/archives + task updates/resolves

  • rejections) so callers can log every decision per feedback_log_every_decision.
typescript
async applyReconciliationOps(
    ops: SignalReconciliationOp[],
    context: { priorFacts: IFact[]; priorTasks: IEntity[] },
    scope: ScopeFilter,
    opts?: {
      /** Optional skeptic filter — return false to drop an op with logging. */
      skepticFilter?: (op: SignalReconciliationOp) =&gt; boolean;
      /** Source signal id stamped on fact-update patches + task state history. */
      sourceSignalId?: string;
      /** Transition timestamp. Defaults to now. */
      at?: Date;
    },
  ): Promise&lt;SignalReconciliationOutcome&gt;

Parameters:

  • ops: SignalReconciliationOp[]
  • context: { priorFacts: IFact[]; priorTasks: IEntity[]; }
  • scope: ScopeFilter
  • opts: { skepticFilter?: ((op: SignalReconciliationOp) =&gt; boolean) | undefined; sourceSignalId?: string | undefined; at?: Date | undefined; } | undefined (optional)

Returns: Promise&lt;SignalReconciliationOutcome&gt;

updateFact()

Mutate a fact in-place. Used by per-conversation reconciliation (ExtractionResolver) to update value / details / observedAt / sourceSignalId / evidenceQuote on a prior fact when the LLM emits an update op — replacing the legacy "supersede chain" pattern that left tombstones behind.

Restrictions:

  • Cannot change subjectId, predicate, kind, objectId, id, createdAt, archived (use archiveFact / restoreFact).
  • Caller's scope must have write access to the fact.

Side effects:

  • When details changes, re-computes isSemantic, clears stale embedding + summaryForEmbedding, and re-embeds on the embedder queue (best-effort).
typescript
async updateFact(
    id: FactId,
    patch: Partial&lt;
      Pick&lt;
        IFact,
        | 'value'
        | 'details'
        | 'observedAt'
        | 'sourceSignalId'
        | 'evidenceQuote'
        | 'confidence'
        | 'importance'
        | 'metadata'
      &gt;
    &gt;,
    scope: ScopeFilter,
  ): Promise&lt;IFact&gt;

Parameters:

  • id: string
  • patch: Partial&lt;Pick&lt;IFact, "metadata" | "value" | "details" | "confidence" | "evidenceQuote" | "sourceSignalId" | "importance" | "observedAt"&gt;&gt;
  • scope: ScopeFilter

Returns: Promise&lt;IFact&gt;

findDuplicateFact()

Find an existing non-archived fact matching the (subjectId, predicate, kind, value, objectId) signature of input. Returns null on no match.

Exposed for callers (the session ingestor) that need to split insert vs merge paths themselves — e.g. to batch LLM-based details merging across several duplicates rather than merging one at a time.

Predicate is canonicalized via the registry (if one is configured) so aliases match the same way addFact would treat them.

typescript
async findDuplicateFact(
    input: Partial&lt;IFact&gt; & {
      subjectId: EntityId;
      predicate: string;
      kind: IFact['kind'];
    },
    scope: ScopeFilter,
  ): Promise&lt;IFact | null&gt;

Parameters:

  • input: Partial&lt;IFact&gt; & { subjectId: string; predicate: string; kind: FactKind; }
  • scope: ScopeFilter

Returns: Promise&lt;IFact | null&gt;

getContext()

typescript
async getContext(
    entityId: EntityId,
    opts: ContextOptions,
    scope: ScopeFilter,
  ): Promise&lt;EntityView&gt;

Parameters:

  • entityId: string
  • opts: ContextOptions
  • scope: ScopeFilter

Returns: Promise&lt;EntityView&gt;

resolveRelatedItems()

Tasks related to a subject entity. Finds task entities (type='task') where any of the common relational metadata fields point at the subject, OR where a relational fact ties a task to the subject. Returns only non- terminal states by default.

typescript
async resolveRelatedItems(
    entityIds: EntityId[],
    scope: ScopeFilter,
    opts?: {
      types?: ('task' | 'event')[];
      /** Task state filter. Default: configured `taskStates.active`. Pass empty array to disable filtering. */
      taskStates?: string[];
      /** Per-bucket cap (tasks and events each capped at this value). Default 50, hard ceiling 200. */
      limit?: number;
      asOf?: Date;
      recentEventsWindowDays?: number;
    },
  ): Promise&lt;RelatedItemsResult&gt;

Parameters:

  • entityIds: string[]
  • scope: ScopeFilter
  • opts: { types?: ("task" | "event")[] | undefined; taskStates?: string[] | undefined; limit?: number | undefined; asOf?: Date | undefined; recentEventsWindowDays?: number | undefined; } | undefined (optional)

Returns: Promise&lt;RelatedItemsResult&gt;

findSimilarOpenTasks()

Semantic kNN over open tasks. Embeds queryText and ranks active tasks by similarity against their contentEmbedding — the metadata-rich composed text (state, due date, assignee/project displayNames, description, contextIds — see taskContentComposer in composers/defaults.ts). This is what lets generic-title tasks like "Follow up" rank correctly when 50 tasks share a name but differ on assignee/project/dueAt.

Pushes the task-state filter into the vector pipeline via EntitySemanticSearchFilter.states when configured filter paths support it (metadata.state in ENTITIES_FILTER_PATHS on Mongo Atlas). The post-filter loop is kept as belt-and-suspenders for adapters that silently ignore unknown filter fields.

Returns empty array when no embedder/semantic adapter is configured — callers should treat semantic similarity as opportunistic, not load-bearing.

typescript
async findSimilarOpenTasks(
    queryOrVector: string | number[],
    scope: ScopeFilter,
    opts?: {
      topK?: number;
      minScore?: number;
      taskStates?: string[];
      /**
       * Narrow the search to tasks whose top-level `contextIds` includes this
       * entity id. Pushed into the underlying `semanticSearchEntities` filter
       * → Atlas `$vectorSearch.filter` clause. Requires `'contextIds'` in the
       * entities vector index's filter paths (declared by default — see
       * `ENTITIES_FILTER_PATHS` in MongoMemoryAdapter).
       */
      contextId?: EntityId;
      /**
       * Narrow by assignee entity id. Pushed into vector pipeline filter via
       * `metadata.assigneeId` path. Useful for "tasks for Alice similar to X"
       * scoped queries.
       */
      assigneeId?: EntityId;
      /**
       * Narrow by project entity id. Pushed into vector pipeline filter via
       * `metadata.projectId` path.
       */
      projectId?: EntityId;
      /**
       * Narrow by reporter entity id. Pushed into vector pipeline filter via
       * `metadata.reporterId` path. Mirrors `assigneeId`. Useful for surgical
       * "tasks where X is reporter" queries — e.g. "what did I ask Y to do?".
       */
      reporterId?: EntityId;
      /**
       * OR-wildcard role match — narrows to tasks where this entity appears
       * in any of `metadata.assigneeId`, `metadata.reporterId`,
       * `metadata.projectId`, or top-level `contextIds`. The entity-side
       * analog of `FactFilter.touchesEntity`.
       *
       * Prefer this over fanning out N separate role-narrowed searches and
       * unioning client-side: the union is pushed into Atlas
       * `$vectorSearch.filter` as one compound `$or`, so vector ranking sees
       * the participant-touching candidates together rather than competing
       * across role-specific top-K cuts.
       */
      touchesEntity?: EntityId;
      /**
       * Multi-anchor variant of `touchesEntity` — narrows to tasks touched by
       * ANY id in this array (any of `assigneeId`/`reporterId`/`projectId`/
       * `contextIds`). Use for participant fan-out: pass every participant +
       * context-anchor entity id and let ONE ranked vector query surface the
       * tasks relevant to the whole signal, instead of N per-anchor searches
       * unioned client-side. ANDs with `touchesEntity` when both are set.
       */
      touchesAnyOf?: EntityId[];
    },
  ): Promise&lt;Array&lt;{ task: IEntity; score: number }&gt;&gt;

Parameters:

  • queryOrVector: string | number[]
  • scope: ScopeFilter
  • opts: { topK?: number | undefined; minScore?: number | undefined; taskStates?: string[] | undefined; contextId?: string | undefined; assigneeId?: string | undefined; projectId?: string | undefined; reporterId?: string | undefined; touchesEntity?: string | undefined; touchesAnyOf?: string[] | undefined; } | undefined (optional)

Returns: Promise&lt;{ task: IEntity; score: number; }[]&gt;

semanticSearchEntities()

General-purpose entity-level semantic search over the content embedding (IEntity.contentEmbedding, populated by the registered per-type content composers). The type-agnostic analog of findSimilarOpenTasks (task-only) and searchDocuments (document-only): rank ANY entity type by semantic similarity to a query, narrowed by the full EntitySemanticSearchFilter set (type(s), contextId, task-role fields, and the single/multi touchesEntity / touchesAnyOf OR-wildcards).

Why it exists: hosts building signal-time retrieval ("which entities is this email about?") previously had to fall back to fact-level semanticSearch + manual subject/object/contextIds aggregation. This exposes the entity content vector directly, so the composed entity text (display name, identifiers, narrative, contextIds, host-specific fields) is what gets matched — strictly better recall than re-deriving entities from fact hits.

Accepts a precomputed vector (from embedQuery) to skip the per-call embed round-trip when fanning out several searches over one query.

Error contract mirrors findSimilarOpenTasks: returns [] when the store lacks a semantic-entity capability, when a string query is passed but no embedder is configured, or when the underlying search throws. Semantic similarity is opportunistic, never load-bearing.

embeddingField defaults to 'content' (the composer-backed vector). Pass 'identity' to search the name/identifier vector used by entity resolution. Adapters MUST NOT silently fall back to the other field — entities lacking the selected vector are simply absent from results.

typescript
async semanticSearchEntities(
    queryOrVector: string | number[],
    filter: EntitySemanticSearchFilter,
    scope: ScopeFilter,
    opts?: { topK?: number; minScore?: number; embeddingField?: EntityEmbeddingField },
  ): Promise&lt;Array&lt;{ entity: IEntity; score: number }&gt;&gt;

Parameters:

  • queryOrVector: string | number[]
  • filter: EntitySemanticSearchFilter
  • scope: ScopeFilter
  • opts: { topK?: number | undefined; minScore?: number | undefined; embeddingField?: EntityEmbeddingField | undefined; } | undefined (optional)

Returns: Promise&lt;{ entity: IEntity; score: number; }[]&gt;

updateEntityMetadata()

Shallow-merge a patch into entity.metadata. Version-bumping, scope-checked, emits entity.upsert event. Caller does NOT read-modify-write — this helper handles all of that atomically (from the caller's perspective).

typescript
async updateEntityMetadata(
    id: EntityId,
    patch: Record&lt;string, unknown&gt;,
    scope: ScopeFilter,
  ): Promise&lt;IEntity&gt;

Parameters:

  • id: string
  • patch: Record&lt;string, unknown&gt;
  • scope: ScopeFilter

Returns: Promise&lt;IEntity&gt;

addEntityContextIds()

Union-merge new entity ids into entity.contextIds. The canonical way to mutate the top-level multi-entity binding after creation.

Semantics:

  • Visibility-validate every addition (each must be visible to the caller; invisible ids throw — mirrors addFact's context-visibility rule).
  • Filter self-references silently (id === entityId).
  • Dedupe against existing contextIds.
  • No-op fast path when every addition is already present.

Return shape: { entity, added } — added is the count of new contextIds actually persisted (post dedupe + self-reference filter). added === 0 means the call was a no-op (everything was already there or filtered out); the returned entity is unchanged from storage. Migration / audit callers branch on added > 0 to count real mutations.

Concurrency: read-modify-write with optimistic-version retry. Two callers unioning different additions onto the same entity converge because the losing-retry observes the winner's write and computes a fresh union. maxAttempts caps at 3 — the last attempt's OptimisticConcurrencyError bubbles on exhaustion (caller's choice to surface or further-retry at a higher level).

typescript
async addEntityContextIds(
    entityId: EntityId,
    additions: EntityId[],
    scope: ScopeFilter,
    opts?: { maxAttempts?: number },
  ): Promise&lt;{ entity: IEntity; added: number }&gt;

Parameters:

  • entityId: string
  • additions: string[]
  • scope: ScopeFilter
  • opts: { maxAttempts?: number | undefined; } | undefined (optional)

Returns: Promise&lt;{ entity: IEntity; added: number; }&gt;

transitionTaskState()

Transition a task entity to a new state — the canonical way to mutate task.metadata.state after creation.

Side effects (read-modify-write at the MemorySystem layer; adapters with native transactions may promote to atomic):

  • Sets metadata.state = newState.
  • Appends metadata.stateHistory: TaskStateHistoryEntry[], keeping only the most-recent stateHistoryCap entries (default 200). Older entries drop in FIFO order. stateHistory is the only audit trail — no separate audit fact is written.
  • When newState is in taskStates.terminal AND metadata.completedAt is unset, sets metadata.completedAt = at.

Validate modes:

  • 'warn' (default): any transition allowed; out-of-matrix transitions log to console.warn and still proceed.
  • 'strict': out-of-matrix transitions throw InvalidTaskTransitionError and the metadata write is skipped.
  • 'none': silent.

Subject must be a type: 'task' entity. For non-task subjects, update metadata directly via updateEntityMetadata.

typescript
async transitionTaskState(
    taskId: EntityId,
    newState: string,
    opts: TransitionTaskStateOptions,
    scope: ScopeFilter,
  ): Promise&lt;TransitionTaskStateResult&gt;

Parameters:

  • taskId: string
  • newState: string
  • opts: TransitionTaskStateOptions
  • scope: ScopeFilter

Returns: Promise&lt;TransitionTaskStateResult&gt;

listOpenTasks()

List open (non-terminal) tasks for a scope, optionally filtered by assignee or project. Thin wrapper around listEntities — uses the configured taskStates.active as the $in filter on metadata.state.

Client-side sort: metadata.dueAt ascending (undefined last), then updatedAt descending. TODO: push down once EntityListFilter.orderBy lands on adapters.

Hard cap 200; default limit 50. Pass a smaller limit explicitly to constrain prompt-token budget when injecting into an extraction prompt.

typescript
async listOpenTasks(
    scope: ScopeFilter,
    opts: {
      assigneeId?: EntityId;
      projectId?: EntityId;
      /**
       * Narrow to tasks whose top-level `contextIds` array includes this
       * anchor (project, deal, meeting, etc.). First-class filter — does NOT
       * go through `metadataFilter` (which would query the wrong path).
       */
      contextId?: EntityId;
      limit?: number;
    } = {},
  ): Promise&lt;IEntity[]&gt;

Parameters:

  • scope: ScopeFilter
  • opts: { assigneeId?: string | undefined; projectId?: string | undefined; contextId?: string | undefined; limit?: number | undefined; } (optional) (default: {})

Returns: Promise&lt;IEntity[]&gt;

listRecentTopics()

List recent topic entities for a scope. Fetches up to limit * 4 (capped at 200) topics and filters client-side by updatedAt >= cutoff where cutoff defaults to now - days days. Sorted by updatedAt descending.

TODO: push down once EntityListFilter.updatedAfter + orderBy land on adapters.

typescript
async listRecentTopics(
    scope: ScopeFilter,
    opts: { days?: number; limit?: number } = {},
  ): Promise&lt;IEntity[]&gt;

Parameters:

  • scope: ScopeFilter
  • opts: { days?: number | undefined; limit?: number | undefined; } (optional) (default: {})

Returns: Promise&lt;IEntity[]&gt;

iterateOpenTasks()

Async iterator over all open tasks visible to scope, yielded in batches.

Sort: metadata.dueAt asc nulls-last, then updatedAt desc, then id asc tiebreak. Same as listOpenTasks, but iterates the full result set rather than truncating at 200.

Use this when you need EVERY open task (status refresh, audit sweeps, backfills). Use listOpenTasks when you need a small bounded slice (prompt injection).

typescript
async *iterateOpenTasks(
    scope: ScopeFilter,
    opts: {
      assigneeId?: EntityId;
      projectId?: EntityId;
      /** Narrow to tasks whose top-level `contextIds` includes this anchor. */
      contextId?: EntityId;
      batchSize?: number;
      /** Resume from a cursor returned by a prior interrupted iteration. */
      startAfter?: string;
    } = {},
  ): AsyncIterable&lt;IEntity[]&gt;

Parameters:

  • scope: ScopeFilter
  • opts: { assigneeId?: string | undefined; projectId?: string | undefined; contextId?: string | undefined; batchSize?: number | undefined; startAfter?: string | undefined; } (optional) (default: {})

Returns: AsyncIterable&lt;IEntity[]&gt;

iterateRecentTopics()

Async iterator over recent topic entities visible to scope, yielded in batches. Sort: updatedAt desc. The days window is applied client-side (consistent with listRecentTopics); iteration stops when either the store is exhausted OR the first batch with all entries older than the cutoff is encountered (since sort is desc, no younger ones exist past that point).

typescript
async *iterateRecentTopics(
    scope: ScopeFilter,
    opts: { days?: number; batchSize?: number; startAfter?: string } = {},
  ): AsyncIterable&lt;IEntity[]&gt;

Parameters:

  • scope: ScopeFilter
  • opts: { days?: number | undefined; batchSize?: number | undefined; startAfter?: string | undefined; } (optional) (default: {})

Returns: AsyncIterable&lt;IEntity[]&gt;

iterateEntitiesByFilter()

Generic async iterator over entities matching filter. The caller MUST pass orderBy to guarantee deterministic iteration — without it, the adapter's natural order kicks in and the iteration result is non-portable across stores. This method does not warn (the adapter does) but does require the caller to be explicit.

typescript
async *iterateEntitiesByFilter(
    filter: EntityListFilter,
    scope: ScopeFilter,
    opts: {
      batchSize?: number;
      startAfter?: string;
      orderBy: EntityOrderBy | EntityOrderBy[];
    },
  ): AsyncIterable&lt;IEntity[]&gt;

Parameters:

  • filter: EntityListFilter
  • scope: ScopeFilter
  • opts: { batchSize?: number | undefined; startAfter?: string | undefined; orderBy: EntityOrderBy | EntityOrderBy[]; }

Returns: AsyncIterable&lt;IEntity[]&gt;

iterateFacts()

Generic async iterator over facts matching query. Like iterateEntitiesByFilter, the caller MUST pass orderBy (FactOrderBy accepts observedAt | createdAt | confidence) to ensure deterministic iteration across stores.

typescript
async *iterateFacts(
    query: FactFilter,
    scope: ScopeFilter,
    opts: {
      batchSize?: number;
      startAfter?: string;
      orderBy: FactOrderBy;
    },
  ): AsyncIterable&lt;IFact[]&gt;

Parameters:

  • query: FactFilter
  • scope: ScopeFilter
  • opts: { batchSize?: number | undefined; startAfter?: string | undefined; orderBy: FactOrderBy; }

Returns: AsyncIterable&lt;IFact[]&gt;

getProfile()

Resolve the most-specific profile visible to the caller. Precedence: ownerId match > groupId match > global. First hit wins.

typescript
async getProfile(entityId: EntityId, scope: ScopeFilter): Promise&lt;IFact | null&gt;

Parameters:

  • entityId: string
  • scope: ScopeFilter

Returns: Promise&lt;IFact | null&gt;

traverse()

typescript
async traverse(
    entityId: EntityId,
    opts: TraversalOptions,
    scope: ScopeFilter,
  ): Promise&lt;Neighborhood&gt;

Parameters:

  • entityId: string
  • opts: TraversalOptions
  • scope: ScopeFilter

Returns: Promise&lt;Neighborhood&gt;

embedQuery()

Embed a query string once so the resulting vector can be reused across multiple semanticSearch / findSimilarOpenTasks calls with different filters. Avoids re-embedding the same query in fan-out workloads (multi-predicate searches, RAG with per-tenant filters, etc.).

Throws SemanticSearchUnavailableError when no embedder is configured — mirroring semanticSearch's error contract so callers can rely on embedQuery succeeding wherever semanticSearch(string, ...) would.

typescript
async embedQuery(query: string): Promise&lt;number[]&gt;

Parameters:

  • query: string

Returns: Promise&lt;number[]&gt;

semanticSearch()

Semantic kNN over facts. Accepts either:

  • string — embeds internally (one round-trip per call), OR
  • number[] — a pre-computed vector from embedQuery, reused across fan-out calls so the embed cost is paid once.

The number[] form throws only on the store-capability check; no embedder is required (the vector is already available).

typescript
async semanticSearch(
    queryOrVector: string | number[],
    filter: FactFilter,
    scope: ScopeFilter,
    topK: number = DEFAULT_SEMANTIC_TOP_K,
  ): Promise&lt;Array&lt;{ fact: IFact; score: number }&gt;&gt;

Parameters:

  • queryOrVector: string | number[]
  • filter: FactFilter
  • scope: ScopeFilter
  • topK: number (optional) (default: DEFAULT_SEMANTIC_TOP_K)

Returns: Promise&lt;{ fact: IFact; score: number; }[]&gt;

regenerateProfile()

typescript
async regenerateProfile(
    entityId: EntityId,
    targetScope: ScopeFields,
    _trigger: 'threshold' | 'manual' = 'manual',
  ): Promise&lt;IFact&gt;

Parameters:

  • entityId: string
  • targetScope: ScopeFields
  • _trigger: "manual" | "threshold" (optional) (default: 'manual')

Returns: Promise&lt;IFact&gt;

deriveFactsFor()

typescript
async deriveFactsFor(entityId: EntityId, scope: ScopeFilter): Promise&lt;IFact[]&gt;

Parameters:

  • entityId: string
  • scope: ScopeFilter

Returns: Promise&lt;IFact[]&gt;

createDocument()

Create a new document. When slug is provided, the document carries {kind:'canonical', value:'doc:<slug>'} so subsequent lookups via getDocument(slug) resolve deterministically. When attachTo is set, an idempotent has_document fact is written linking the parent to the new document.

Returns the created entity. Content-embedding refresh is queued asynchronously — read pendingEmbeddings() / flushEmbeddings() to observe.

typescript
async createDocument(input: CreateDocumentInput, scope: ScopeFilter): Promise&lt;Document&gt;

Parameters:

  • input: CreateDocumentInput
  • scope: ScopeFilter

Returns: Promise&lt;Document&gt;

updateDocument()

Update a document — body, role, format, summary, or extra metadata. All fields optional; only provided keys are touched (shallow overwrite over metadata). Queues a content-embedding refresh if body changed (gated by metadataDeepEqual short-circuit in applyMetadataMerge).

idOrSlug accepts either a raw entity id or a bare slug (the doc: prefix is added automatically when the value isn't recognized as an id).

typescript
async updateDocument(
    idOrSlug: string,
    patch: UpdateDocumentInput,
    scope: ScopeFilter,
  ): Promise&lt;Document&gt;

Parameters:

  • idOrSlug: string
  • patch: UpdateDocumentInput
  • scope: ScopeFilter

Returns: Promise&lt;Document&gt;

getDocument()

Fetch a document by id or slug. Returns the entity verbatim (including metadata.body). Returns null when not found / not visible.

typescript
async getDocument(idOrSlug: string, scope: ScopeFilter): Promise&lt;Document | null&gt;

Parameters:

  • idOrSlug: string
  • scope: ScopeFilter

Returns: Promise&lt;Document | null&gt;

attachDocument()

Attach a document to a parent entity via the canonical has_document predicate. Idempotent — a no-op when an identical non-archived fact already exists in the caller's scope.

typescript
async attachDocument(parentId: EntityId, docIdOrSlug: string, scope: ScopeFilter): Promise&lt;void&gt;

Parameters:

  • parentId: string
  • docIdOrSlug: string
  • scope: ScopeFilter

Returns: Promise&lt;void&gt;

detachDocument()

Remove a has_document attachment between a parent entity and a document. Archives EVERY matching non-archived fact in scope (idempotent), so duplicate attachments — should they exist due to race conditions — are cleaned up in one call.

Returns {archived, skippedDueToPermissions} so callers can distinguish "no matching facts" (both zero) from "had matches but couldn't write any" (archived=0, skipped>0).

typescript
async detachDocument(
    parentId: EntityId,
    docIdOrSlug: string,
    scope: ScopeFilter,
  ): Promise&lt;DetachDocumentResult&gt;

Parameters:

  • parentId: string
  • docIdOrSlug: string
  • scope: ScopeFilter

Returns: Promise&lt;DetachDocumentResult&gt;

listDocuments()

List documents — optionally narrowed by attachedTo, role, ownerId. By default the response strips metadata.body (listing pages can be large); pass includeBody: true to keep it.

typescript
async listDocuments(filter: ListDocumentsFilter, scope: ScopeFilter): Promise&lt;Document[]&gt;

Parameters:

  • filter: ListDocumentsFilter
  • scope: ScopeFilter

Returns: Promise&lt;Document[]&gt;

searchDocuments()

Search documents — semantic mode uses contentEmbedding (requires an embedder); keyword mode runs a case-insensitive substring match over metadata.body and displayName against a page of candidates. Both modes honor attachedTo / role filters and clamp limit to [1, 50].

Score semantics: semantic returns 0..1 cosine similarity from the underlying semanticSearchEntities; keyword returns a coarse 0..1 hit score (1.0 for displayName match, 0.5 for body-only).

typescript
async searchDocuments(input: SearchDocumentsInput, scope: ScopeFilter): Promise&lt;DocumentSearchHit[]&gt;

Parameters:

  • input: SearchDocumentsInput
  • scope: ScopeFilter

Returns: Promise&lt;DocumentSearchHit[]&gt;

flushEmbeddings()

typescript
flushEmbeddings(): Promise&lt;void&gt;

Returns: Promise&lt;void&gt;

pendingEmbeddings()

typescript
pendingEmbeddings(): number

Returns: number

backfillContentEmbeddings()

Backfill contentEmbedding / contentEmbeddingText for entities whose stored embedding doesn't match what the current composer would produce.

Run-once migration helper. Use cases:

  • Upgrading from a release where content embedding was document-only — backfill makes every task / event / person / etc. searchable semantically without waiting for each entity's next mutation.
  • After overriding a composer in MemorySystemConfig.entityContentComposers so the new composer's output applies to historical data immediately.
  • After running mergeEntities / archiveEntity campaigns where cascading content refresh would be desirable.

Idempotent. Skips entities whose contentEmbeddingText already matches the composer output (no embed cost). Safe to re-run.

Resumable. No transactional guarantees. Interrupting mid-run leaves a partially-converged population; re-running converges the remainder.

Scoping. Bounded by scope (same visibility rules as every other read). Multi-tenant hosts iterate over scopes and call once per scope.

Concurrency. Each enqueue goes through the standard EmbeddingQueue with bounded concurrency (config.embeddingQueue.concurrency). Caller should await memorySystem.flushEmbeddings() after the helper returns to wait for all in-flight embeds.

typescript
async backfillContentEmbeddings(
    scope: ScopeFilter,
    opts?: {
      /** Narrow to specific entity types. Empty/omitted = all types. */
      types?: string[];
      /** Page size for the streaming scan. Default 500, max 1000. */
      batchSize?: number;
      /** Progress callback invoked after each page. */
      onProgress?: (scanned: number, queued: number) =&gt; void;
    },
  ): Promise&lt;{ scanned: number; queued: number; skipped: number }&gt;

Parameters:

  • scope: ScopeFilter
  • opts: { types?: string[] | undefined; batchSize?: number | undefined; onProgress?: ((scanned: number, queued: number) =&gt; void) | undefined; } | undefined (optional)

Returns: Promise&lt;{ scanned: number; queued: number; skipped: number; }&gt;

backfillFactEmbeddings()

Backfill embedding / summaryForEmbedding for facts. Sister method to backfillContentEmbeddings — same idempotency, same scoping rules. Run once when upgrading to a release that removes the 80-char threshold gate, so short atomic facts (e.g. (Sarah, works_at, Acme)) become searchable semantically without waiting for each fact's next mutation.

typescript
async backfillFactEmbeddings(
    scope: ScopeFilter,
    opts?: {
      /** Narrow to specific fact predicates. Empty/omitted = all predicates. */
      predicates?: string[];
      /** Narrow to fact kind. Empty/omitted = both atomic + document. */
      kind?: IFact['kind'];
      /** Page size for the streaming scan. Default 500, max 1000. */
      batchSize?: number;
      /** Progress callback invoked after each page. */
      onProgress?: (scanned: number, queued: number) =&gt; void;
    },
  ): Promise&lt;{ scanned: number; queued: number; skipped: number }&gt;

Parameters:

  • scope: ScopeFilter
  • opts: { predicates?: string[] | undefined; kind?: FactKind | undefined; batchSize?: number | undefined; onProgress?: ((scanned: number, queued: number) =&gt; void) | undefined; } | undefined (optional)

Returns: Promise&lt;{ scanned: number; queued: number; skipped: number; }&gt;

destroy()

typescript
destroy(): void

Returns: void

shutdown()

typescript
async shutdown(): Promise&lt;void&gt;

Returns: Promise&lt;void&gt;


MemoryWritePluginNextGen class

📍 src/core/context-nextgen/plugins/MemoryWritePluginNextGen.ts:258

Constructor

constructor

typescript
constructor(config: MemoryWritePluginConfig)

Parameters:

  • config: MemoryWritePluginConfig
Methods

getInstructions()

typescript
getInstructions(): string | null

Returns: string | null

getContent()

typescript
async getContent(): Promise&lt;string | null&gt;

Returns: Promise&lt;string | null&gt;

getContents()

typescript
getContents(): unknown

Returns: unknown

getTokenSize()

typescript
getTokenSize(): number

Returns: number

getInstructionsTokenSize()

typescript
getInstructionsTokenSize(): number

Returns: number

isCompactable()

typescript
isCompactable(): boolean

Returns: boolean

compact()

typescript
async compact(_targetTokensToFree: number): Promise&lt;number&gt;

Parameters:

  • _targetTokensToFree: number

Returns: Promise&lt;number&gt;

getTools()

typescript
getTools(): ToolFunction[]

Returns: ToolFunction&lt;any, any&gt;[]

destroy()

typescript
destroy(): void

Returns: void

getState()

typescript
getState(): unknown

Returns: unknown

restoreState()

typescript
restoreState(_state: unknown): void

Parameters:

  • _state: unknown

Returns: void

Properties
Property Type Description
name name: "memory_write" -

ModelBudgetExceededError class

📍 src/core/model-execution/ModelTask.ts:9

Constructor

constructor

typescript
constructor(public readonly limit: string)

Parameters:

  • limit: string

ModelTask class

📍 src/core/model-execution/ModelTask.ts:123

In-process shared admission, reservations and usage. Never stores prompts or credentials.

Constructor

constructor

typescript
constructor(options: { id?: string; limits?: ModelTaskLimits; signal?: AbortSignal } = {})

Parameters:

  • options: { id?: string | undefined; limits?: ModelTaskLimits | undefined; signal?: AbortSignal | undefined; } (optional) (default: {})
Methods

cancel()

typescript
cancel(reason: unknown = new DOMException('Model task cancelled', 'AbortError')): void

Parameters:

  • reason: unknown (optional) (default: new DOMException('Model task cancelled', 'AbortError'))

Returns: void

execute()

Execute one logical call; installed SDK adapters admit every physical retry separately.

typescript
async execute&lt;T&gt;(descriptor: ModelCallDescriptor, operation: (signal: AbortSignal) =&gt; Promise&lt;T&gt;, options: {
    signal?: AbortSignal; transport?: boolean; usage?: (result: T) =&gt; TokenUsage | undefined;
    /** @internal Latest terminal usage survives an iterator failure or cancellation. */
    observedUsage?: () =&gt; TokenUsage | undefined;
    /** @internal Final synchronous native request/authority guard, including retries. */
    beforeDispatch?: () =&gt; void;
    /** @internal Observed provider/transport dispatch after successful reservation. */
    onDispatch?: () =&gt; void;
  } = {}): Promise&lt;{ result: T; invocationId: string }&gt;

Parameters:

  • descriptor: ModelCallDescriptor
  • operation: (signal: AbortSignal) =&gt; Promise&lt;T&gt;
  • options: { signal?: AbortSignal | undefined; transport?: boolean | undefined; usage?: ((result: T) =&gt; TokenUsage | undefined) | undefined; observedUsage?: (() =&gt; TokenUsage | undefined) | undefined; beforeDispatch?: (() =&gt; void) | undefined; onDispatch?: (() =&gt; void) | undefined; } (optional) (default: {})

Returns: Promise&lt;{ result: T; invocationId: string; }&gt;

iterate()

Streaming variant with pull-based backpressure and invocation-local transport tracking.

typescript
async *iterate&lt;T&gt;(descriptor: ModelCallDescriptor, factory: (signal: AbortSignal) =&gt; AsyncIterable&lt;T&gt;, options: {
    signal?: AbortSignal; transport?: boolean; usage?: (event: T) =&gt; TokenUsage | undefined;
    beforeDispatch?: () =&gt; void;
    /** @internal Observed provider/transport dispatch after successful reservation. */
    onDispatch?: () =&gt; void;
  } = {}): AsyncIterableIterator&lt;T&gt;

Parameters:

  • descriptor: ModelCallDescriptor
  • factory: (signal: AbortSignal) =&gt; AsyncIterable&lt;T&gt;
  • options: { signal?: AbortSignal | undefined; transport?: boolean | undefined; usage?: ((event: T) =&gt; TokenUsage | undefined) | undefined; beforeDispatch?: (() =&gt; void) | undefined; onDispatch?: (() =&gt; void) | undefined; } (optional) (default: {})

Returns: AsyncIterableIterator&lt;T&gt;

recordExternal()

Host-reported usage is idempotent by ID. Conflicting replays fail explicitly.

typescript
recordExternal(report: { id: string; purpose: string; connector: string; model: string; parentInvocationId?: string; usage: TokenUsage | null;
    status?: 'succeeded' | 'failed' | 'cancelled'; }): void

Parameters:

  • report: { id: string; purpose: string; connector: string; model: string; parentInvocationId?: string | undefined; usage: TokenUsage | null; status?: "failed" | "cancelled" | "succeeded" | undefined; }

Returns: void

recordValidation()

Attach a host validation result without recounting the model usage.

typescript
recordValidation(invocationId: string, valid: boolean): void

Parameters:

  • invocationId: string
  • valid: boolean

Returns: void

snapshot()

typescript
snapshot(): ModelTaskSnapshot

Returns: ModelTaskSnapshot

destroy()

typescript
destroy(): void

Returns: void

Properties
Property Type Description
id id: string -
limits limits: Readonly&lt;ModelTaskLimits&gt; -

MongoMemoryAdapter class

📍 src/memory/adapters/mongo/MongoMemoryAdapter.ts:214

Constructor

constructor

typescript
constructor(opts: MongoMemoryAdapterOptions)

Parameters:

  • opts: MongoMemoryAdapterOptions
Methods

ensureIndexes()

H7: ensure the recommended indexes exist. Idempotent — Mongo's createIndex is a no-op when the index is already present with matching specification. Callers integrate this into their migration system; the adapter does NOT call it automatically (indexes are the client app's responsibility, not a library concern).

Invokes the shared ensureIndexes(...) function against this adapter's collections. See indexes.ts for the index list and why each exists.

typescript
async ensureIndexes(): Promise&lt;void&gt;

Returns: Promise&lt;void&gt;

createEntity()

typescript
async createEntity(input: NewEntity): Promise&lt;IEntity&gt;

Parameters:

  • input: NewEntity

Returns: Promise&lt;IEntity&gt;

createEntities()

typescript
async createEntities(inputs: NewEntity[]): Promise&lt;IEntity[]&gt;

Parameters:

  • inputs: NewEntity[]

Returns: Promise&lt;IEntity[]&gt;

updateEntity()

typescript
async updateEntity(entity: IEntity): Promise&lt;void&gt;

Parameters:

  • entity: IEntity

Returns: Promise&lt;void&gt;

getEntity()

typescript
async getEntity(id: EntityId, scope: ScopeFilter): Promise&lt;IEntity | null&gt;

Parameters:

  • id: string
  • scope: ScopeFilter

Returns: Promise&lt;IEntity | null&gt;

getEntities()

typescript
async getEntities(ids: EntityId[], scope: ScopeFilter): Promise&lt;Array&lt;IEntity | null&gt;&gt;

Parameters:

  • ids: string[]
  • scope: ScopeFilter

Returns: Promise&lt;(IEntity | null)[]&gt;

findEntitiesByIdentifier()

typescript
async findEntitiesByIdentifier(
    kind: string,
    value: string,
    scope: ScopeFilter,
  ): Promise&lt;IEntity[]&gt;

Parameters:

  • kind: string
  • value: string
  • scope: ScopeFilter

Returns: Promise&lt;IEntity[]&gt;

atomicCreateOrFindByNormalizedName()

Atomic find-or-create by (type, normalizedDisplayName, scope). See the interface contract.

Implementation: optimistic find-then-insert with duplicate-key recovery. Cross-process atomicity depends on the unique partial index on {groupId, ownerId, type, normalizedDisplayName} being installed — without it, a racing insert succeeds and produces duplicates. The library exports ensureNormalizedNameUniqueIndex for hosts to install in their migration (not auto-installed because adding a unique index to a collection containing duplicates fails).

typescript
async atomicCreateOrFindByNormalizedName(
    input: NewEntity,
    scope: ScopeFilter,
  ): Promise&lt;{ entity: IEntity; created: boolean }&gt;

Parameters:

  • input: NewEntity
  • scope: ScopeFilter

Returns: Promise&lt;{ entity: IEntity; created: boolean; }&gt;

findEntitiesByNormalizedName()

typescript
async findEntitiesByNormalizedName(
    type: string | undefined,
    normalized: string,
    scope: ScopeFilter,
    opts?: { matchAliases?: boolean; limit?: number },
  ): Promise&lt;IEntity[]&gt;

Parameters:

  • type: string | undefined
  • normalized: string
  • scope: ScopeFilter
  • opts: { matchAliases?: boolean | undefined; limit?: number | undefined; } | undefined (optional)

Returns: Promise&lt;IEntity[]&gt;

searchEntities()

typescript
async searchEntities(
    query: string,
    opts: EntitySearchOptions,
    scope: ScopeFilter,
  ): Promise&lt;Page&lt;IEntity&gt;&gt;

Parameters:

  • query: string
  • opts: EntitySearchOptions
  • scope: ScopeFilter

Returns: Promise&lt;Page&lt;IEntity&gt;&gt;

listEntities()

typescript
async listEntities(
    filter: EntityListFilter,
    opts: ListOptions,
    scope: ScopeFilter,
  ): Promise&lt;Page&lt;IEntity&gt;&gt;

Parameters:

  • filter: EntityListFilter
  • opts: ListOptions
  • scope: ScopeFilter

Returns: Promise&lt;Page&lt;IEntity&gt;&gt;

archiveEntity()

typescript
async archiveEntity(id: EntityId, scope: ScopeFilter): Promise&lt;void&gt;

Parameters:

  • id: string
  • scope: ScopeFilter

Returns: Promise&lt;void&gt;

deleteEntity()

typescript
async deleteEntity(id: EntityId, scope: ScopeFilter): Promise&lt;void&gt;

Parameters:

  • id: string
  • scope: ScopeFilter

Returns: Promise&lt;void&gt;

createFact()

typescript
async createFact(input: NewFact): Promise&lt;IFact&gt;

Parameters:

  • input: NewFact

Returns: Promise&lt;IFact&gt;

createFacts()

typescript
async createFacts(inputs: NewFact[]): Promise&lt;IFact[]&gt;

Parameters:

  • inputs: NewFact[]

Returns: Promise&lt;IFact[]&gt;

getFact()

typescript
async getFact(id: FactId, scope: ScopeFilter): Promise&lt;IFact | null&gt;

Parameters:

  • id: string
  • scope: ScopeFilter

Returns: Promise&lt;IFact | null&gt;

findFacts()

typescript
async findFacts(
    filter: FactFilter,
    opts: FactQueryOptions,
    scope: ScopeFilter,
  ): Promise&lt;Page&lt;IFact&gt;&gt;

Parameters:

  • filter: FactFilter
  • opts: FactQueryOptions
  • scope: ScopeFilter

Returns: Promise&lt;Page&lt;IFact&gt;&gt;

updateFact()

typescript
async updateFact(id: FactId, patch: Partial&lt;IFact&gt;, scope: ScopeFilter): Promise&lt;void&gt;

Parameters:

  • id: string
  • patch: Partial&lt;IFact&gt;
  • scope: ScopeFilter

Returns: Promise&lt;void&gt;

rewriteEntityPrincipal()

Rewrite entity:<from> → entity:<to> access grants across entities, facts, and (if present) the facts archive. Bulk identity fix used by mergeEntities; scoped to the caller's tenant for safety, no per-record write check, no version bump (these are access-token rewrites, not semantic mutations). See IMemoryStore.rewriteEntityPrincipal.

typescript
async rewriteEntityPrincipal(
    fromEntityId: EntityId,
    toEntityId: EntityId,
    scope: ScopeFilter,
  ): Promise&lt;void&gt;

Parameters:

  • fromEntityId: string
  • toEntityId: string
  • scope: ScopeFilter

Returns: Promise&lt;void&gt;

countFacts()

typescript
async countFacts(filter: FactFilter, scope: ScopeFilter): Promise&lt;number&gt;

Parameters:

  • filter: FactFilter
  • scope: ScopeFilter

Returns: Promise&lt;number&gt;

traverse()

typescript
async traverse(
    startId: EntityId,
    opts: TraversalOptions,
    scope: ScopeFilter,
  ): Promise&lt;Neighborhood&gt;

Parameters:

  • startId: string
  • opts: TraversalOptions
  • scope: ScopeFilter

Returns: Promise&lt;Neighborhood&gt;

semanticSearch()

typescript
async semanticSearch(
    queryVector: number[],
    filter: FactFilter,
    opts: SemanticSearchOptions,
    scope: ScopeFilter,
  ): Promise&lt;Array&lt;{ fact: IFact; score: number }&gt;&gt;

Parameters:

  • queryVector: number[]
  • filter: FactFilter
  • opts: SemanticSearchOptions
  • scope: ScopeFilter

Returns: Promise&lt;{ fact: IFact; score: number; }[]&gt;

semanticSearchEntities()

typescript
async semanticSearchEntities(
    queryVector: number[],
    filter: EntitySemanticSearchFilter,
    opts: SemanticSearchOptions & { minScore?: number; embeddingField?: EntityEmbeddingField },
    scope: ScopeFilter,
  ): Promise&lt;Array&lt;{ entity: IEntity; score: number }&gt;&gt;

Parameters:

  • queryVector: number[]
  • filter: EntitySemanticSearchFilter
  • opts: SemanticSearchOptions & { minScore?: number | undefined; embeddingField?: EntityEmbeddingField | undefined; }
  • scope: ScopeFilter

Returns: Promise&lt;{ entity: IEntity; score: number; }[]&gt;

ensureVectorSearchIndexes()

Create the Atlas Vector Search indexes for facts and/or entities if they aren't already present. Separate from ensureIndexes() because vector indexes need runtime parameters (dimensions, similarity) and take longer to build — callers shouldn't pay that cost unless they use semantic search.

Requires:

  • Atlas Server v6.0.11+ and mongodb node driver v6.6+ (the driver exposes createSearchIndex / listSearchIndexes).
  • The IMongoCollectionLike wrapper must implement createSearchIndex (both bundled wrappers do; custom wrappers may need updating).

Idempotent — re-running is safe: existing indexes with the configured name are detected via listSearchIndexes and skipped. Concurrent-create races (two migrations running at once) are absorbed: if createSearchIndex fails but the index is present on re-check, we treat it as "another process won" and continue.

Fire-and-forget: returns as soon as Atlas accepts the create request. The index builds asynchronously on Atlas (30–60s typical). Runs during startup migrations, so the index is ready well before real traffic. The typical first query lands minutes after the migration, not seconds — no readiness wait needed.

Index names come from the adapter's config by default. If the adapter was constructed with vectorIndexName: 'custom_facts' (or entityVectorIndexName: 'custom_entities'), this helper creates indexes under those names automatically. Callers can still override via factsIndexName / entitiesIndexName, but the default is the safe choice — runtime queries and helper output always agree.

Filter fields are auto-declared in the index definition. Atlas $vectorSearch silently ignores filter clauses whose paths aren't declared as type: 'filter' in the index. We declare scope + archived

  • discriminator paths for both collections so scope enforcement works on the $vectorSearch fast path. See the field lists in FACTS_FILTER_PATHS / ENTITIES_FILTER_PATHS below — manual Atlas-UI creators must match or the filter is silently ignored (scope bypass).
typescript
async ensureVectorSearchIndexes(opts: {
    /** Embedding dimensionality — MUST match your embedder. Must be a positive integer. */
    dimensions: number;
    /** Default: 'cosine'. Match the similarity your embedder was trained for. */
    similarity?: 'cosine' | 'dotProduct' | 'euclidean';
    /**
     * Atlas index name for facts. Default: the adapter's own `vectorIndexName`
     * option, or `'facts_vector'` when that's also unset. Pass `null` to skip
     * the facts index entirely.
     */
    factsIndexName?: string | null;
    /**
     * Atlas index name for entities (identityEmbedding). Default: the
     * adapter's own `entityVectorIndexName` option, or `'entities_vector'`
     * when unset. Pass `null` to skip.
     */
    entitiesIndexName?: string | null;
    /**
     * Atlas index name for entity content (contentEmbedding) — used by
     * document semantic search. **Opt-in.** Default: the adapter's own
     * `entityContentVectorIndexName` option, or **`null` (skip)** when that's
     * also unset. Hosts that use documents should either set the adapter's
     * `entityContentVectorIndexName` (so the runtime path and this helper
     * agree on the name) or pass `entitiesContentIndexName` explicitly here.
     *
     * Default-skip is deliberate: adding a third Atlas index automatically
     * on `ensureVectorSearchIndexes()` would silently bill existing
     * deployments that aren't using documents.
     */
    entitiesContentIndexName?: string | null;
  }): Promise&lt;void&gt;

Parameters:

  • opts: { dimensions: number; similarity?: "cosine" | "dotProduct" | "euclidean" | undefined; factsIndexName?: string | null | undefined; entitiesIndexName?: string | null | undefined; entitiesContentIndexName?: string | null | undefined; }

Returns: Promise&lt;void&gt;

destroy()

typescript
destroy(): void

Returns: void

shutdown()

typescript
async shutdown(): Promise&lt;void&gt;

Returns: Promise&lt;void&gt;


ParallelTasksError class

📍 src/domain/errors/AIErrors.ts:339

Error thrown when multiple tasks fail in parallel execution (fail-all mode)

Constructor

constructor

typescript
constructor(
    /** Array of task failures */
    public readonly failures: TaskFailure[]
  )

Parameters:

  • failures: TaskFailure[]
Methods

getErrors()

Get all failure errors

typescript
getErrors(): Error[]

Returns: Error[]

getFailedTaskIds()

Get failed task IDs

typescript
getFailedTaskIds(): string[]

Returns: string[]


PlanningAgent class

📍 src/capabilities/taskAgent/PlanningAgent.ts:90

PlanningAgent class

Static Methods

static create()

Create a new PlanningAgent

typescript
static create(config: PlanningAgentConfig): PlanningAgent

Parameters:

  • config: PlanningAgentConfig

Returns: PlanningAgent

Methods

generatePlan()

Generate a plan from a goal

typescript
async generatePlan(input: {
    goal: string;
    context?: string;
    constraints?: string[];
  }): Promise&lt;GeneratedPlan&gt;

Parameters:

  • input: { goal: string; context?: string | undefined; constraints?: string[] | undefined; }

Returns: Promise&lt;GeneratedPlan&gt;

refinePlan()

Validate and refine an existing plan

typescript
async refinePlan(plan: Plan, feedback: string): Promise&lt;GeneratedPlan&gt;

Parameters:

  • plan: Plan
  • feedback: string

Returns: Promise&lt;GeneratedPlan&gt;

getCurrentTasks()

Get current tasks (for tool access)

typescript
getCurrentTasks(): TaskInput[]

Returns: TaskInput[]

addTask()

Add task (called by planning tools)

typescript
addTask(task: TaskInput): void

Parameters:

  • task: TaskInput

Returns: void

updateTask()

Update task (called by planning tools)

typescript
updateTask(name: string, updates: Partial&lt;TaskInput&gt;): void

Parameters:

  • name: string
  • updates: Partial&lt;TaskInput&gt;

Returns: void

removeTask()

Remove task (called by planning tools)

typescript
removeTask(name: string): void

Parameters:

  • name: string

Returns: void

finalizePlanning()

Mark planning as complete

typescript
finalizePlanning(): void

Returns: void


TaskStatePluginNextGen class

📍 src/core/context-nextgen/plugins/TaskStatePluginNextGen.ts:129

Host-controlled semantic notebook and protected prompt view; no model mutation tools.

Constructor

constructor

typescript
constructor(config: TaskStatePluginConfig)

Parameters:

  • config: TaskStatePluginConfig
Methods

emptyState()

typescript
emptyState(): TaskStateSnapshot

Returns: TaskStateSnapshot

updateHost()

Host-only atomic update. The model has no tool exposing this method.

typescript
updateHost(delta: TaskStateHostDelta, expectedRevision: number): TaskStateSnapshot

Parameters:

  • delta: TaskStateHostDelta
  • expectedRevision: number

Returns: TaskStateSnapshot

propose()

Host submits model output as unconfirmed data, with source and uncertainty.

typescript
propose(notes: TaskStateNoteInput[], expectedRevision: number): TaskStateSnapshot

Parameters:

  • notes: TaskStateNoteInput[]
  • expectedRevision: number

Returns: TaskStateSnapshot

assume()

typescript
assume(notes: TaskStateNoteInput[], expectedRevision: number): TaskStateSnapshot

Parameters:

  • notes: TaskStateNoteInput[]
  • expectedRevision: number

Returns: TaskStateSnapshot

recordAction()

Host supplies an actual ToolManager outcome; observation recording never reexecutes an action.

typescript
recordAction(observed: ToolExecutionOutcome, expectedRevision: number): TaskStateSnapshot

Parameters:

  • observed: ToolExecutionOutcome
  • expectedRevision: number

Returns: TaskStateSnapshot

confirmAction()

Explicit host-defined completion condition; model text/tool success cannot invoke it.

typescript
confirmAction(executionId: string, status: TaskStatus, proof: TaskStateSource, expectedRevision: number): TaskStateSnapshot

Parameters:

  • executionId: string
  • status: TaskStatus
  • proof: TaskStateSource
  • expectedRevision: number

Returns: TaskStateSnapshot

syncLifecycle()

Snapshot an existing Task/routine authority; this view does not drive its lifecycle.

typescript
syncLifecycle(view: TaskStateLifecycleView, expectedRevision: number): TaskStateSnapshot

Parameters:

  • view: TaskStateLifecycleView
  • expectedRevision: number

Returns: TaskStateSnapshot

refreshMemoryTask()

Read linked task metadata through existing MemorySystem authorization. Transition it through MemorySystem directly.

typescript
async refreshMemoryTask(memory: Pick&lt;MemorySystem, 'getEntity'&gt;, scope: ScopeFilter, expectedRevision: number, signal?: AbortSignal): Promise&lt;TaskStateSnapshot&gt;

Parameters:

  • memory: Pick&lt;MemorySystem, "getEntity"&gt;
  • scope: ScopeFilter
  • expectedRevision: number
  • signal: AbortSignal | undefined (optional)

Returns: Promise&lt;TaskStateSnapshot&gt;

pruneResolved()

Explicit host pruning only; unresolved constraints and unconfirmed actions cannot be evicted.

typescript
pruneResolved(noteIds: string[], executionIds: string[], expectedRevision: number): TaskStateSnapshot

Parameters:

  • noteIds: string[]
  • executionIds: string[]
  • expectedRevision: number

Returns: TaskStateSnapshot

getInstructions()

typescript
getInstructions(): string

Returns: string

getContent()

typescript
async getContent(): Promise&lt;string&gt;

Returns: Promise&lt;string&gt;

getContents()

typescript
getContents(): TaskStateSnapshot

Returns: TaskStateSnapshot

getState()

typescript
getState(): TaskStateSnapshot

Returns: TaskStateSnapshot

validateState()

Pure bounded preflight; future versions/foreign task scopes are rejected before context mutation.

typescript
validateState(value: unknown): TaskStateSnapshot

Parameters:

  • value: unknown

Returns: TaskStateSnapshot

restoreState()

typescript
restoreState(value: unknown): void

Parameters:

  • value: unknown

Returns: void

destroy()

typescript
destroy(): void

Returns: void

Properties
Property Type Description
name name: "task_state" -
scope scope: Readonly&lt;EvidenceScope&gt; -
taskId taskId: string -

TaskTimeoutError class

📍 src/domain/errors/AIErrors.ts:292

Error thrown when a task execution times out

Constructor

constructor

typescript
constructor(
    public readonly taskId: string,
    public readonly taskName: string,
    public readonly timeoutMs: number
  )

Parameters:

  • taskId: string
  • taskName: string
  • timeoutMs: number

TaskValidationError class

📍 src/domain/errors/AIErrors.ts:311

Error thrown when task completion validation fails

Constructor

constructor

typescript
constructor(
    public readonly taskId: string,
    public readonly taskName: string,
    public readonly reason: string
  )

Parameters:

  • taskId: string
  • taskName: string
  • reason: string

WorkingMemory class

📍 src/capabilities/taskAgent/WorkingMemory.ts:103

WorkingMemory manages the agent's indexed working memory.

Features:

  • Store/retrieve with descriptions for index
  • Scoped memory (simple or task-aware)
  • Priority-based eviction (respects pinned, priority, then LRU)
  • Pluggable priority calculation via PriorityCalculator strategy
  • Task completion detection and stale entry notification
  • Event emission for monitoring
Constructor

constructor

Create a WorkingMemory instance

typescript
constructor(
    storage: IMemoryStorage,
    config: WorkingMemoryConfig = DEFAULT_MEMORY_CONFIG,
    priorityCalculator: PriorityCalculator = staticPriorityCalculator
  )

Parameters:

  • storage: IMemoryStorage
  • config: WorkingMemoryConfig (optional) (default: DEFAULT_MEMORY_CONFIG)
  • priorityCalculator: PriorityCalculator (optional) (default: staticPriorityCalculator)
Methods

setPriorityCalculator()

Set the priority calculator (for switching strategies at runtime)

typescript
setPriorityCalculator(calculator: PriorityCalculator): void

Parameters:

  • calculator: PriorityCalculator

Returns: void

setPriorityContext()

Update priority context (e.g., task states for TaskAgent)

typescript
setPriorityContext(context: PriorityContext): void

Parameters:

  • context: PriorityContext

Returns: void

getPriorityContext()

Get the current priority context

typescript
getPriorityContext(): PriorityContext

Returns: PriorityContext

store()

Store a value in working memory

typescript
async store(
    key: string,
    description: string,
    value: unknown,
    options?: {
      scope?: MemoryScope;
      priority?: MemoryPriority;
      pinned?: boolean;
    }
  ): Promise&lt;void&gt;

Parameters:

  • key: string
  • description: string
  • value: unknown
  • options: { scope?: MemoryScope | undefined; priority?: MemoryPriority | undefined; pinned?: boolean | undefined; } | undefined (optional)

Returns: Promise&lt;void&gt;

getMaxIndexEntries()

Get the configured max index entries limit

typescript
getMaxIndexEntries(): number | undefined

Returns: number | undefined

storeForTasks()

Store a value scoped to specific tasks Convenience method for task-aware memory

typescript
async storeForTasks(
    key: string,
    description: string,
    value: unknown,
    taskIds: string[],
    options?: { priority?: MemoryPriority; pinned?: boolean }
  ): Promise&lt;void&gt;

Parameters:

  • key: string
  • description: string
  • value: unknown
  • taskIds: string[]
  • options: { priority?: MemoryPriority | undefined; pinned?: boolean | undefined; } | undefined (optional)

Returns: Promise&lt;void&gt;

storeForPlan()

Store a value scoped to the entire plan Convenience method for plan-scoped memory

typescript
async storeForPlan(
    key: string,
    description: string,
    value: unknown,
    options?: { priority?: MemoryPriority; pinned?: boolean }
  ): Promise&lt;void&gt;

Parameters:

  • key: string
  • description: string
  • value: unknown
  • options: { priority?: MemoryPriority | undefined; pinned?: boolean | undefined; } | undefined (optional)

Returns: Promise&lt;void&gt;

retrieve()

Retrieve a value from working memory

Note: Access stats update is not strictly atomic. Under very high concurrency, accessCount may be slightly inaccurate. This is acceptable for memory management purposes where exact counts are not critical.

typescript
async retrieve(key: string): Promise&lt;unknown&gt;

Parameters:

  • key: string

Returns: Promise&lt;unknown&gt;

retrieveMany()

Retrieve multiple values

typescript
async retrieveMany(keys: string[]): Promise&lt;Record&lt;string, unknown&gt;&gt;

Parameters:

  • keys: string[]

Returns: Promise&lt;Record&lt;string, unknown&gt;&gt;

delete()

Delete a value from working memory

typescript
async delete(key: string): Promise&lt;void&gt;

Parameters:

  • key: string

Returns: Promise&lt;void&gt;

has()

Check if key exists

typescript
async has(key: string): Promise&lt;boolean&gt;

Parameters:

  • key: string

Returns: Promise&lt;boolean&gt;

persist()

Promote an entry to persistent scope Works with both simple and task-aware scopes

typescript
async persist(key: string): Promise&lt;void&gt;

Parameters:

  • key: string

Returns: Promise&lt;void&gt;

pin()

Pin an entry (never evicted)

typescript
async pin(key: string): Promise&lt;void&gt;

Parameters:

  • key: string

Returns: Promise&lt;void&gt;

unpin()

Unpin an entry

typescript
async unpin(key: string, newPriority: MemoryPriority = 'normal'): Promise&lt;void&gt;

Parameters:

  • key: string
  • newPriority: MemoryPriority (optional) (default: 'normal')

Returns: Promise&lt;void&gt;

setPriority()

Set the base priority of an entry

typescript
async setPriority(key: string, priority: MemoryPriority): Promise&lt;void&gt;

Parameters:

  • key: string
  • priority: MemoryPriority

Returns: Promise&lt;void&gt;

updateScope()

Update the scope of an entry without re-storing the value

typescript
async updateScope(key: string, scope: MemoryScope): Promise&lt;void&gt;

Parameters:

  • key: string
  • scope: MemoryScope

Returns: Promise&lt;void&gt;

addTasksToScope()

Add task IDs to an existing task-scoped entry If entry is not task-scoped, converts it to task-scoped

typescript
async addTasksToScope(key: string, taskIds: string[]): Promise&lt;void&gt;

Parameters:

  • key: string
  • taskIds: string[]

Returns: Promise&lt;void&gt;

clearScope()

Clear all entries of a specific scope

typescript
async clearScope(scope: MemoryScope): Promise&lt;void&gt;

Parameters:

  • scope: MemoryScope

Returns: Promise&lt;void&gt;

clear()

Clear all entries

typescript
async clear(): Promise&lt;void&gt;

Returns: Promise&lt;void&gt;

getIndex()

Get memory index with computed effective priorities Respects maxIndexEntries limit for context display

typescript
async getIndex(): Promise&lt;MemoryIndex&gt;

Returns: Promise&lt;MemoryIndex&gt;

formatIndex()

Format index for context injection

typescript
async formatIndex(): Promise&lt;string&gt;

Returns: Promise&lt;string&gt;

evict()

Evict entries using specified strategy

Eviction order:

  1. Never evict pinned entries
  2. Evict low priority first, then normal, then high (never critical)
  3. Within same priority, use strategy (LRU or largest size)
typescript
async evict(count: number, strategy: EvictionStrategy = 'lru'): Promise&lt;string[]&gt;

Parameters:

  • count: number
  • strategy: EvictionStrategy (optional) (default: 'lru')

Returns: Promise&lt;string[]&gt;

evictLRU()

Evict entries using priority-aware LRU algorithm

typescript
async evictLRU(count: number): Promise&lt;string[]&gt;

Parameters:

  • count: number

Returns: Promise&lt;string[]&gt;

evictBySize()

Evict largest entries first (priority-aware)

typescript
async evictBySize(count: number): Promise&lt;string[]&gt;

Parameters:

  • count: number

Returns: Promise&lt;string[]&gt;

onTaskComplete()

Handle task completion - detect and notify about stale entries

Call this when a task completes to:

  1. Update priority context with new task state
  2. Detect entries that became stale
  3. Emit event to notify LLM about stale entries
typescript
async onTaskComplete(
    taskId: string,
    taskStates: Map&lt;string, TaskStatusForMemory&gt;
  ): Promise&lt;StaleEntryInfo[]&gt;

Parameters:

  • taskId: string
  • taskStates: Map&lt;string, TaskStatusForMemory&gt;

Returns: Promise&lt;StaleEntryInfo[]&gt;

evictCompletedTaskEntries()

Evict entries for completed tasks

Removes entries that were scoped only to completed tasks. Use after onTaskComplete() if you want automatic cleanup.

typescript
async evictCompletedTaskEntries(
    taskStates: Map&lt;string, TaskStatusForMemory&gt;
  ): Promise&lt;string[]&gt;

Parameters:

  • taskStates: Map&lt;string, TaskStatusForMemory&gt;

Returns: Promise&lt;string[]&gt;

getAccess()

Get limited memory access for tools

This provides a simplified interface for tools to interact with memory without exposing the full WorkingMemory API.

typescript
getAccess(): WorkingMemoryAccess

Returns: WorkingMemoryAccess

storeRaw()

Store raw data (low priority, first to be evicted)

Use this for original/unprocessed data that should be summarized. Raw data is automatically evicted first when memory pressure is high.

typescript
async storeRaw(
    key: string,
    description: string,
    value: unknown,
    options?: { taskIds?: string[]; scope?: MemoryScope }
  ): Promise&lt;void&gt;

Parameters:

  • key: string
  • description: string
  • value: unknown
  • options: { taskIds?: string[] | undefined; scope?: MemoryScope | undefined; } | undefined (optional)

Returns: Promise&lt;void&gt;

storeSummary()

Store a summary derived from raw data (normal priority)

Use this for processed/summarized data that extracts key information. Links back to source data for cleanup tracking.

typescript
async storeSummary(
    key: string,
    description: string,
    value: unknown,
    derivedFrom: string | string[],
    options?: { taskIds?: string[]; scope?: MemoryScope }
  ): Promise&lt;void&gt;

Parameters:

  • key: string
  • description: string
  • value: unknown
  • derivedFrom: string | string[]
  • options: { taskIds?: string[] | undefined; scope?: MemoryScope | undefined; } | undefined (optional)

Returns: Promise&lt;void&gt;

storeFindings()

Store final findings (high priority, kept longest)

Use this for conclusions, insights, or final results that should be preserved. These are the last to be evicted and typically span the entire plan.

typescript
async storeFindings(
    key: string,
    description: string,
    value: unknown,
    _derivedFrom?: string | string[],
    options?: { taskIds?: string[]; scope?: MemoryScope; pinned?: boolean }
  ): Promise&lt;void&gt;

Parameters:

  • key: string
  • description: string
  • value: unknown
  • _derivedFrom: string | string[] | undefined (optional)
  • options: { taskIds?: string[] | undefined; scope?: MemoryScope | undefined; pinned?: boolean | undefined; } | undefined (optional)

Returns: Promise&lt;void&gt;

cleanupRawData()

Clean up raw data after summary/findings are created

Call this after creating summaries to free up memory used by raw data. Only deletes entries in the 'raw' tier.

typescript
async cleanupRawData(derivedFromKeys: string[]): Promise&lt;number&gt;

Parameters:

  • derivedFromKeys: string[]

Returns: Promise&lt;number&gt;

getByTier()

Get all entries by tier

typescript
async getByTier(tier: MemoryTier): Promise&lt;MemoryEntry[]&gt;

Parameters:

  • tier: MemoryTier

Returns: Promise&lt;MemoryEntry[]&gt;

promote()

Promote an entry to a higher tier

Changes the key prefix and updates priority. Use this when raw data becomes more valuable (e.g., frequently accessed).

typescript
async promote(key: string, toTier: MemoryTier): Promise&lt;string&gt;

Parameters:

  • key: string
  • toTier: MemoryTier

Returns: Promise&lt;string&gt;

getTierStats()

Get tier statistics

typescript
async getTierStats(): Promise&lt;Record&lt;MemoryTier, { count: number; sizeBytes: number }&gt;&gt;

Returns: Promise&lt;Record&lt;MemoryTier, { count: number; sizeBytes: number; }&gt;&gt;

getStats()

Get statistics about memory usage

typescript
async getStats(): Promise&lt;{
    totalEntries: number;
    totalSizeBytes: number;
    utilizationPercent: number;
    byPriority: Record&lt;MemoryPriority, number&gt;;
    pinnedCount: number;
  }&gt;

Returns: Promise&lt;{ totalEntries: number; totalSizeBytes: number; utilizationPercent: number; byPriority: Record&lt;MemoryPriority, number&gt;; pinnedCount: number; }&gt;

getLimit()

Get the configured memory limit

typescript
getLimit(): number

Returns: number

destroy()

Destroy the WorkingMemory instance Removes all event listeners and clears internal state

typescript
destroy(): void

Returns: void

serialize()

Serialize all memory entries for persistence

Returns a serializable representation of all memory entries that can be saved to storage and restored later.

typescript
async serialize(): Promise&lt;SerializedMemory&gt;

Returns: Promise&lt;SerializedMemory&gt;

restore()

Restore memory entries from serialized state

Clears existing memory and repopulates from the serialized state. Timestamps are reset to current time.

typescript
async restore(state: SerializedMemory): Promise&lt;void&gt;

Parameters:

  • state: SerializedMemory

Returns: Promise&lt;void&gt;


WorkingMemoryPluginNextGen class

📍 src/core/context-nextgen/plugins/WorkingMemoryPluginNextGen.ts:95

Constructor

constructor

typescript
constructor(pluginConfig: WorkingMemoryPluginConfig = {})

Parameters:

  • pluginConfig: WorkingMemoryPluginConfig (optional) (default: {})
Methods

getInstructions()

typescript
getInstructions(): string

Returns: string

getContent()

typescript
async getContent(): Promise&lt;string | null&gt;

Returns: Promise&lt;string | null&gt;

getContents()

typescript
getContents(): unknown

Returns: unknown

getTokenSize()

typescript
getTokenSize(): number

Returns: number

getInstructionsTokenSize()

typescript
getInstructionsTokenSize(): number

Returns: number

isCompactable()

typescript
isCompactable(): boolean

Returns: boolean

compact()

typescript
async compact(_targetTokensToFree: number): Promise&lt;number&gt;

Parameters:

  • _targetTokensToFree: number

Returns: Promise&lt;number&gt;

getTools()

typescript
getTools(): ToolFunction[]

Returns: ToolFunction&lt;any, any&gt;[]

destroy()

typescript
destroy(): void

Returns: void

getState()

typescript
getState(): SerializedWorkingMemoryState

Returns: SerializedWorkingMemoryState

restoreState()

typescript
restoreState(state: unknown): void

Parameters:

  • state: unknown

Returns: void

getStoreSchema()

typescript
getStoreSchema(): StoreEntrySchema

Returns: StoreEntrySchema

storeGet()

typescript
async storeGet(key?: string, _context?: ToolContext): Promise&lt;StoreGetResult&gt;

Parameters:

  • key: string | undefined (optional)
  • _context: ToolContext | undefined (optional)

Returns: Promise&lt;StoreGetResult&gt;

storeSet()

typescript
async storeSet(key: string, data: Record&lt;string, unknown&gt;, _context?: ToolContext): Promise&lt;StoreSetResult&gt;

Parameters:

  • key: string
  • data: Record&lt;string, unknown&gt;
  • _context: ToolContext | undefined (optional)

Returns: Promise&lt;StoreSetResult&gt;

storeDelete()

typescript
async storeDelete(key: string, _context?: ToolContext): Promise&lt;StoreDeleteResult&gt;

Parameters:

  • key: string
  • _context: ToolContext | undefined (optional)

Returns: Promise&lt;StoreDeleteResult&gt;

storeList()

typescript
async storeList(filter?: Record&lt;string, unknown&gt;, _context?: ToolContext): Promise&lt;StoreListResult&gt;

Parameters:

  • filter: Record&lt;string, unknown&gt; | undefined (optional)
  • _context: ToolContext | undefined (optional)

Returns: Promise&lt;StoreListResult&gt;

storeAction()

typescript
async storeAction(action: string, params?: Record&lt;string, unknown&gt;, _context?: ToolContext): Promise&lt;StoreActionResult&gt;

Parameters:

  • action: string
  • params: Record&lt;string, unknown&gt; | undefined (optional)
  • _context: ToolContext | undefined (optional)

Returns: Promise&lt;StoreActionResult&gt;

store()

Store a value in memory

typescript
async store(
    key: string,
    description: string,
    value: unknown,
    options?: {
      scope?: MemoryScope;
      priority?: MemoryPriority;
      tier?: MemoryTier;
      pinned?: boolean;
    }
  ): Promise&lt;{ key: string; sizeBytes: number }&gt;

Parameters:

  • key: string
  • description: string
  • value: unknown
  • options: { scope?: MemoryScope | undefined; priority?: MemoryPriority | undefined; tier?: MemoryTier | undefined; pinned?: boolean | undefined; } | undefined (optional)

Returns: Promise&lt;{ key: string; sizeBytes: number; }&gt;

retrieve()

Retrieve a value from memory

typescript
async retrieve(key: string): Promise&lt;unknown | undefined&gt;

Parameters:

  • key: string

Returns: Promise&lt;unknown&gt;

delete()

Delete a key from memory

typescript
async delete(key: string): Promise&lt;boolean&gt;

Parameters:

  • key: string

Returns: Promise&lt;boolean&gt;

query()

Query memory entries

typescript
async query(options?: {
    pattern?: string;
    tier?: MemoryTier;
    includeValues?: boolean;
    includeStats?: boolean;
  }): Promise&lt;{
    entries: Array&lt;{
      key: string;
      description: string;
      tier?: MemoryTier;
      value?: unknown;
    }&gt;;
    stats?: { count: number; totalBytes: number };
  }&gt;

Parameters:

  • options: { pattern?: string | undefined; tier?: MemoryTier | undefined; includeValues?: boolean | undefined; includeStats?: boolean | undefined; } | undefined (optional)

Returns: Promise&lt;{ entries: { key: string; description: string; tier?: MemoryTier | undefined; value?: unknown; }[]; stats?: { count: number; totalBytes: number; } | undefined; }&gt;

formatIndex()

Format memory index for context

typescript
async formatIndex(): Promise&lt;string&gt;

Returns: Promise&lt;string&gt;

evict()

Evict entries to free space

typescript
async evict(count: number, strategy: EvictionStrategy = 'lru'): Promise&lt;string[]&gt;

Parameters:

  • count: number
  • strategy: EvictionStrategy (optional) (default: 'lru')

Returns: Promise&lt;string[]&gt;

cleanupRaw()

Cleanup raw tier entries

typescript
async cleanupRaw(): Promise&lt;{ deleted: number; keys: string[] }&gt;

Returns: Promise&lt;{ deleted: number; keys: string[]; }&gt;

Properties
Property Type Description
name name: "working_memory" -

CheckpointStrategy interface

📍 src/capabilities/taskAgent/CheckpointManager.ts:8

Properties
Property Type Description
afterToolCalls? afterToolCalls?: number; Checkpoint after every N tool calls
afterLLMCalls? afterLLMCalls?: number; Checkpoint after every N LLM calls
intervalMs? intervalMs?: number; Checkpoint on time interval
beforeExternalWait beforeExternalWait: boolean; Always checkpoint before external wait
mode `mode: 'sync' 'async';`

ExternalDependency interface

📍 src/domain/entities/Task.ts:71

External dependency configuration

Properties
Property Type Description
type `type: 'webhook' 'poll'
webhookId? webhookId?: string; For webhook: unique ID to match incoming webhook
pollConfig? `pollConfig?: {
toolName: string;
toolArgs: Record&lt;string, unknown&gt;;
intervalMs: number;
maxAttempts: number;

};| For poll: how to check if complete | |scheduledAt?|scheduledAt?: number;| For scheduled: when to resume | |manualDescription?|manualDescription?: string;| For manual: description of what's needed | |timeoutMs?|timeoutMs?: number;| Timeout for all types | |state|state: 'waiting' | 'received' | 'timeout';| Current state | |receivedData?|receivedData?: unknown;| Data received from external source | |receivedAt?|receivedAt?: number;` | - |


ExternalDependencyEvents interface

📍 src/capabilities/taskAgent/ExternalDependencyHandler.ts:10

Properties
Property Type Description
'webhook:received' 'webhook:received': { webhookId: string; data: unknown }; -
'poll:success' 'poll:success': { taskId: string; data: unknown }; -
'poll:timeout' 'poll:timeout': { taskId: string }; -
'scheduled:triggered' 'scheduled:triggered': { taskId: string }; -
'manual:completed' 'manual:completed': { taskId: string; data: unknown }; -

GeneratedPlan interface

📍 src/capabilities/taskAgent/PlanningAgent.ts:36

Generated plan with metadata

Properties
Property Type Description
plan plan: Plan; -
reasoning reasoning: string; -
estimated_duration? estimated_duration?: string; -
complexity? `complexity?: 'low' 'medium'

IMemoryStorage interface

📍 src/domain/interfaces/IMemoryStorage.ts:14

Methods

get()

Get entry by key

typescript
get(key: string): Promise&lt;MemoryEntry | undefined&gt;;

Parameters:

  • key: string

Returns: Promise&lt;MemoryEntry | undefined&gt;

set()

Set/update entry

typescript
set(key: string, entry: MemoryEntry): Promise&lt;void&gt;;

Parameters:

  • key: string
  • entry: MemoryEntry

Returns: Promise&lt;void&gt;

delete()

Delete entry

typescript
delete(key: string): Promise&lt;void&gt;;

Parameters:

  • key: string

Returns: Promise&lt;void&gt;

has()

Check if key exists

typescript
has(key: string): Promise&lt;boolean&gt;;

Parameters:

  • key: string

Returns: Promise&lt;boolean&gt;

getAll()

Get all entries

typescript
getAll(): Promise&lt;MemoryEntry[]&gt;;

Returns: Promise&lt;MemoryEntry[]&gt;

getByScope()

Get entries by scope

typescript
getByScope(scope: MemoryScope): Promise&lt;MemoryEntry[]&gt;;

Parameters:

  • scope: MemoryScope

Returns: Promise&lt;MemoryEntry[]&gt;

clearScope()

Clear all entries with given scope

typescript
clearScope(scope: MemoryScope): Promise&lt;void&gt;;

Parameters:

  • scope: MemoryScope

Returns: Promise&lt;void&gt;

clear()

Clear everything

typescript
clear(): Promise&lt;void&gt;;

Returns: Promise&lt;void&gt;

getTotalSize()

Get total size in bytes

typescript
getTotalSize(): Promise&lt;number&gt;;

Returns: Promise&lt;number&gt;


IMemoryStore interface

📍 src/memory/types.ts:770

Storage contract. Required methods are the minimum capability; optional methods (traverse, semanticSearch) are discovered by duck-typing.

Id generation: adapters own id assignment. createEntity / createFact return a fully-formed record with its id populated. Callers never pass ids for new records.

Adapter responsibilities:

  • Apply ScopeFilter to every read — MemorySystem also filters, but the adapter must provide defence-in-depth.
  • Assign primary ids on create. Native mechanisms preferred (Mongo ObjectId, Meteor Random.id(), UUID for in-memory).
  • Enforce optimistic concurrency on updateEntity: reject if incoming version !== stored.version + 1.
  • Hide archived records by default; return them only when an explicit archived: true filter is passed.
  • Support asOf on fact queries (validFrom ≤ asOf ≤ validUntil ?? ∞ AND createdAt ≤ asOf).
  • When possible, expose a transactional primitive for supersession — MemorySystem currently writes the new fact before archiving the predecessor (crash-safe ordering) but adapters with native transactions may promote this to a single atomic operation.
Methods

createEntity()

Insert a new entity. Adapter assigns id + version (1) + timestamps. Returns the created record.

typescript
createEntity(input: NewEntity): Promise&lt;IEntity&gt;;

Parameters:

  • input: NewEntity

Returns: Promise&lt;IEntity&gt;

createEntities()

Batch insert. Returned array is in the same order as input.

typescript
createEntities(inputs: NewEntity[]): Promise&lt;IEntity[]&gt;;

Parameters:

  • inputs: NewEntity[]

Returns: Promise&lt;IEntity[]&gt;

updateEntity()

Update an existing entity. Incoming version must equal stored.version + 1.

typescript
updateEntity(entity: IEntity): Promise&lt;void&gt;;

Parameters:

  • entity: IEntity

Returns: Promise&lt;void&gt;

getEntity()

typescript
getEntity(id: EntityId, scope: ScopeFilter): Promise&lt;IEntity | null&gt;;

Parameters:

  • id: string
  • scope: ScopeFilter

Returns: Promise&lt;IEntity | null&gt;

getEntities()

Batch fetch entities by id. Returned array is in the same order as input; ids not found or filtered out by scope resolve to null in-place. Lets callers render references (e.g. fact.objectId → entity displayName) without firing N round-trips. Adapters SHOULD implement this as a single native batch query (e.g. Mongo {_id:{$in:[…]}}); the default InMemory impl maps over getEntity.

typescript
getEntities(ids: EntityId[], scope: ScopeFilter): Promise&lt;Array&lt;IEntity | null&gt;&gt;;

Parameters:

  • ids: string[]
  • scope: ScopeFilter

Returns: Promise&lt;(IEntity | null)[]&gt;

findEntitiesByIdentifier()

typescript
findEntitiesByIdentifier(kind: string, value: string, scope: ScopeFilter): Promise&lt;IEntity[]&gt;;

Parameters:

  • kind: string
  • value: string
  • scope: ScopeFilter

Returns: Promise&lt;IEntity[]&gt;

findEntitiesByNormalizedName()

O(1) indexed exact-match lookup for entities whose normalizedDisplayName (or, when opts.matchAliases, normalizedAliases) equals normalized. Used by EntityResolver Tier 2/3 in place of the legacy searchEntities(q, {limit:50}) substring-then-filter path which was both order-sensitive (Mongo oversample cap could truncate exact matches under heavy substring fan-out) and non-atomic.

Contract:

  • Returns at most opts.limit entities (default 20).
  • Equality is byte-for-byte against the stored normalized field — callers must normalize the query string the same way (normalizeSurface).
  • Archived entities excluded.
  • Scope filter applied identically to other reads.
  • Entities lacking normalizedDisplayName (legacy pre-0.8.0 data) are treated as if the field doesn't match — they are NOT returned. Hosts upgrading from <0.8.0 must run MemorySystem.backfillNormalizedFields to populate.
  • When opts.matchAliases is true, the method returns entities matching EITHER normalizedDisplayName === normalized OR normalized ∈ normalizedAliases. Default is false (displayName only).
typescript
findEntitiesByNormalizedName(
    type: string | undefined,
    normalized: string,
    scope: ScopeFilter,
    opts?: { matchAliases?: boolean; limit?: number },
  ): Promise&lt;IEntity[]&gt;;

Parameters:

  • type: string | undefined
  • normalized: string
  • scope: ScopeFilter
  • opts: { matchAliases?: boolean | undefined; limit?: number | undefined; } | undefined (optional)

Returns: Promise&lt;IEntity[]&gt;

atomicCreateOrFindByNormalizedName()

Atomically find-or-create an entity by (type, normalizedDisplayName, scope). The load-bearing primitive for eliminating concurrent-insert duplicates — two callers racing the same surface converge on a single row.

Returns:

  • { entity, created: true } — no prior row existed; the adapter inserted input and returned the fresh entity.
  • { entity, created: false } — a row was already present (or another writer beat us to insert); the adapter returned the winner unchanged. Callers are responsible for accumulating aliases/identifiers/metadata onto the winner after the fact (see MemorySystem.tryAtomicCreateOrResolve).

Atomicity guarantees:

  • InMemory: enforced by the JS event-loop (no await between read and write inside the method body) — single-process only.
  • Mongo: enforced by a unique partial index on {groupId, ownerId, type, normalizedDisplayName}. Hosts must install this index via ensureNormalizedNameUniqueIndex (exported from the library) — otherwise the method degrades to a non-atomic find-then-create that still races. Adding a unique index to a collection containing duplicates fails hard, so the library refuses to auto-create it; run after backfillNormalizedFields + a dedup pass.

Degraded path:

  • When normalizeSurface(input.displayName) collapses to empty (pure punctuation / whitespace), the adapter cannot index a stable key. Falls back to plain createEntity — guaranteed created: true. The caller will see a duplicate in the rare case of two concurrent writes of pure-punctuation displayNames.
typescript
atomicCreateOrFindByNormalizedName(
    input: NewEntity,
    scope: ScopeFilter,
  ): Promise&lt;{ entity: IEntity; created: boolean }&gt;;

Parameters:

  • input: NewEntity
  • scope: ScopeFilter

Returns: Promise&lt;{ entity: IEntity; created: boolean; }&gt;

searchEntities()

typescript
searchEntities(query: string, opts: EntitySearchOptions, scope: ScopeFilter): Promise&lt;Page&lt;IEntity&gt;&gt;;

Parameters:

  • query: string
  • opts: EntitySearchOptions
  • scope: ScopeFilter

Returns: Promise&lt;Page&lt;IEntity&gt;&gt;

listEntities()

typescript
listEntities(filter: EntityListFilter, opts: ListOptions, scope: ScopeFilter): Promise&lt;Page&lt;IEntity&gt;&gt;;

Parameters:

  • filter: EntityListFilter
  • opts: ListOptions
  • scope: ScopeFilter

Returns: Promise&lt;Page&lt;IEntity&gt;&gt;

archiveEntity()

typescript
archiveEntity(id: EntityId, scope: ScopeFilter): Promise&lt;void&gt;;

Parameters:

  • id: string
  • scope: ScopeFilter

Returns: Promise&lt;void&gt;

deleteEntity()

Hard delete — MemorySystem gates this with an explicit flag.

typescript
deleteEntity(id: EntityId, scope: ScopeFilter): Promise&lt;void&gt;;

Parameters:

  • id: string
  • scope: ScopeFilter

Returns: Promise&lt;void&gt;

createFact()

Insert a new fact. Adapter assigns id + createdAt. Returns the created record.

typescript
createFact(input: NewFact): Promise&lt;IFact&gt;;

Parameters:

  • input: NewFact

Returns: Promise&lt;IFact&gt;

createFacts()

Batch insert. Returned array is in the same order as input.

typescript
createFacts(inputs: NewFact[]): Promise&lt;IFact[]&gt;;

Parameters:

  • inputs: NewFact[]

Returns: Promise&lt;IFact[]&gt;

getFact()

typescript
getFact(id: FactId, scope: ScopeFilter): Promise&lt;IFact | null&gt;;

Parameters:

  • id: string
  • scope: ScopeFilter

Returns: Promise&lt;IFact | null&gt;

findFacts()

typescript
findFacts(filter: FactFilter, opts: FactQueryOptions, scope: ScopeFilter): Promise&lt;Page&lt;IFact&gt;&gt;;

Parameters:

  • filter: FactFilter
  • opts: FactQueryOptions
  • scope: ScopeFilter

Returns: Promise&lt;Page&lt;IFact&gt;&gt;

updateFact()

Patch fields on an existing fact. Used for archiving + embedding writes.

typescript
updateFact(id: FactId, patch: Partial&lt;IFact&gt;, scope: ScopeFilter): Promise&lt;void&gt;;

Parameters:

  • id: string
  • patch: Partial&lt;IFact&gt;
  • scope: ScopeFilter

Returns: Promise&lt;void&gt;

countFacts()

typescript
countFacts(filter: FactFilter, scope: ScopeFilter): Promise&lt;number&gt;;

Parameters:

  • filter: FactFilter
  • scope: ScopeFilter

Returns: Promise&lt;number&gt;

rewriteEntityPrincipal()?

Rewrite every entity:<fromEntityId> access grant to entity:<toEntityId> across all entities + facts (in readPrincipals, writePrincipals, and acl). Used by mergeEntities so access grants follow identity convergence — when a duplicate Person is merged away, records previously readable via the loser's principal become readable via the winner's. Bulk identity fix: scoped to the caller's tenant (scope.groupId) for safety, but does not run per-record write checks (the merge already enforced same-tenant + write access on winner/loser).

Optional capability — stores that don't implement it simply skip this step (their merges won't rewrite ACL grants). Both built-in adapters implement it.

typescript
rewriteEntityPrincipal?(
    fromEntityId: EntityId,
    toEntityId: EntityId,
    scope: ScopeFilter,
  ): Promise&lt;void&gt;;

Parameters:

  • fromEntityId: string
  • toEntityId: string
  • scope: ScopeFilter

Returns: Promise&lt;void&gt;

traverse()?

typescript
traverse?(startId: EntityId, opts: TraversalOptions, scope: ScopeFilter): Promise&lt;Neighborhood&gt;;

Parameters:

  • startId: string
  • opts: TraversalOptions
  • scope: ScopeFilter

Returns: Promise&lt;Neighborhood&gt;

semanticSearch()?

typescript
semanticSearch?(
    queryVector: number[],
    filter: FactFilter,
    opts: SemanticSearchOptions,
    scope: ScopeFilter,
  ): Promise&lt;Array&lt;{ fact: IFact; score: number }&gt;&gt;;

Parameters:

  • queryVector: number[]
  • filter: FactFilter
  • opts: SemanticSearchOptions
  • scope: ScopeFilter

Returns: Promise&lt;{ fact: IFact; score: number; }[]&gt;

semanticSearchEntities()?

Entity-level semantic search. Default field is identityEmbedding, consumed by EntityResolver's semantic tier (Tier 4) when EntityResolutionConfig.enableSemanticResolution is on. With opts.embeddingField:'content', the same method searches contentEmbedding — used by MemorySystem.searchDocuments. Adapters that don't implement this are skipped — the resolver falls back to Tiers 1-3.

Contract:

  • filter.type / filter.types narrow by IEntity.type. At least one should be used in practice — otherwise every entity type is a candidate.
  • opts.topK clamped by the caller (resolver passes small values, ~10).
  • opts.minScore optional noise floor (adapter MAY pre-filter; resolver post-filters regardless, so implementations can ignore it).
  • opts.embeddingField selects which entity embedding to search; defaults to 'identity' for backward compatibility. Adapters MUST NOT silently fall back to the other field on misses — return an empty result.
  • Results ordered by descending score (cosine similarity, 0..1).
  • Archived entities MUST be excluded.
  • scope enforcement identical to every other read.
typescript
semanticSearchEntities?(
    queryVector: number[],
    filter: EntitySemanticSearchFilter,
    opts: SemanticSearchOptions & { minScore?: number; embeddingField?: EntityEmbeddingField },
    scope: ScopeFilter,
  ): Promise&lt;Array&lt;{ entity: IEntity; score: number }&gt;&gt;;

Parameters:

  • queryVector: number[]
  • filter: EntitySemanticSearchFilter
  • opts: SemanticSearchOptions & { minScore?: number | undefined; embeddingField?: EntityEmbeddingField | undefined; }
  • scope: ScopeFilter

Returns: Promise&lt;{ entity: IEntity; score: number; }[]&gt;

destroy()

typescript
destroy(): void;

Returns: void

shutdown()?

typescript
shutdown?(): Promise&lt;void&gt;;

Returns: Promise&lt;void&gt;


InContextMemoryConfig interface

📍 src/core/context-nextgen/plugins/InContextMemoryPluginNextGen.ts:38

Properties
Property Type Description
maxEntries? maxEntries?: number; Maximum number of entries (default: 20)
maxTotalTokens? maxTotalTokens?: number; Maximum total tokens for all entries (default: 40000)
defaultPriority? defaultPriority?: InContextPriority; Default priority for new entries (default: 'normal')
showTimestamps? showTimestamps?: boolean; Whether to show timestamps in output (default: false)
onEntriesChanged? onEntriesChanged?: (entries: InContextEntry[]) =&gt; void; Callback fired when entries change. Receives all current entries.

InMemoryAdapterOptions interface

📍 src/memory/adapters/inmemory/InMemoryAdapter.ts:49

Properties
Property Type Description
entities? entities?: IEntity[]; Seed data for tests.
facts? facts?: IFact[]; -

IPlanStorage interface

📍 src/domain/interfaces/IPlanStorage.ts:8

Methods

savePlan()

Save or update a plan

typescript
savePlan(plan: Plan): Promise&lt;void&gt;;

Parameters:

  • plan: Plan

Returns: Promise&lt;void&gt;

getPlan()

Get plan by ID

typescript
getPlan(planId: string): Promise&lt;Plan | undefined&gt;;

Parameters:

  • planId: string

Returns: Promise&lt;Plan | undefined&gt;

updateTask()

Update a specific task within a plan

typescript
updateTask(planId: string, task: Task): Promise&lt;void&gt;;

Parameters:

  • planId: string
  • task: Task

Returns: Promise&lt;void&gt;

addTask()

Add a new task to a plan (for dynamic task creation)

typescript
addTask(planId: string, task: Task): Promise&lt;void&gt;;

Parameters:

  • planId: string
  • task: Task

Returns: Promise&lt;void&gt;

deletePlan()

Delete a plan

typescript
deletePlan(planId: string): Promise&lt;void&gt;;

Parameters:

  • planId: string

Returns: Promise&lt;void&gt;

listPlans()

List plans by status

typescript
listPlans(filter?: { status?: PlanStatus[] }): Promise&lt;Plan[]&gt;;

Parameters:

  • filter: { status?: PlanStatus[] | undefined; } | undefined (optional)

Returns: Promise&lt;Plan[]&gt;

findByWebhookId()

Find plans with tasks waiting on a specific webhook

typescript
findByWebhookId(webhookId: string): Promise&lt;{ plan: Plan; task: Task } | undefined&gt;;

Parameters:

  • webhookId: string

Returns: Promise&lt;{ plan: Plan; task: Task; } | undefined&gt;


IScopedMemoryView interface

📍 src/memory/types.ts:991

Read-only view scoped to a specific caller, passed to the rule engine. Rules CANNOT write through this view — they return partial IFact specs that MemorySystem validates and persists.

Methods

getEntity()

typescript
getEntity(id: EntityId): Promise&lt;IEntity | null&gt;;

Parameters:

  • id: string

Returns: Promise&lt;IEntity | null&gt;

findFacts()

typescript
findFacts(filter: FactFilter, opts?: { limit?: number }): Promise&lt;IFact[]&gt;;

Parameters:

  • filter: FactFilter
  • opts: { limit?: number | undefined; } | undefined (optional)

Returns: Promise&lt;IFact[]&gt;


MemoryConnectorsConfig interface

📍 src/memory/integration/createMemorySystemWithConnectors.ts:19

Properties
Property Type Description
embedding? embedding?: ConnectorEmbedderConfig; -
profile? profile?: ConnectorProfileGeneratorConfig; -

MemoryEntry interface

📍 src/domain/entities/Memory.ts:380

Single memory entry stored in working memory

Properties
Property Type Description
key key: string; -
description description: string; -
value value: unknown; -
sizeBytes sizeBytes: number; -
scope scope: MemoryScope; -
basePriority basePriority: MemoryPriority; -
pinned pinned: boolean; -
createdAt createdAt: number; -
lastAccessedAt lastAccessedAt: number; -
accessCount accessCount: number; -

MemoryEntryInput interface

📍 src/domain/entities/Memory.ts:444

Input for creating a memory entry

Properties
Property Type Description
key key: string; -
description description: string; -
value value: unknown; -
scope? scope?: MemoryScope; Scope - defaults to 'session' for basic agents
priority? priority?: MemoryPriority; Base priority - may be overridden by dynamic calculation
pinned? pinned?: boolean; If true, entry is never evicted

MemoryIndex interface

📍 src/domain/entities/Memory.ts:408

Full memory index with metadata

Properties
Property Type Description
entries entries: MemoryIndexEntry[]; -
totalSizeBytes totalSizeBytes: number; -
totalSizeHuman totalSizeHuman: string; -
limitBytes limitBytes: number; -
limitHuman limitHuman: string; -
utilizationPercent utilizationPercent: number; -
totalEntryCount totalEntryCount: number; Total entry count (before any truncation for display)
omittedCount omittedCount: number; Number of entries omitted from display due to maxIndexEntries limit

MemoryIndexEntry interface

📍 src/domain/entities/Memory.ts:396

Index entry (lightweight, always in context)

Properties
Property Type Description
key key: string; -
description description: string; -
size size: string; -
scope scope: MemoryScope; -
effectivePriority effectivePriority: MemoryPriority; -
pinned pinned: boolean; -

MemoryPluginConfig interface

📍 src/core/context-nextgen/plugins/MemoryPluginNextGen.ts:126

Properties
Property Type Description
memory memory: MemorySystem; Live memory system. REQUIRED.
agentId agentId: string; Agent id — unique per agent definition.
userId userId: string; Current user id. REQUIRED — the memory layer's owner invariant means every
bootstrapped entity needs an owner. Host app should pass the logged-in
user's id (auto-filled from AgentContextNextGen.userId when wired via
feature flag).
groupId? groupId?: string; Trusted group id for the caller (authenticated by the host app).
Closed into tool deps so every memory call uses this groupId. Tools do
NOT accept a groupId arg from the LLM — see the security review. Leave
undefined for non-grouped deployments.
principals? principals?: string[]; Trusted caller principal set (host-resolved), e.g.
['user:<id>', 'group:<gid>', 'world', 'entity:<selfPersonId>']. When set,
the plugin's read scope (profile injection / getContext) AND the read tools
authorize by principal intersection (readPrincipals ∋ caller) instead of
legacy owner/group/world — so the agent sees facts/entities granted to the
user's Person (entity: token), including ones it doesn't own. Omitted →
legacy scope (backward compatible). NEVER derived from LLM input — host-
trusted, same provenance as groupId.
timezone? timezone?: string; Viewer's IANA timezone (e.g. 'America/New_York'). When set, injected
instants (events, recent-activity timestamps) and the user's **Timezone:**
label render in this zone instead of UTC. When absent, instants render as
stored (UTC, explicitly labelled). The host supplies this — the plugin never
reads entity metadata to discover it.
userEntityPermissions? userEntityPermissions?: Permissions; Permissions stamped on the bootstrapped user entity.
agentEntityPermissions? agentEntityPermissions?: Permissions; Permissions stamped on the bootstrapped agent entity.
personaEntityId? personaEntityId?: EntityId; Optional persona entity id. When set, the agent's behavior rules are
read from and written to this entity instead of the variant agent entity
bootstrapped by agentId. Lets several agent variants share one identity:
pass the same personaEntityId to each variant and any rule written via
memory_set_agent_rule (and any 'me'/'this_agent' subject token in read
tools) lands on the shared persona, so all variants render the same
"User-specific instructions for this agent" block.

The variant agent entity (keyed by system_agent_id:<agentId>) is still bootstrapped — host code that wants per-variant analytics or factContextIds can reach it via getBootstrappedIds().agentEntityId. Only the LLM-facing subject for rules + 'this_agent' is overridden.

The host owns the persona entity's lifecycle (upsert with whatever type/identifier scheme fits — e.g. type:'assistant_persona' keyed by {kind:'system_assistant_persona_id', value:userId} for a per-user persona). The persona entity MUST be owned by the same userId passed here, or memory_set_agent_rule will reject writes with a cross-owner error (the same ownership invariant enforced for variant agents). | | groupBootstrap? | groupBootstrap?: { /** Display name of the organization (e.g., the group's namefield). */ displayName: string; /** * Additional identifiers beyondsystem_group_id. For example: * [{ kind: 'domain', value: 'acme.com' }]lets signal extraction * converge with this same entity — the library'sEmailSignalAdapter * seeds organizations withkind: 'domain' when resolving participant * email addresses. Match that convention so bootstrap doesn't create a * parallel entity. */ identifiers?: Identifier[]; /** Permissions stamped on the bootstrapped organization entity. */ permissions?: Permissions; }; | Optional group ("current organization") bootstrap. When present AND groupId is set, a third organization entity is upserted carrying the identifier {kind: 'system_group_id', value: groupId} (plus any extras). Rendered as an "About the User's Organization" block alongside the user profile.

Visibility of facts on this entity is controlled by the host's MemorySystem.visibilityPolicy and per-write permissions overrides — the library's built-in defaults are group-read + world-read. A host that needs per-user privacy on a shared org entity MUST install a visibility policy that produces user-private permissions on those facts.

Skip this field (or leave groupId undefined) in non-grouped deployments or when the caller has no current organization (e.g., platform superadmin). | | userProfileInjection? | userProfileInjection?: MemoryPluginInjectionConfig; | Per-profile injection config. Defaults to {profile:true, topFacts:20}. | | agentProfileInjection? | agentProfileInjection?: MemoryPluginInjectionConfig; | - | | groupProfileInjection? | groupProfileInjection?: MemoryPluginInjectionConfig; | Injection config for the group ("organization") profile block. Same defaults as userProfileInjection. Ignored when groupBootstrap is not provided. | | defaultVisibility? | defaultVisibility?: { forUser?: Visibility; forAgent?: Visibility; forOther?: Visibility; }; | Default visibility for memory_remember / memory_link. Defaults: forUser='private', forAgent='group', forOther='private'. | | autoResolveThreshold? | autoResolveThreshold?: number; | Fuzzy-match threshold for {surface} lookups. Default: 0.9. | | userDisplayName? | userDisplayName?: string; | Entity display names used when bootstrapping. If the user/agent entity already exists (identifier-keyed), these are ignored. The group entity's displayName is taken from groupBootstrap.displayName. | | agentDisplayName? | agentDisplayName?: string; | - |


MemoryPluginInjectionConfig interface

📍 src/core/context-nextgen/plugins/MemoryPluginNextGen.ts:87

Properties
Property Type Description
profile? profile?: boolean; Include profile.details text. Default: true.
topFacts? topFacts?: number; Top N recent ranked facts to include. 0 disables. Default: 20.
factPredicates? factPredicates?: string[]; Restrict topFacts to these predicates. Default: all.
relatedTasks? relatedTasks?: boolean; Include active related tasks. Default: false.
relatedEvents? relatedEvents?: boolean; Include recent related events. Default: false.
identifiers? identifiers?: boolean; Include the entity's identifiers (kind=value). Default: false.
maxFactLineChars? maxFactLineChars?: number; Optional cap on each rendered fact line. Default: undefined (no cap).
Previously defaulted to 200 chars, which clipped fact details mid-sentence
in the system message. Hosts who want to keep the system message small
can set this explicitly. See feedback_no_truncation.md.
recentActivity? `recentActivity?: {
/** How many rows to render. 0 disables. Default 20. */
limit?: number;
/** Lookback window in days. Default 7. */
windowDays?: number;
/** Optional predicate allowlist — e.g. `['committed_to','attended','decision_made']`. */
predicates?: string[];

};| Time-ordered recent activity about this entity. Renders a### Recent activitysection after the top facts. UnliketopFacts` (ranked), this is strict newest-first — the agent sees a rolling window of what the subject has actually been doing.

Defaults: ON with { limit: 20, windowDays: 7 }. Pass { limit: 0 } to disable. |


MemorySystemConfig interface

📍 src/memory/types.ts:1392

Properties
Property Type Description
store store: IMemoryStore; -
embedder? embedder?: IEmbedder; -
profileGenerator? profileGenerator?: IProfileGenerator; -
ruleEngine? ruleEngine?: IRuleEngine; -
taskStates? taskStates?: TaskStatesConfig; Task-state vocabulary. Defaults to:
{ active: ['pending','in_progress','blocked','deferred'],
terminal: ['done','cancelled'] }

The two arrays must be disjoint and non-empty. | | stateHistoryCap? | stateHistoryCap?: number; | Maximum number of entries retained in task.metadata.stateHistory. transitionTaskState keeps the most-recent N entries (older entries are dropped in FIFO order). Guards against unbounded metadata growth on chatty tasks — a task that cycles through states thousands of times could otherwise push the entity document past Mongo's 16 MB cap. Entries past the cap are lost; callers that need unbounded audit must maintain it externally.

Default: 200. Must be >= 1. | | profileRegenerationThreshold? | profileRegenerationThreshold?: number; | Number of new atomic facts since last profile regen that triggers auto-regeneration. | | topFactsRanking? | topFactsRanking?: RankingConfig; | - | | embeddingQueue? | embeddingQueue?: EmbeddingQueueConfig; | - | | entityResolution? | entityResolution?: EntityResolutionConfig; | - | | predicates? | predicates?: import('./predicates/PredicateRegistry.js').PredicateRegistry; | Pluggable predicate vocabulary. When present, addFact canonicalizes the predicate (camelCase/dash/alias → snake_case), applies defaultImportance / isAggregate defaults, auto-supersedes prior facts for singleValued predicates, and folds registry weights into ranking. Absent = free-form predicate strings (pre-registry behavior).

Pass PredicateRegistry.standard() for the built-in 44-predicate starter set, PredicateRegistry.empty() plus .registerAll(...) for a fully custom vocabulary. | | predicateMode? | predicateMode?: 'permissive' | 'strict'; | 'strict' rejects any addFact whose (canonicalized) predicate is not in the registry. 'permissive' (default) writes unknowns verbatim — they show up in IngestionResult.newPredicates for drift monitoring. Throws at construction if set to 'strict' without a registry. | | unknownPredicatePolicy? | unknownPredicatePolicy?: 'fuzzy_map' | 'keep' | 'drop'; | H5 — how the LLM extraction pipeline handles a predicate that isn't in the registry (after canonicalisation). Only used when a registry is configured.

  • 'fuzzy_map' (default): try to snap onto the closest registered predicate via edit distance (length-aware — see unknownPredicateFuzzyMaxDistance). Typical wins: work_at→works_at, mention→mentioned. No match → fall through to 'keep'.
  • 'keep': write the unknown predicate verbatim (pre-H5 behaviour). Surfaces in IngestionResult.newPredicates for human review.
  • 'drop': skip the fact entirely, record the reason in unresolved.

Regardless of policy, the unknown predicate is always added to newPredicates (with the mapping target if one was chosen) so operators can still audit drift. | | unknownPredicateFuzzyMaxDistance? | unknownPredicateFuzzyMaxDistance?: number; | F3 — absolute cap on the Levenshtein distance used by findClosest when unknownPredicatePolicy='fuzzy_map'. The effective budget is also clamped by predicate length (floor(min(lenA,lenB)/4), min 1), so lowering this only tightens further. Default: 2 (registry's built-in budget).

Tune down (e.g. 1) if your vocabulary has semantically-distinct predicates within edit distance 2 of each other (talks_at vs works_at). Tune up only with confidence your predicates are well-separated in edit-distance space. | | predicateAutoSupersede? | predicateAutoSupersede?: boolean; | When true (default), addFact auto-supersedes the prior visible fact for a (subject, predicate) pair when the predicate is marked singleValued. Set to false to opt out while still getting canonicalization + defaults. | | onChange? | onChange?: (event: ChangeEvent) =&gt; void; | - | | onError? | onError?: (error: unknown, event: ChangeEvent) =&gt; void; | Invoked when onChange throws. Lets operators surface listener failures to their logging / telemetry pipeline rather than losing them silently. Falls back to console.warn when unset. | | visibilityPolicy? | visibilityPolicy?: VisibilityPolicy; | Host-supplied default permissions for every entity / fact write where the caller didn't specify permissions explicitly. Lets hosts express policies like "entities are group-readable, facts are owner-private by default" in one place instead of at every call site — and, critically, applies to writes emitted from inside the library (e.g., by ExtractionResolver or ProfileGenerator paths) that the host can't intercept directly.

Callers that pass permissions on the write input always win — the policy only fills the blanks. Return undefined from the policy to fall through to the library defaults (DEFAULT_GROUP_LEVEL / DEFAULT_WORLD_LEVEL, both 'read').

Keep the function cheap — it runs on every entity / fact create. | | entityContentComposers? | entityContentComposers?: Record&lt; string, import('./composers/types.js').EntityContentComposer &gt;; | Per-type content-embedding composers. Library ships defaults for task, event, person, organization, topic, project, document, cluster — see composers/defaults.ts. Caller-supplied entries override the default for that type; unspecified types fall back to the default (or get no content embedding if there is no default).

Composers run on every entity mutation site; contentEmbedding and contentEmbeddingText refresh whenever the composed text changes. Empty-string composer output skips the embed for that entity entirely. | | factContentComposer? | factContentComposer?: import('./composers/types.js').FactContentComposer; | Fact content-embedding composer. Library ships a default that composes atomic facts as "<subject.displayName> <predicate> <object.displayName | value>" (resolving entity ids to surface forms) and document facts as their details/summaryForEmbedding verbatim. Override to customize the embedded fact text or to skip embedding for specific predicates (return '' from compose). |


MemoryWritePluginConfig interface

📍 src/core/context-nextgen/plugins/MemoryWritePluginNextGen.ts:28

Properties
Property Type Description
memory memory: MemorySystem; Live memory system. REQUIRED.
agentId agentId: string; Agent id. REQUIRED — matches MemoryPluginNextGen.agentId.
userId userId: string; Current user id. REQUIRED — matches MemoryPluginNextGen.userId.
groupId? groupId?: string; Trusted group id from host auth. Matches MemoryPluginNextGen.groupId.
predicates? predicates?: PredicateRegistry; Optional explicit predicate registry override for prompt rendering.
When unset, the plugin uses memory.getPredicateRegistry() — that's
almost always what you want, since the same registry governs
canonicalization, validation, and ranking on writes. Override only when
you intentionally want the LLM's advertised vocabulary to differ from
the storage-enforced one (rare; mostly testing).
defaultVisibility? `defaultVisibility?: {
forUser?: Visibility;
forAgent?: Visibility;
forOther?: Visibility;

};| Default visibility for remember/link. Matches MemoryPlugin defaults. | |autoResolveThreshold?|autoResolveThreshold?: number;| Fuzzy-match threshold for{surface}subject lookups. Default 0.9. | |getOwnSubjectIds?|getOwnSubjectIds?: () => { userEntityId?: string; agentEntityId?: string };| Callback supplied by the siblingMemoryPluginNextGenso"me"/"this_agent"tokens resolve to its bootstrapped entities. When absent, those tokens return "not available". | |forgetRateLimit?|forgetRateLimit?: { maxCallsPerWindow?: number; windowMs?: number };| Rate-limit override for memory_forget. Also used as the fallback for setAgentRuleRateLimitwhen that field is omitted. | |setAgentRuleRateLimit?|setAgentRuleRateLimit?: { maxCallsPerWindow?: number; windowMs?: number };| Rate-limit override for memory_set_agent_rule. Falls back to forgetRateLimitwhen omitted; allows hosts to give rule-writes a larger budget than destructive forgets without sharing one knob. | |forbiddenEntityTypes?|forbiddenEntityTypes?: ReadonlyArray<string>;| Entity types the agent must NOT create viamemory_upsert_entity. When set, such upserts are rejected and the tool description drops those types' guidance (see MemoryToolDeps.forbiddenEntityTypes). For host-deterministic types (e.g. event` from a calendar pipeline). Omit for no restriction. |


ModelTaskLimits interface

📍 src/core/model-execution/types.ts:9

Limits apply to one explicitly shared, process-local task.

Properties
Property Type Description
maxCalls? maxCalls?: number; -
maxTokens? maxTokens?: number; Conservative reservations use provider capacity, not estimated prompt size.
maxCostUSD? maxCostUSD?: number; Model token charges only. Requires a known conservative price bound.
deadline? deadline?: number; Absolute Unix time in milliseconds.

ModelTaskSnapshot interface

📍 src/core/model-execution/types.ts:127

Properties
Property Type Description
id id: string; -
limits limits: ModelTaskLimits; -
invocations invocations: ModelInvocationRecord[]; -
attempts attempts: ModelAttemptRecord[]; -
totals `totals: {
calls: number;
inputTokens: number;
outputTokens: number;
totalTokens: number;
cachedInputTokens: number;
reasoningTokens: number;
knownModelCostUSD: number;
unknownUsageInvocations: number;
unknownCostInvocations: number;
unknownChargeAttempts: number;
chargedTokens: number;
chargedCostUSD: number | null;

};` | - |


MongoMemoryAdapterOptions interface

📍 src/memory/adapters/mongo/MongoMemoryAdapter.ts:81

Properties
Property Type Description
entities entities: IMongoCollectionLike&lt;IEntity&gt;; -
facts facts: IMongoCollectionLike&lt;IFact&gt;; -
factsArchive? factsArchive?: IMongoCollectionLike&lt;IFact&gt;; Optional archive collection for facts. When provided, the adapter
switches to move-on-archive semantics:
  • updateFact(id, {archived: true}, scope) moves the doc from facts to factsArchive (stamping archivedAt) instead of setting archived: true in place.
  • updateFact(id, {archived: false}, scope) (restoreFact) moves the doc back from factsArchive to facts.
  • getFact(id) falls back to factsArchive when the id isn't in facts — supersession-chain walks and audit reads of archived facts keep working.
  • findFacts(filter) with filter.archived === true queries factsArchive; otherwise queries facts (which stays live-only).
  • countFacts(...) uses the same routing.

Benefits at scale: the live (primary) collection stays small even when archive history is large; indexes don't carry archived rows; the archived: false / $exists: false read filter becomes redundant on the primary collection (every doc there is live by construction) and can be dropped by callers.

When omitted, behaviour is unchanged — archived docs stay in the primary collection with archived: true (legacy mode). | | disableWorldVisibility? | disableWorldVisibility?: boolean; | When true, scopeToFilter omits the "world" branch (groupId: {$ne: caller.groupId} ∧ permissions.world !== 'none') from the produced read filter. Use this in deployments where cross-tenant world-readable visibility is not used — the $ne predicate is fundamentally not sargable and forces a wide collection scan on every branch-equipped query (subject lookups, identifier lookups, traversal), dwarfing any potential benefit when no docs actually carry permissions.world: 'read'. Default false (backwards-compatible).

Security note: enabling this changes the visibility contract. Any record carrying permissions.world: 'read' becomes invisible to cross-group callers — silently from the caller's perspective. The adapter emits a one-time console.warn at construction so the trade-off isn't fully silent operationally; pass a logger to route the warning through your own infrastructure instead. | | logger? | logger?: { warn(msg: string): void }; | Optional logger used for boot-time advisories (currently: the disableWorldVisibility security trade-off warning). Defaults to console.warn. Pass your app's logger to redirect into structured logging. | | useNativeGraphLookup? | useNativeGraphLookup?: boolean; | When true AND facts.aggregate is present, traverse() uses a single native $graphLookup pipeline per direction instead of iterative BFS. Default: false. | | vectorIndexName? | vectorIndexName?: string; | When set AND facts.aggregate is present, semanticSearch() uses Atlas Vector Search via $vectorSearch against this index name. Otherwise falls back to cursor-scan cosine. | | entityVectorIndexName? | entityVectorIndexName?: string; | When set AND entities.aggregate is present, semanticSearchEntities() uses Atlas Vector Search via $vectorSearch against this index name. Otherwise falls back to cursor-scan cosine over entity.identityEmbedding.

Index is NOT auto-created by ensureIndexes() (which only handles regular b-tree indexes). Create it via ensureVectorSearchIndexes() (programmatic, requires mongodb node driver v6.6+ + Atlas Server v6.0.11+) or via the Atlas UI / admin API. See ensureVectorSearchIndexes JSDoc for details. | | entityContentVectorIndexName? | entityContentVectorIndexName?: string; | Atlas Vector Search index for entity.contentEmbedding — used when semanticSearchEntities is called with opts.embeddingField:'content' (currently consumed by MemorySystem.searchDocuments). Distinct from entityVectorIndexName so identity matches never leak into content search and vice versa. Same auto-creation rules as the identity index: not built by ensureIndexes(); create via ensureVectorSearchIndexes(). | | vectorCandidateMultiplier? | vectorCandidateMultiplier?: number; | Number of vector candidates to ask Atlas Vector Search to consider before returning topK. Used by both semanticSearch (facts) and semanticSearchEntities when the corresponding index name is set. Default: topK * 10. | | factsCollectionName? | factsCollectionName?: string; | Name of the facts collection — required by $graphLookup (it needs the collection name to recurse over). If omitted, useNativeGraphLookup is disabled and iterative BFS is used instead. | | defaultPageSize? | defaultPageSize?: number; | Default page size when a caller doesn't specify limit. | | vectorIndexDrainPollMs? | vectorIndexDrainPollMs?: number; | When ensureVectorSearchIndexes must drop + recreate a drifted index, Atlas removes the dropped index asynchronously and rejects a same-name create until it has fully drained. The helper polls until the dropped index is gone before recreating. These tune that wait. Defaults: poll every 2s, give up after 120s (then fall through to create + its race handling). Lower them in tests; raise the timeout for unusually slow Atlas tiers. | | vectorIndexDrainTimeoutMs? | vectorIndexDrainTimeoutMs?: number; | - |


NewTaskSummary interface

📍 src/memory/integration/signalReconciliationPrompt.ts:50

A newly-observed/created task rendered as context (no id needed).

Properties
Property Type Description
title title: string; -
state? state?: string; -
dueAt? dueAt?: string; -
evidenceQuote? evidenceQuote?: string; -

Plan interface

📍 src/domain/entities/Task.ts:390

Execution plan - a goal with steps to achieve it

Properties
Property Type Description
id id: string; -
goal goal: string; -
context? context?: string; -
tasks tasks: Task[]; -
concurrency? concurrency?: PlanConcurrency; Concurrency settings
allowDynamicTasks allowDynamicTasks: boolean; Can agent modify the plan?
status status: PlanStatus; Plan status
suspendedReason? `suspendedReason?: {
type: 'waiting_external' | 'manual_pause' | 'error';
taskId?: string;
message?: string;

};| Why is the plan suspended? | |createdAt|createdAt: number;| Timestamps | |startedAt?|startedAt?: number;| - | |completedAt?|completedAt?: number;| - | |lastUpdatedAt|lastUpdatedAt: number;| - | |currentTaskId?|currentTaskId?: string;| For resume: which task to continue from | |metadata?|metadata?: Record<string, unknown>;` | Metadata |


PlanConcurrency interface

📍 src/domain/entities/Task.ts:374

Plan concurrency settings

Properties
Property Type Description
maxParallelTasks maxParallelTasks: number; -
strategy `strategy: 'fifo' 'priority'
failureMode? `failureMode?: 'fail-fast' 'continue'
  • 'fail-fast': Stop on first failure (Promise.all behavior) - DEFAULT
  • 'continue': Continue other tasks on failure, mark failed ones
  • 'fail-all': Wait for all to complete, then report all failures together |

PlanInput interface

📍 src/domain/entities/Task.ts:429

Input for creating a plan

Properties
Property Type Description
goal goal: string; -
context? context?: string; -
tasks tasks: TaskInput[]; -
concurrency? concurrency?: PlanConcurrency; -
allowDynamicTasks? allowDynamicTasks?: boolean; -
metadata? metadata?: Record&lt;string, unknown&gt;; -
skipCycleCheck? skipCycleCheck?: boolean; Skip dependency cycle detection (default: false)

PlanningAgentConfig interface

📍 src/capabilities/taskAgent/PlanningAgent.ts:16

PlanningAgent configuration

Properties
Property Type Description
connector `connector: string Connector;`
model model: string; Model to use for planning (can be different/cheaper than execution)
maxPlanningIterations? maxPlanningIterations?: number; Max planning iterations
planningTemperature? planningTemperature?: number; Temperature for planning (lower = more deterministic)
availableTools? availableTools?: ToolFunction[]; Tools available for the plan (used to inform planning)

RelatedTask interface

📍 src/memory/types.ts:391

Properties
Property Type Description
task task: IEntity; -
role role: string; Relationship that links this task to the subject entity
(e.g. 'assigned_to', 'reporter_of', 'project_of', 'context_of').

ResearchPlan interface

📍 src/capabilities/researchAgent/types.ts:179

Research plan for systematic research

Properties
Property Type Description
goal goal: string; Research goal/question
queries queries: ResearchQuery[]; Queries to execute
sources? sources?: string[]; Sources to use (empty = all available)
maxResultsPerQuery? maxResultsPerQuery?: number; Maximum results per query
maxTotalFindings? maxTotalFindings?: number; Maximum total findings

ResolverMemoryHooks interface

📍 src/memory/resolution/EntityResolver.ts:95

Narrow hook used by EntityResolver — lets it query + upsert without pulling in the full MemorySystem surface (keeps the resolver easy to test).

Properties
Property Type Description
store store: IMemoryStore; -
embedQuery? embedQuery?: (text: string) =&gt; Promise&lt;number[]&gt;; -
upsertEntity `upsertEntity: (
input: Partial&lt;IEntity&gt; & {
  identifiers: Identifier[];
  displayName: string;
  type: string;
},
scope: ScopeFilter,

) => Promise<{ entity: IEntity; created: boolean }>;| - | |atomicCreateOrResolve|atomicCreateOrResolve: ( input: Partial<IEntity> & { identifiers: Identifier[]; displayName: string; type: string; /** Surface + any caller-supplied aliases (used for alias accumulation on race-loss). / aliasesForMerge?: string[]; metadataMerge?: 'fillMissing' | 'overwrite'; /* Persistent multi-entity binding — written to IEntity.contextIds. */ contextIds?: EntityId[]; }, scope: ScopeFilter, ) => Promise<{ entity: IEntity; created: boolean }>;| Atomically create OR resolve by(type, normalizedDisplayName, scope), applying alias accumulation when an existing row is returned. Used by upsertBySurfacewhen resolver Tier 1-3 didn't match — replaces the naiveupsertEntitycall that raced past concurrent inserts of the same surface. SeeMemorySystem.tryAtomicCreateOrResolvefor the wiring. | |appendAliasesAndIdentifiers|appendAliasesAndIdentifiers: ( id: EntityId, aliases: string[], identifiers: Identifier[], scope: ScopeFilter, opts?: { metadata?: Record<string, unknown>; metadataMerge?: 'fillMissing' | 'overwrite'; contextIdsToUnion?: EntityId[]; }, ) => Promise<IEntity>;| Patches an existing entity with additional aliases/identifiers (no-op if already present). Whenopts.metadatais supplied, merges peropts.metadataMerge`:

  • 'fillMissing' (default): only keys absent from stored metadata are set.
  • 'overwrite': shallow-merge (incoming keys win). When opts.contextIdsToUnion is supplied, the helper unions those entity ids into IEntity.contextIds (dedupe + self-reference filter). Caller is responsible for visibility-validating the additions. |

RoutineTaskResult interface

📍 src/domain/entities/RoutineExecutionRecord.ts:46

Properties
Property Type Description
success success: boolean; -
output? output?: string; -
error? error?: string; -
validationScore? validationScore?: number; -
validationExplanation? validationExplanation?: string; -

RoutineTaskSnapshot interface

📍 src/domain/entities/RoutineExecutionRecord.ts:54

Properties
Property Type Description
taskId taskId: string; -
name name: string; -
description description: string; -
status `status: 'pending' 'blocked'
attempts attempts: number; -
maxAttempts maxAttempts: number; -
result? result?: RoutineTaskResult; -
startedAt? startedAt?: number; -
completedAt? completedAt?: number; -
controlFlowType? `controlFlowType?: 'map' 'fold'

RoutineTaskSummary interface

📍 src/core/routines/types.ts:23

Properties
Property Type Description
id readonly id: string; -
executionId? readonly executionId?: string; -
name readonly name: string; -
state `readonly state: 'pending' 'running'
verification? readonly verification?: VerificationDecision; -
references? readonly references?: readonly EvidenceReference[]; -

SerializedInContextMemoryState interface

📍 src/core/context-nextgen/plugins/InContextMemoryPluginNextGen.ts:51

Properties
Property Type Description
entries entries: InContextEntry[]; -

SerializedWorkingMemoryState interface

📍 src/core/context-nextgen/plugins/WorkingMemoryPluginNextGen.ts:50

Properties
Property Type Description
version version: number; -
entries `entries: Array<{
key: string;
description: string;
value: unknown;
scope: MemoryScope;
sizeBytes: number;
basePriority?: MemoryPriority;
pinned?: boolean;

}>;` | - |


Task interface

📍 src/domain/entities/Task.ts:297

A single unit of work

Properties
Property Type Description
id id: string; -
name name: string; -
description description: string; -
status status: TaskStatus; -
dependsOn dependsOn: string[]; Tasks that must complete before this one (task IDs)
externalDependency? externalDependency?: ExternalDependency; External dependency (if waiting on external event)
condition? condition?: TaskCondition; Condition for execution
execution? execution?: TaskExecution; Execution settings
validation? validation?: TaskValidation; Completion validation settings
suggestedTools? suggestedTools?: string[]; Tool names the LLM should prefer for this task (advisory, not enforced)
expectedOutput? expectedOutput?: string; Optional expected output description
controlFlow? controlFlow?: TaskControlFlow; Control flow: map, fold, or until (replaces normal LLM execution for this task)
result? `result?: {
success: boolean;
output?: unknown;
error?: string;
/** Validation score (0-100) if validation was performed */
validationScore?: number;
/** Explanation of validation result */
validationExplanation?: string;

};| Result after completion | |createdAt|createdAt: number;| Timestamps | |startedAt?|startedAt?: number;| - | |completedAt?|completedAt?: number;| - | |lastUpdatedAt|lastUpdatedAt: number;| - | |attempts|attempts: number;| Retry tracking | |maxAttempts|maxAttempts: number;| - | |metadata?|metadata?: Record<string, unknown>;` | Metadata for extensions |


TaskCondition interface

📍 src/domain/entities/Task.ts:61

Task condition - evaluated before execution

Properties
Property Type Description
memoryKey memoryKey: string; -
operator operator: ConditionOperator; -
value? value?: unknown; -
onFalse `onFalse: 'skip' 'fail'

TaskExecution interface

📍 src/domain/entities/Task.ts:175

Task execution settings

Properties
Property Type Description
parallel? parallel?: boolean; Can run in parallel with other parallel tasks
maxConcurrency? maxConcurrency?: number; Max concurrent if this spawns sub-work
priority? priority?: number; Priority (higher = executed first)
maxIterations? maxIterations?: number; Maximum LLM iterations (tool-call loops) per agent.run() for this task.
Prevents runaway agents. Default: 50.
raceProtection? raceProtection?: boolean; If true (default), re-check condition immediately before LLM call
to protect against race conditions when parallel tasks modify memory.
Set to false to skip re-check for performance if you know condition won't change.

TaskFailure interface

📍 src/domain/errors/AIErrors.ts:330

Task failure info for parallel execution

Properties
Property Type Description
taskId taskId: string; -
taskName taskName: string; -
error error: Error; -

TaskFoldFlow interface

📍 src/domain/entities/Task.ts:138

Fold: accumulate a result across array elements

Properties
Property Type Description
type type: 'fold'; -
source source: ControlFlowSource; Source array reference — task name, memory key, or structured ref.
tasks tasks: SubRoutineSpec; Sub-routine to run per element
initialValue initialValue: unknown; Starting accumulator value
resultKey resultKey: string; Memory key for final accumulated result
maxIterations? maxIterations?: number; Cap iterations (default: array.length, hard max: 1000)
iterationTimeoutMs? iterationTimeoutMs?: number; Timeout per sub-execution iteration in ms (default: no timeout)

TaskInput interface

📍 src/domain/entities/Task.ts:355

Input for creating a task

Properties
Property Type Description
id? id?: string; -
name name: string; -
description description: string; -
dependsOn? dependsOn?: string[]; -
externalDependency? externalDependency?: ExternalDependency; -
condition? condition?: TaskCondition; -
execution? execution?: TaskExecution; -
suggestedTools? suggestedTools?: string[]; -
validation? validation?: TaskValidation; -
expectedOutput? expectedOutput?: string; -
controlFlow? controlFlow?: TaskControlFlow; -
maxAttempts? maxAttempts?: number; -
metadata? metadata?: Record&lt;string, unknown&gt;; -

TaskMapFlow interface

📍 src/domain/entities/Task.ts:123

Map: execute a sub-routine for each element in an array

Properties
Property Type Description
type type: 'map'; -
source source: ControlFlowSource; Source array reference — task name, memory key, or structured ref.
tasks tasks: SubRoutineSpec; Sub-routine to run per element
resultKey? resultKey?: string; Memory key for collected results array
maxIterations? maxIterations?: number; Cap iterations (default: array.length, hard max: 1000)
iterationTimeoutMs? iterationTimeoutMs?: number; Timeout per sub-execution iteration in ms (default: no timeout)

TaskReconciliationOp interface

📍 src/memory/integration/ExtractionResolver.ts:154

Task reconciliation operation — the signal-reconciliation pass (a SECOND LLM pass that runs after extraction). Distinct from the fact ops above: tasks are MUTABLE entities, so reconciliation UPDATES them in place (state, narrative, dueAt, assignee) instead of the archive+create supersession used for immutable facts.

taskId MUST be one of the prior task ids passed to MemorySystem.applyReconciliationOps; hallucinated ids are rejected.

When newState moves the task into a TERMINAL state, the dispatcher stamps AI-resolution provenance onto the task metadata (see AIResolutionProvenance) so the host can distinguish "auto-resolved by AI reconciliation" from "closed by the user". reason is REQUIRED whenever newState is set.

Properties
Property Type Description
op op: 'task_update'; -
taskId taskId: EntityId; -
newState? newState?: string; New task state, e.g. `'in_progress'
narrative? narrative?: string; Refreshed task narrative / card body. Optional.
dueAt? dueAt?: string; ISO date string for a (re)scheduled due date. Optional.
assigneeId? assigneeId?: string; Reassigned owner entity id. Optional.
evidenceQuote? evidenceQuote?: string; Verbatim quote from the signal content justifying the change.
reason? reason?: string; Brief reasoning — REQUIRED when newState is set (the provenance trail).

TaskSourceRef interface

📍 src/domain/entities/Task.ts:110

Reference to a source value for control flow operations.

Properties
Property Type Description
task? task?: string; Reference the output of a named task (resolves to _task_output{name})
key? key?: string; Direct memory key lookup
path? path?: string; JSON path to extract from the resolved value (e.g., 'data.items', 'results[0].entries')

TaskStateAction interface

📍 src/core/context-nextgen/plugins/TaskStatePluginNextGen.ts:34

Properties
Property Type Description
authority authority: 'observation'; -
outcome outcome: Omit&lt;ToolExecutionOutcome, 'error'&gt;; -
confirmation? confirmation?: { status: TaskStatus; source: TaskStateSource }; Explicit host confirmation of workflow state; tool success alone never sets it.

TaskStateHistoryEntry interface

📍 src/memory/MemorySystem.ts:264

Single entry appended to task.metadata.stateHistory on every transition. No cap — retention is the caller's problem (audit systems, GDPR, archival).

Properties
Property Type Description
from `from: string undefined;`
to to: string; -
at at: Date; -
signalId? signalId?: string; -
reason? reason?: string; -

TaskStateHostDelta interface

📍 src/core/context-nextgen/plugins/TaskStatePluginNextGen.ts:64

Properties
Property Type Description
notes? notes?: TaskStateNoteInput[]; -
resolve? resolve?: string[]; -
confirmActions? confirmActions?: Array&lt;{ executionId: string; status: TaskStatus; source: TaskStateSource }&gt;; Explicit host confirmations, applied atomically before optional pruning.
prune? prune?: { noteIds?: string[]; executionIds?: string[] }; Explicit pruning after notes/resolutions/confirmations; only the final state must fit.

TaskStateNote interface

📍 src/core/context-nextgen/plugins/TaskStatePluginNextGen.ts:24

Properties
Property Type Description
authority `authority: 'host' 'proposal'
resolved? resolved?: boolean; -
supersededBy? supersededBy?: string; -

TaskStateNoteInput interface

📍 src/core/context-nextgen/plugins/TaskStatePluginNextGen.ts:15

Properties
Property Type Description
id id: string; -
category category: TaskStateCategory; -
text text: string; -
source source: TaskStateSource; -
uncertainty? uncertainty?: string; -
supersedes? supersedes?: string; -
conflictsWith? conflictsWith?: string[]; -

TaskStatePluginConfig interface

📍 src/core/context-nextgen/plugins/TaskStatePluginNextGen.ts:51

Properties
Property Type Description
scope scope: EvidenceScope; -
taskId taskId: string; -
association? association?: string; -
lifecycle? lifecycle?: TaskStateLifecycleBinding; -
maxEntries? maxEntries?: number; Combined notes/actions; default 100. No automatic eviction.
maxPromptTokens? maxPromptTokens?: number; Full protected prompt view; default 8000 estimated tokens.
maxSnapshotBytes? maxSnapshotBytes?: number; Strict JSON snapshot/input limit; default 256 KiB.

TaskStatesConfig interface

📍 src/memory/types.ts:1385

Task-state vocabulary configuration. Drives which states getContext surfaces as "open" in relatedTasks, and which are treated as "terminal" (done/cancelled) for side effects like auto-setting completedAt.

Library default preserves the legacy vocabulary. Apps using different lifecycles (e.g. 'proposed' | 'scheduled' | 'in_progress' | 'done') override here rather than hardcoding state strings in metadata queries.

Properties
Property Type Description
active active: string[]; States treated as "still open" — surfaced in getContext.relatedTasks.
terminal terminal: string[]; States treated as "finished" — transitions into these auto-set completedAt.

TaskStateSnapshot interface

📍 src/core/context-nextgen/plugins/TaskStatePluginNextGen.ts:40

Properties
Property Type Description
version version: 1; -
scope scope: EvidenceScope; -
taskId taskId: string; -
association? association?: string; Optional host-owned session/work association, checked on restoration.
revision revision: number; -
notes notes: TaskStateNote[]; -
actions actions: TaskStateAction[]; -
lifecycle? lifecycle?: TaskStateLifecycleView; -

TaskStateSource interface

📍 src/core/context-nextgen/plugins/TaskStatePluginNextGen.ts:14

Properties
Property Type Description
label label: string; -
turnId? turnId?: string; -
evidence? evidence?: EvidenceReference -

TaskUntilFlow interface

📍 src/domain/entities/Task.ts:155

Until: repeat a sub-routine until a condition is met

Properties
Property Type Description
type type: 'until'; -
tasks tasks: SubRoutineSpec; Sub-routine to run each iteration
condition condition: TaskCondition; Checked AFTER each iteration (reuses existing TaskCondition type)
maxIterations? maxIterations?: number; Maximum iterations. Default: 1. Hard cap: 1000.
iterationKey? iterationKey?: string; Optional ICM key for current iteration index
iterationTimeoutMs? iterationTimeoutMs?: number; Timeout per sub-execution iteration in ms (default: no timeout)

TaskValidation interface

📍 src/domain/entities/Task.ts:208

Task completion validation settings

Used to verify that a task actually achieved its goal before marking it complete. Supports multiple validation approaches:

  • Programmatic checks (memory keys, hooks)
  • LLM self-reflection with completeness scoring
  • Natural language criteria evaluation
Properties
Property Type Description
completionCriteria? completionCriteria?: string[]; Natural language completion criteria.
These are evaluated by LLM self-reflection to determine if the task is complete.
Examples:
  • "The response contains at least 3 specific examples"
  • "User's email has been validated and stored in memory"
  • "All requested data fields are present in the output"

This is the RECOMMENDED approach for flexible, intelligent validation. | | minCompletionScore? | minCompletionScore?: number; | Minimum completeness score (0-100) to consider task successful. LLM self-reflection returns a score; if below this threshold:

  • If requireUserApproval is set, ask user
  • Otherwise, follow the mode setting (strict = fail, warn = continue) Default: 80 | | requireUserApproval? | requireUserApproval?: 'never' | 'uncertain' | 'always'; | When to require user approval:
  • 'never': Never ask user, use automated decision (default)
  • 'uncertain': Ask user when score is between minCompletionScore and minCompletionScore + 15
  • 'always': Always ask user to confirm task completion | | requiredMemoryKeys? | requiredMemoryKeys?: string[]; | Memory keys that must exist after task completion. If the task should store data in memory, list the required keys here. This is a hard requirement checked BEFORE LLM reflection. | | customValidator? | customValidator?: string; | Custom validation function name (registered via validateTask hook). The hook will be called with this identifier to dispatch to the right validator. Runs AFTER LLM reflection, can override the result. | | mode? | mode?: 'strict' | 'warn'; | Validation mode:
  • 'strict': Validation failure marks task as failed (default)
  • 'warn': Validation failure logs warning but task still completes | | skipReflection? | skipReflection?: boolean; | Skip LLM self-reflection validation. LLM validation is opt-in: set to false to enable it (requires completionCriteria). Default: undefined (treated as true — validation auto-passes). |

TaskValidationResult interface

📍 src/domain/entities/Task.ts:270

Result of task validation (returned by LLM reflection)

Properties
Property Type Description
isComplete isComplete: boolean; Whether the task is considered complete
completionScore completionScore: number; Completeness score from 0-100
explanation explanation: string; LLM's explanation of why the task is/isn't complete
criteriaResults? `criteriaResults?: Array<{
criterion: string;
met: boolean;
evidence?: string;

}>;| Per-criterion evaluation results | |requiresUserApproval|requiresUserApproval: boolean;| Whether user approval is needed | |approvalReason?|approvalReason?: string;` | Reason for requiring user approval |


TransitionTaskStateOptions interface

📍 src/memory/MemorySystem.ts:272

Properties
Property Type Description
signalId? signalId?: string; Stable audit pointer — typically the ingest signal id. Flows into the history entry AND the written fact.
at? at?: Date; When the transition happened. Defaults to now.
reason? reason?: string; Free-form audit note. Stored in the history entry.
validate? `validate?: 'strict' 'warn'
  • 'warn' (default): any transition allowed; out-of-matrix transitions route through onError and proceed.
  • 'strict': out-of-matrix transitions throw InvalidTaskTransitionError — the metadata write is skipped.
  • 'none': no validation, no warnings. | | transitions? | transitions?: Record&lt;string, string[]&gt;; | Explicit allowed transitions: { from: [allowed, to, states] }. When omitted, every transition is allowed (with a warning for duplicates in 'warn'). Keys include '__initial' for transitions into a first-time state. |

TransitionTaskStateResult interface

📍 src/memory/MemorySystem.ts:294

Properties
Property Type Description
task task: IEntity; -
rejected? rejected?: string; Set when validate='strict' rejected the transition.

WorkingMemoryAccess interface

📍 src/domain/interfaces/IToolContext.ts:26

Limited memory access for tools

This interface is designed to work with all agent types:

  • Basic agents: Use simple scopes ('session', 'persistent')
  • TaskAgent: Use task-aware scopes ({ type: 'task', taskIds: [...] })
  • UniversalAgent: Switches between simple and task-aware based on mode
Methods

get()

typescript
get(key: string): Promise&lt;unknown&gt;;

Parameters:

  • key: string

Returns: Promise&lt;unknown&gt;

set()

Store a value in memory

typescript
set(
    key: string,
    description: string,
    value: unknown,
    options?: {
      /** Scope determines lifecycle - defaults to 'session' */
      scope?: MemoryScope;
      /** Base priority for eviction ordering */
      priority?: MemoryPriority;
      /** If true, entry is never evicted */
      pinned?: boolean;
    }
  ): Promise&lt;void&gt;;

Parameters:

  • key: string
  • description: string
  • value: unknown
  • options: { scope?: MemoryScope | undefined; priority?: MemoryPriority | undefined; pinned?: boolean | undefined; } | undefined (optional)

Returns: Promise&lt;void&gt;

delete()

typescript
delete(key: string): Promise&lt;void&gt;;

Parameters:

  • key: string

Returns: Promise&lt;void&gt;

has()

typescript
has(key: string): Promise&lt;boolean&gt;;

Parameters:

  • key: string

Returns: Promise&lt;boolean&gt;

list()

List all memory entries Returns key, description, and computed priority info

typescript
list(): Promise&lt;
    Array&lt;{
      key: string;
      description: string;
      effectivePriority?: MemoryPriority;
      pinned?: boolean;
    }&gt;
  &gt;;

Returns: Promise&lt;{ key: string; description: string; effectivePriority?: MemoryPriority | undefined; pinned?: boolean | undefined; }[]&gt;


WorkingMemoryConfig interface

📍 src/domain/entities/Memory.ts:424

Configuration for working memory

Properties
Property Type Description
maxSizeBytes? maxSizeBytes?: number; Max memory size in bytes. If not set, calculated from model context
maxIndexEntries? maxIndexEntries?: number; Max number of entries in the memory index. Excess entries are auto-evicted via LRU. Default: 30
descriptionMaxLength descriptionMaxLength: number; Max description length
softLimitPercent softLimitPercent: number; Percentage at which to warn agent
contextAllocationPercent contextAllocationPercent: number; Percentage of model context to allocate to memory

WorkingMemoryEvents interface

📍 src/capabilities/taskAgent/WorkingMemory.ts:83

Properties
Property Type Description
stored stored: { key: string; description: string; scope: MemoryScope }; -
retrieved retrieved: { key: string }; -
deleted deleted: { key: string }; -
evicted `evicted: { keys: string[]; reason: 'lru' 'size'
limit_warning limit_warning: { utilizationPercent: number }; -
stale_entries stale_entries: { entries: StaleEntryInfo[] }; -

WorkingMemoryPluginConfig interface

📍 src/core/context-nextgen/plugins/WorkingMemoryPluginNextGen.ts:65

Properties
Property Type Description
config? config?: WorkingMemoryConfig; Memory configuration
storage? storage?: IMemoryStorage; Storage backend (default: InMemoryStorage)
priorityCalculator? priorityCalculator?: PriorityCalculator; Priority calculator (default: staticPriorityCalculator)

ControlFlowSource type

📍 src/domain/entities/Task.ts:120

Source can be a simple key string (legacy) or a structured reference.

typescript
type ControlFlowSource = string | TaskSourceRef

EvictionStrategy type

📍 src/capabilities/taskAgent/WorkingMemory.ts:73

Eviction strategy type

typescript
type EvictionStrategy = 'lru' | 'size'

MemoryPriority type

📍 src/domain/entities/Memory.ts:110

Priority determines eviction order (lower priority evicted first)

  • critical: Never evicted (pinned, or actively in use)
  • high: Important data, evicted only when necessary
  • normal: Default priority
  • low: Candidate for eviction (stale data, completed task data)
typescript
type MemoryPriority = 'critical' | 'high' | 'normal' | 'low'

MemoryScope type

📍 src/domain/entities/Memory.ts:33

Union type - memory system accepts both

typescript
type MemoryScope = SimpleScope | TaskAwareScope

MemorySystemWithConnectorsConfig type

📍 src/memory/integration/createMemorySystemWithConnectors.ts:24

typescript
type MemorySystemWithConnectorsConfig = Omit&lt;
  MemorySystemConfig,
  'embedder' | 'profileGenerator'
&gt; & {
  connectors?: MemoryConnectorsConfig;
}

PlanStatus type

📍 src/domain/entities/Task.ts:38

Plan status

typescript
type PlanStatus = | 'pending'
  | 'running'
  | 'suspended'
  | 'completed'
  | 'failed'
  | 'cancelled'

SimpleScope type

📍 src/domain/entities/Memory.ts:20

Memory entities for WorkingMemory

This module provides a GENERIC memory system that works across all agent types:

  • Basic Agent: Simple session/persistent scoping with static priority
  • TaskAgent: Task-aware scoping with dynamic priority based on task states
  • UniversalAgent: Mode-aware, switches strategy based on current mode

The key abstraction is PriorityCalculator - a pluggable strategy that determines entry priority for eviction decisions.

typescript
type SimpleScope = 'session' | 'persistent'

SubRoutineSpec type

📍 src/domain/entities/Task.ts:107

Sub-routine specification: either inline tasks or a full RoutineDefinition

typescript
type SubRoutineSpec = TaskInput[] | RoutineDefinition

TaskAwareScope type

📍 src/domain/entities/Memory.ts:25

Task-aware scope for TaskAgent/UniversalAgent

typescript
type TaskAwareScope = | { type: 'task'; taskIds: string[] }   // Needed for specific task(s)
  | { type: 'plan' }                       // Needed throughout plan execution
  | { type: 'persistent' }

TaskControlFlow type

📍 src/domain/entities/Task.ts:170

Union of all control flow types

typescript
type TaskControlFlow = TaskMapFlow | TaskFoldFlow | TaskUntilFlow

TaskStateCategory type

📍 src/core/context-nextgen/plugins/TaskStatePluginNextGen.ts:13

typescript
type TaskStateCategory = 'objective' | 'constraint' | 'decision' | 'question' | 'artifact'

TaskStateLifecycleBinding type

📍 src/core/context-nextgen/plugins/TaskStatePluginNextGen.ts:29

typescript
type TaskStateLifecycleBinding = { kind: 'task' | 'routine' | 'memory'; id: string }

TaskStateLifecycleView type

📍 src/core/context-nextgen/plugins/TaskStatePluginNextGen.ts:30

typescript
type TaskStateLifecycleView = | { kind: 'task'; id: string; status?: TaskStatus }
  | { kind: 'routine'; id: string; status?: RoutineExecutionStatus }
  | { kind: 'memory'; id: string; state?: string | null }

TaskStatus type

📍 src/domain/entities/Task.ts:13

Task status lifecycle

typescript
type TaskStatus = | 'pending'           // Not started
  | 'blocked'           // Dependencies not met
  | 'in_progress'       // Currently executing
  | 'waiting_external'  // Waiting on external event
  | 'completed'         // Successfully finished
  | 'failed'            // Failed after max retries
  | 'skipped'           // Skipped (condition not met)
  | 'cancelled'

TaskStatusForMemory type

📍 src/domain/entities/Memory.ts:219

Task status values for priority calculation

typescript
type TaskStatusForMemory = 'pending' | 'in_progress' | 'completed' | 'failed' | 'skipped' | 'cancelled'

calculateEntrySize function

📍 src/domain/entities/Memory.ts:539

Calculate the size of a value in bytes (JSON serialization) Uses Buffer.byteLength for accurate UTF-8 byte count

typescript
export function calculateEntrySize(value: unknown): number

canTaskExecute function

📍 src/domain/entities/Task.ts:548

Check if a task can be executed (dependencies met, status is pending)

typescript
export function canTaskExecute(task: Task, allTasks: Task[]): boolean

createInContextMemoryContributor function

📍 src/core/context-nextgen/assembly.ts:204

Optional adapter: select whiteboard entries without deleting their stored source.

typescript
export function createInContextMemoryContributor(plugin: InContextMemoryPluginNextGen): ContextContributor

createMemoryReadTools function

📍 src/tools/memory/index.ts:146

Read-only retrieval tools — no memory writes performed.

typescript
export function createMemoryReadTools(args: CreateMemoryToolsArgs): ToolFunction[]

createMemorySystemWithConnectors function

📍 src/memory/integration/createMemorySystemWithConnectors.ts:31

typescript
export function createMemorySystemWithConnectors(
  config: MemorySystemWithConnectorsConfig,
): MemorySystem

createMemoryTools function

📍 src/tools/memory/index.ts:176

All 12 memory tools (6 read + 6 write). Convenience factory — most callers should prefer createMemoryReadTools / createMemoryWriteTools separately so read agents don't carry the write-tool schema overhead.

typescript
export function createMemoryTools(args: CreateMemoryToolsArgs): ToolFunction[]

createMemoryWriteTools function

📍 src/tools/memory/index.ts:159

Write-side memory tools — mutate entities and facts.

typescript
export function createMemoryWriteTools(args: CreateMemoryToolsArgs): ToolFunction[]

createPlan function

📍 src/domain/entities/Task.ts:481

Create a plan with tasks

typescript
export function createPlan(input: PlanInput): Plan

createTask function

📍 src/domain/entities/Task.ts:452

Create a task with defaults

typescript
export function createTask(input: TaskInput): Task

createTaskSnapshots function

📍 src/domain/entities/RoutineExecutionRecord.ts:102

Create initial task snapshots from a routine definition.

typescript
export function createTaskSnapshots(definition: RoutineDefinition): RoutineTaskSnapshot[]

detectDependencyCycle function

📍 src/domain/entities/Task.ts:755

Detect dependency cycles in tasks using depth-first search

typescript
export function detectDependencyCycle(tasks: Task[]): string[] | null

evaluateCondition function

📍 src/domain/entities/Task.ts:612

Evaluate a task condition against memory

typescript
export async function evaluateCondition(
  condition: TaskCondition,
  memory: ConditionMemoryAccess
): Promise&lt;boolean&gt;

forPlan function

📍 src/domain/entities/Memory.ts:487

Create a plan-scoped memory entry input

typescript
export function forPlan(
  key: string,
  description: string,
  value: unknown,
  options?: { priority?: MemoryPriority; pinned?: boolean }
): MemoryEntryInput

forTasks function

📍 src/domain/entities/Memory.ts:467

Create a task-scoped memory entry input

typescript
export function forTasks(
  key: string,
  description: string,
  value: unknown,
  taskIds: string[],
  options?: { priority?: MemoryPriority; pinned?: boolean }
): MemoryEntryInput

generateSimplePlan function

📍 src/capabilities/taskAgent/PlanningAgent.ts:438

Simple plan generation without tools (fallback)

typescript
export async function generateSimplePlan(
  goal: string,
  context?: string
): Promise&lt;Plan&gt;

getNextExecutableTasks function

📍 src/domain/entities/Task.ts:570

Get the next tasks that can be executed

typescript
export function getNextExecutableTasks(plan: Plan): Task[]

getTaskDependencies function

📍 src/domain/entities/Task.ts:709

Get the dependency tasks for a task

typescript
export function getTaskDependencies(task: Task, allTasks: Task[]): Task[]

isSimpleScope function

📍 src/domain/entities/Memory.ts:45

Type guard: is this a simple scope?

typescript
export function isSimpleScope(scope: MemoryScope): scope is SimpleScope

isTaskAwareScope function

📍 src/domain/entities/Memory.ts:38

Type guard: is this a task-aware scope?

typescript
export function isTaskAwareScope(scope: MemoryScope): scope is TaskAwareScope

isTaskBlocked function

📍 src/domain/entities/Task.ts:688

Check if a task is blocked by dependencies

typescript
export function isTaskBlocked(task: Task, allTasks: Task[]): boolean

isTerminalMemoryStatus function

📍 src/domain/entities/Memory.ts:229

Check if a task status is terminal (task will not progress further)

typescript
export function isTerminalMemoryStatus(status: TaskStatusForMemory): boolean

isTerminalStatus function

📍 src/domain/entities/Task.ts:31

Check if a task status is terminal (task will not progress further)

typescript
export function isTerminalStatus(status: TaskStatus): boolean

resolveDependencies function

📍 src/domain/entities/Task.ts:723

Resolve task name dependencies to task IDs Modifies taskInputs in place

typescript
export function resolveDependencies(taskInputs: TaskInput[], tasks: Task[]): void

scopeEquals function

📍 src/domain/entities/Memory.ts:53

Compare two scopes for equality Handles both simple scopes (string comparison) and task-aware scopes (deep comparison)

typescript
export function scopeEquals(a: MemoryScope, b: MemoryScope): boolean

scopeMatches function

📍 src/domain/entities/Memory.ts:83

Check if a scope matches a filter scope More flexible than scopeEquals - supports partial matching for task scopes

typescript
export function scopeMatches(entryScope: MemoryScope, filterScope: MemoryScope): boolean

updateTaskStatus function

📍 src/domain/entities/Task.ts:660

Update task status and timestamps

typescript
export function updateTaskStatus(task: Task, status: TaskStatus): Task

DEFAULT_CHECKPOINT_STRATEGY const

📍 src/capabilities/taskAgent/CheckpointManager.ts:25

Properties
Property Type Description
afterToolCalls 1 -
afterLLMCalls 1 -
intervalMs 30000 -
beforeExternalWait true -
mode 'async' -

DEFAULT_MEMORY_CONFIG const

📍 src/domain/entities/Memory.ts:506

Default configuration values

Properties
Property Type Description
maxSizeBytes 25 * 1024 * 1024 -
maxIndexEntries 30 -
descriptionMaxLength 500 -
softLimitPercent 80 -
contextAllocationPercent 20 -

MEMORY_PRIORITY_VALUES const

📍 src/domain/entities/Memory.ts:115

Priority values for comparison (higher = more important, less likely to evict)

Properties
Property Type Description
critical 4 -
high 3 -
normal 2 -
low 1 -

Documentation snapshot · 2026-11-02Suggest a correction ↗

Search documentation

Type to search the v2 documentation.