Skip to main content

Temporal Reasoning

Temporal Reasoning enables WASP to understand how things have changed over time — not just what the current state is, but how it got there and what trends suggest about the future.

Overview

The TemporalReasoner (src/memory/temporal.py) provides:

  1. Extraction — rule-based extraction of temporal data from conversation text
  2. Storage — writes to world_timeline for historical tracking
  3. Insights — generates [TEMPORAL INSIGHTS] block for the system prompt
  4. Change detection — identifies when entities have meaningfully changed state

Temporal Extraction

After every message, extract_from_text() scans for:

Price Mentions

"BTC went up to $68,000 today"
→ entity=BTC, value=68000, observation_type=price

State Changes

"I finished the project yesterday"
→ entity=project, state=completed, observation_type=state

Relative Time References

"last week the server was at 80% CPU"
→ entity=server_cpu, value=80%, observation_type=metric, timeref=last_week

Contamination Guards

The extractor uses _CONTAMINATION_GUARDS — a list of patterns that indicate garbage text which should not be extracted:

_CONTAMINATION_GUARDS = [
r"^\s*\"", # Starts with quote (JSON artifact)
r"lament.*inconvenientes", # Error message artifacts
r"technically.*problems", # Error message artifacts
...
]

Any text matching a guard is skipped entirely.

Context Injection

The _temporal_insights() function in build_context():

  1. Reads recent world_timeline entries (last 24 hours)
  2. Groups by entity
  3. Generates trend descriptions
[TEMPORAL INSIGHTS]
BTC: $67,663 (stable, -0.99% from yesterday's $68,337)
ETH: $1,950 (stable, -1.68% from yesterday's $1,983)
Last observed: 2 hours ago

Token efficiency: When the [TEMPORAL INSIGHTS] block is present, the world_model_block (which covers the same entities) is suppressed to avoid duplication.

Get Entity History

from src.memory.temporal import get_entity_history

history = await get_entity_history(entity="BTC", hours=24, session=session)
# Returns list of (timestamp, value) pairs

Detect Change

from src.memory.temporal import detect_change

change = await detect_change(entity="BTC", session=session)
# Returns: {"changed": True, "from": 68000, "to": 67663, "pct": -0.99, "direction": "down"}

Configuration

SettingDefaultDescription
TEMPORAL_REASONING_ENABLEDtrueEnable/disable temporal insights
TEMPORAL_REASONING_MAX_INSIGHTS5Max entities to include in insights block

Integration with Perception

The BackgroundPerceptionJob uses temporal reasoning to decide when to notify:

change = await detect_change(entity=asset, session=session)
if abs(change["pct"]) > 4.0:
# Ask LLM: is this notable enough to notify?
notable = await assess_notability(change, context)
if notable:
await send_telegram_alert(...)

Integration with Dream Mode

During Dream Mode, DreamJob prefetches prices for all KG crypto assets and stores them in world_timeline with source=dream_prefetch. This ensures temporal data is available even if the user hasn't mentioned prices recently.

Database Schema

-- world_timeline (time series)
CREATE TABLE world_timeline (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
entity VARCHAR(255) NOT NULL,
value TEXT,
observation_type VARCHAR(50), -- price, state, metric, mention
source VARCHAR(100), -- conversation, dream_prefetch, perception_job
chat_id VARCHAR(255),
timestamp TIMESTAMPTZ DEFAULT NOW()
);

-- entity_states (current state, aggregated)
CREATE TABLE entity_states (
entity VARCHAR(255) PRIMARY KEY,
current_value TEXT,
trend VARCHAR(20), -- rising, falling, stable, unknown
change_pct FLOAT,
updated_at TIMESTAMPTZ DEFAULT NOW()
);

Querying History

# Full history for BTC
docker exec agent-postgres psql -U agent -d agent -c "
SELECT entity, value, observation_type, source, timestamp
FROM world_timeline
WHERE entity = 'BTC'
ORDER BY timestamp DESC
LIMIT 50;
"

# All current entity states
docker exec agent-postgres psql -U agent -d agent -c "
SELECT * FROM entity_states ORDER BY updated_at DESC;
"