For the complete documentation index, see llms.txt. This page is also available as Markdown.

Properties

Version: 6.2.0

Overview

Properties are EDDI's primary mechanism for storing and retrieving state within and across conversations. They are key-value pairs that can be set by agent configuration, extracted from API responses, or written by LLM tools — and they're accessible in every template (system prompts, HTTP call bodies, output templates, property instructions).

Properties are the glue that connects the pipeline's processing steps with persistent user state. Understanding how they work is essential for building stateful agents.

Key Concepts

What Properties Are

A property has:

  • Name (key): The identifier used to access the property (e.g., preferred_language, company_name)

  • Value: Can be a String, Integer, Float, Map, List, or Boolean

  • Scope: How long the property lives

  • Visibility (v6): Who can see the property

Property vs Context vs Memory

Mechanism
Source
Lifetime
Access Pattern

Properties

Agent-set (via PropertySetter, LLM tools)

Configurable (step → longTerm)

{properties.key}

Context

Your application (passed per request)

Per request

{context.key}

Memory

Pipeline (each task writes data)

Per step (current turn's data)

{memory.current.key}

Use properties when the agent needs to remember something. Use context when your application injects something. Use memory when you need data from the current or previous pipeline step.


Scopes

Properties support four scopes that control their lifetime:

Scope
Lifetime
Persistence
Use Case

step

Current conversation turn only

Not persisted

Temporary data needed only for this response

conversation

Entire conversation session

Persisted in conversation memory

User preferences within a session, extracted entities

longTerm

Across conversations

Persisted in user property store

User profile data, preferences that should survive between sessions

secret

Across conversations (encrypted)

Persisted via SecretsVault

API keys, tokens, sensitive credentials

Choosing the Right Scope


Visibility (v6)

Properties also have a visibility dimension that controls which agents can see them:

Visibility
Who sees it
Use Case

self (default)

Only the owning agent

Agent-specific preferences, internal state

group

All agents in the same group conversation

Shared context in multi-agent orchestration

global

All agents for this user

Cross-agent user preferences (e.g., language, timezone)

Visibility is orthogonal to scope — a property can be longTerm + self (persists across sessions, visible only to the owning agent) or longTerm + global (persists and visible to all agents).


Setting Properties

Via PropertySetter Configuration (JSON)

The PropertySetter task (ai.labs.property) sets properties based on triggered actions:

When the greet_user action fires:

  1. greeted is set to "true" for this conversation session

  2. preferred_language is set from the input context and persisted across all conversations and agents

Via Pre/Post Request Instructions

Properties can be set before or after any lifecycle task (HTTP calls, LLM calls):

Via LLM Tools (Agent-Driven)

When enableMemoryTools is enabled in the agent configuration, the LLM can set properties using built-in memory tools:

See Persistent User Memory for full details on the LLM memory tools, visibility scoping, and Dream consolidation.


Accessing Properties in Templates

Properties are available in all templates via the properties namespace.

⚠️ properties exposes raw values, not Property objects. MemoryItemConverter.convert() puts ConversationProperties.toMap() into the template context, and toMap() returns the unwrapped Java value that was stored (String, Integer, Float, Boolean, List, Map) — the Property wrapper never reaches the template. Use {properties.key} directly. A .valueString / .valueInt / … suffix resolves against the raw value (a String has no valueString property) and fails at render time. The valueString, valueInt, … names are write-side field names of the JSON property-setter config only. AGENTS.md §5.1 is the authoritative reference for the template data model.

In Output Templates

In System Prompts (LLM)

In HTTP Call Bodies

Reading the Different Value Types

The property-setter config picks the value type by which value* field you write (valueString, valueInt, valueFloat, valueObject, valueList, valueBoolean). In templates, all of them are read the same way — through the property name:

Written as
Read in a template
Example

valueString

{properties.name}

Hello {properties.name}

valueInt

{properties.age}

You are {properties.age}

valueFloat

{properties.score}

Score: {properties.score}

valueObject

{properties.profile.<field>}

{properties.profile.email}

valueList

{properties.tags}

{#for item in properties.tags}...{/for}

valueBoolean

{properties.isPremium}

{#if properties.isPremium}...{/if}


Property Lifecycle

Properties are managed by Conversation.java at session boundaries — NOT by pipeline tasks.

1. Conversation Init

Recall order (most_recent or most_accessed) and the maximum number of recalled entries come from the agent's userMemoryConfig. The documented defaults are most_recent ordering and 50 entries — the field defaults of AgentConfiguration.UserMemoryConfig, which apply as soon as the agent declares a userMemoryConfig block, however small.

Known inconsistency: an agent with no userMemoryConfig block at all falls back to a separate hard-coded default in Conversation (DEFAULT_MAX_RECALL_ENTRIES = 1000) rather than to the 50 above, so the effective cap silently changes by a factor of 20 depending on whether the block is present. Treat 50 as the intended default and set maxRecallEntries explicitly if the number matters to you; unifying the two constants is tracked as a code fix.

2. Pipeline Execution

3. Conversation Teardown

Key insight: Persistent state is a session concern handled at init/teardown — NOT in the pipeline. This means properties "just work" without any task ordering dependencies.

Storage: In v6, all persistent properties are stored in the unified usermemories collection (MongoDB) or usermemories table (PostgreSQL). The legacy properties collection has been removed. See Persistent User Memory for the full unified memory model.


Secret Properties

Properties with scope=secret are automatically handled by the SecretsVault:

  1. During pipeline execution, the secret value is available in memory normally

  2. At teardown, the value is encrypted and stored in SecretsVault

  3. The in-memory property value is scrubbed (replaced with a vault reference)

  4. On next conversation init, the value is loaded from the vault and decrypted

See Secrets Vault for full documentation.


Best Practices

1. Use Appropriate Scopes

2. Use fromObjectPath for Extraction

Instead of storing entire API responses, extract only what you need:

3. Use Visibility for Multi-Agent Scenarios

4. Naming Conventions

  • Use snake_case for property names

  • Use descriptive, specific names (user_preferred_timezone not tz)

  • Prefix agent-specific properties with the agent's domain (support_ticket_id, onboarding_step)


Last updated

Was this helpful?