Skip to content

Entry ​

Apeira stores everything as append-only entries. This page covers the entry model: the core entry types, how to build entries, custom entry types, and the storage contract.

AgentEntry ​

Every item stored by Apeira is an AgentEntry:

ts
interface AgentEntry<T extends keyof AgentCustomEntry = keyof AgentCustomEntry> {
  data: AgentCustomEntry[T]
  id: string
  parentId?: string
  timestamp: number
  type: T
}

Every entry has:

  • id – a unique identifier (crypto.randomUUID() by default).
  • type – the entry kind, e.g. 'input', 'state', 'event'.
  • data – the payload, typed by type.
  • timestamp – creation time in milliseconds. (Date.now() by default)
  • parentId – optional pointer used by sessions and semantic entries to build trees.

Core entry types ​

input ​

input entries store messages, tool calls, and model outputs that are passed to the runner.

ts
import { 
entry
,
toAgentInput
,
user
} from '@apeira/core'
const
e
=
entry
('input',
user
('Hello.'))
const
inputs
=
toAgentInput
([
e
])

See Input for the input types and helpers.

state ​

state entries store snapshots of agent.state. The latest state entry is restored on init().

ts
import { 
entry
} from '@apeira/core'
const
e
=
entry
('state', {
userName
: 'Alice' })

See State for managing state.

event ​

event entries store events emitted with agent.emit(..., { save: true }). They are typically used for audit trails or session tracking.

ts
import { 
entry
} from '@apeira/core'
const
e
=
entry
('event', {
turnId
:
crypto
.
randomUUID
(),
type
: 'agent.reset',
})

Helpers ​

  • entry(type, data) – creates an AgentEntry with a generated id and timestamp.
  • toAgentInput(entries) – filters an array of entries to only input entries and returns their data.
ts
import { 
entry
,
toAgentInput
,
user
} from '@apeira/core'
const
inputEntry
=
entry
('input',
user
('Hello.'))
const
inputs
=
toAgentInput
([
inputEntry
])

How Apeira uses entries ​

  1. Initialization – if storage has no input entries, Apeira writes initialInput.
  2. State restore – the latest state entry is loaded into agent.state.
  3. Turn start – Apeira reads entries, transforms them through plugins, and converts them to model input with toAgentInput().
  4. Turn success – new inputs and model outputs are appended as input entries.
  5. Reset – storage is cleared and initialInput / initialState are restored.

Custom entry types ​

Plugins can add custom entry types by extending AgentCustomEntry:

ts
import type { AgentCustomEntry } from '@apeira/core'

declare module '@apeira/core' {
  interface AgentCustomEntry {
    'my-plugin/config': { value: string }
  }
}

After declaration, entry('my-plugin/config', { value: 'x' }) is fully typed. Custom entries are preserved by @apeira/session as ordinary semantic nodes.

Reading entries ​

You can read the current storage entries at any time:

ts
import { 
createAgent
,
mem
} from '@apeira/core'
import {
responses
} from '@apeira/core/responses'
const
agent
=
createAgent
({
instructions
: 'You are a helpful assistant.',
runner
:
responses
({
apiKey
:
process
.
env
.
OPENAI_API_KEY
,
baseURL
: 'https://api.openai.com/v1/',
model
: 'gpt-5.5',
}),
storage
:
mem
(),
}) const
entries
= await
agent
.
storage
.
read
()

Each entry has id, timestamp, type, and data. See Storage for choosing a storage backend.

Storage contract ​

AgentStorage only sees entries. It does not know about turns, plugins, or runners. This separation is what makes custom storage backends simple: they only need to implement append, clear, and read.