Memory¶
ConversationHistory
dataclass
¶
ConversationHistory(session_id: str, user_id: str, chatbot_id: Optional[str] = None, turns: List[ConversationTurn] = list(), created_at: datetime = datetime.now(), updated_at: datetime = datetime.now(), metadata: Dict[str, Any] = dict())
Manages conversation history for a session - replaces ConversationSession.
add_turn ¶
get_recent_turns ¶
clear_turns ¶
to_dict ¶
Serialize conversation history to dictionary.
Source code in packages/ai-parrot/src/parrot/memory/abstract.py
from_dict
classmethod
¶
Deserialize conversation history from dictionary.
Source code in packages/ai-parrot/src/parrot/memory/abstract.py
ConversationMemory ¶
ConversationMemory(debug: bool = False, *, token_counter: Optional[TokenCounter] = None, omission_store: Optional[OmissionStore] = None, normalize: bool = True, oversize_tool_tokens: int = 2000)
Bases: ABC
Abstract base class for conversation memory storage.
FEAT-525 turns add_turn into a concrete template method (the
FEAT-391 "concrete public, abstract private" pattern): every writer —
bot, ChatStorage cold tier, voice transcripts — gets Stage 0
(normalization), Stage 0.5 (token counting) and write-time oversize
offload for free. Backends implement the abstract :meth:_store_turn
only, persisting the turn and (when given) the updated
metadata["compaction"] in one write.
Initialize the memory.
| PARAMETER | DESCRIPTION |
|---|---|
debug
|
Enables verbose per-history debug logging.
TYPE:
|
token_counter
|
The counter used for Stage 0.5. Defaults to
:func:
TYPE:
|
omission_store
|
The store oversized tool outputs are offloaded
to. Backends normally pass their own default; falling back
to an :class:
TYPE:
|
normalize
|
When
TYPE:
|
oversize_tool_tokens
|
Write-time offload threshold, in tokens
(same default as :class:
TYPE:
|
Source code in packages/ai-parrot/src/parrot/memory/abstract.py
token_counter
property
¶
The Stage 0.5 token counter, resolved lazily on first use.
omission_store
property
¶
The store oversized tool outputs are offloaded to.
Backends should set self._omission_store in their own
__init__ to a store sharing their connection/root. This
fallback exists so the property never raises, but an
:class:InMemoryOmissionStore built here is unset-and-forget: it
is process-local and lost on restart.
omission_key ¶
Compose the omission-store scoping key for one session.
| PARAMETER | DESCRIPTION |
|---|---|
user_id
|
Owner of the conversation.
TYPE:
|
session_id
|
Conversation session.
TYPE:
|
chatbot_id
|
Agent attribution;
TYPE:
|
| RETURNS | DESCRIPTION |
|---|---|
str
|
|
Source code in packages/ai-parrot/src/parrot/memory/abstract.py
create_history
abstractmethod
async
¶
create_history(user_id: str, session_id: str, metadata: Optional[Dict[str, Any]] = None, chatbot_id: Optional[str] = None) -> ConversationHistory
Create a new conversation history.
Source code in packages/ai-parrot/src/parrot/memory/abstract.py
get_history
abstractmethod
async
¶
update_history
abstractmethod
async
¶
add_turn
async
¶
add_turn(user_id: str, session_id: str, turn: ConversationTurn, chatbot_id: Optional[str] = None, *, compaction: Optional[CompactionCommit] = None) -> None
Persist one turn: normalize, count, offload oversized outputs, write once.
Concrete template method (FEAT-525): normalizes (Stage 0, unless
normalize=False), counts tokens (Stage 0.5, always-on),
offloads any tool output above oversize_tool_tokens to the
omission store with a short preview left in the turn, then
delegates the single backend write to :meth:_store_turn. When
compaction is given, folds it into the persisted
metadata["compaction"] state (calibration EWMA, boundary,
stage2_needed) in the same write.
| PARAMETER | DESCRIPTION |
|---|---|
user_id
|
Owner of the conversation.
TYPE:
|
session_id
|
Conversation session.
TYPE:
|
turn
|
The turn to persist. Not mutated when
TYPE:
|
chatbot_id
|
Agent attribution.
TYPE:
|
compaction
|
The bot's commit for this round, or
TYPE:
|
Source code in packages/ai-parrot/src/parrot/memory/abstract.py
report_usage
async
¶
report_usage(user_id: str, session_id: str, *, estimated_prompt_tokens: int, provider_prompt_tokens: Optional[int], chatbot_id: Optional[str] = None) -> None
Fold one (estimate, provider) observation into the calibration state, without writing a turn.
Standalone counterpart to the calibration folded into
:meth:add_turn via compaction= — used by partial-save paths
(e.g. ask_stream on error) and tests that need to update
calibration independently of a turn write.
| PARAMETER | DESCRIPTION |
|---|---|
user_id
|
Owner of the conversation.
TYPE:
|
session_id
|
Conversation session.
TYPE:
|
estimated_prompt_tokens
|
The bot's own token estimate for the round.
TYPE:
|
provider_prompt_tokens
|
The provider-reported prompt token count for the same round, when available.
TYPE:
|
chatbot_id
|
Agent attribution.
TYPE:
|
Source code in packages/ai-parrot/src/parrot/memory/abstract.py
clear_history
abstractmethod
async
¶
list_sessions
abstractmethod
async
¶
delete_history
abstractmethod
async
¶
ConversationTurn
dataclass
¶
ConversationTurn(turn_id: str, user_id: str, user_message: str, assistant_response: str, context_used: Optional[str] = None, tools_used: List[str] = list(), timestamp: datetime = datetime.now(), metadata: Dict[str, Any] = dict(), chatbot_id: Optional[str] = None, tool_invocations: List[ToolInvocation] = list(), error: Optional[str] = None, token_count: Optional[TokenCount] = None, state: TurnState = TurnState.RAW, schema_version: int = 1, norm_version: Optional[str] = None)
Represents a single turn in a conversation.
to_dict ¶
Serialize turn to dictionary.
Source code in packages/ai-parrot/src/parrot/memory/abstract.py
from_dict
classmethod
¶
Deserialize turn from dictionary.
Source code in packages/ai-parrot/src/parrot/memory/abstract.py
from_ai_message
classmethod
¶
from_ai_message(*, user_message: str, response: AIMessage, user_id: str, chatbot_id: str, context_used: Optional[str] = None, turn_id: Optional[str] = None, assistant_text: Optional[str] = None, error: Optional[str] = None, tool_invocations: Optional[List[ToolInvocation]] = None) -> ConversationTurn
Build a turn from the AIMessage a bot round produced.
This is the canonical constructor used by
AbstractBot.save_conversation_turn call sites (FEAT-524). Before
this existed every bot entry point hand-rolled its own turn with
slightly different metadata keys; routing through here gives every
persisted turn one shape.
| PARAMETER | DESCRIPTION |
|---|---|
user_message
|
The user's text for this round.
TYPE:
|
response
|
The final :class:
TYPE:
|
user_id
|
Owner of the conversation.
TYPE:
|
chatbot_id
|
The agent producing the turn. Must be the bot's
TYPE:
|
context_used
|
Optional retrieval context string used this round.
TYPE:
|
turn_id
|
Explicit turn id. Defaults to
TYPE:
|
assistant_text
|
Overrides the assistant text taken from
TYPE:
|
error
|
Round-level failure text (FEAT-525). Condensed by Stage 0 rule 5 when the turn is normalized; never omitted.
TYPE:
|
tool_invocations
|
Captured invocations to persist INSTEAD OF
deriving them from
TYPE:
|
| RETURNS | DESCRIPTION |
|---|---|
ConversationTurn
|
A fully populated :class: |
Source code in packages/ai-parrot/src/parrot/memory/abstract.py
177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 | |
AnswerMemory ¶
Store and retrieve question/answer interactions by turn identifier.
Source code in packages/ai-parrot/src/parrot/memory/agent.py
store_interaction
async
¶
Persist a question/answer pair under the provided turn identifier.
Source code in packages/ai-parrot/src/parrot/memory/agent.py
get
async
¶
Retrieve a stored interaction by turn identifier.
Source code in packages/ai-parrot/src/parrot/memory/agent.py
CompactionCommit
dataclass
¶
CompactionCommit(prompt_estimate: int, boundary_turn_id: Optional[str], stage2_needed: bool, history_estimate: int = 0, dropped_turns: int = 0)
What the bot hands to save_conversation_turn after the round.
| ATTRIBUTE | DESCRIPTION |
|---|---|
prompt_estimate |
TYPE:
|
boundary_turn_id |
The new monotonic boundary.
TYPE:
|
stage2_needed |
Whether Stage 2 is needed for this session.
TYPE:
|
history_estimate |
Telemetry only — the compacted history's total
estimated size. Ignored by :func:
TYPE:
|
dropped_turns |
Telemetry only — count of turns dropped by the last
compaction pass. Ignored by :func:
TYPE:
|
CompactionResult
dataclass
¶
CompactionResult(views: Tuple[TurnView, ...], omissions: Tuple[Omission, ...], history_estimate: int, boundary_turn_id: Optional[str], stage2_needed: bool, dropped_turn_ids: Tuple[str, ...])
Output of :func:parrot.memory.compaction.compact.compact_history.
ContextBudget
dataclass
¶
ContextBudget(window: int, reserve_output: int = 8192, reserve_fixed: int = 4096, high_watermark: float = 0.8, low_watermark: float = 0.6, max_turns: int = 30, verbatim_tokens: int = 15000, min_verbatim_turns: int = 2, oversize_tool_tokens: int = 2000, tool_activity_limit: Limit = Limit())
Token budget and retention configuration for one bot/agent.
| ATTRIBUTE | DESCRIPTION |
|---|---|
window |
The provider's context window, from
TYPE:
|
reserve_output |
Tokens reserved for the model's own output.
TYPE:
|
reserve_fixed |
Tokens reserved for the system prompt, tool schemas and provider framing allowance.
TYPE:
|
high_watermark |
Fraction of
TYPE:
|
low_watermark |
Reserved for Stage 2 (target after summarization); unused by the deterministic three-tier walk.
TYPE:
|
max_turns |
Unified safety ceiling on the number of turns considered
(was
TYPE:
|
verbatim_tokens |
Cumulative token budget for the verbatim (RAW) tier.
TYPE:
|
min_verbatim_turns |
Minimum number of turns kept verbatim, regardless of size.
TYPE:
|
oversize_tool_tokens |
Any tool output above this size is pruned from every turn but the newest, even inside the verbatim tier.
TYPE:
|
tool_activity_limit |
Bound applied when rendering the RAW
TYPE:
|
Limit
dataclass
¶
Limit(max_invocations: int = 12, max_input_chars: int = 200, max_output_chars: int = 400, max_block_tokens: int = 1500)
Bound on the RAW <tool-activity> block.
Keeps a chatty recent turn from blowing the whole budget by itself.
OmissionStore ¶
Bases: ABC
Content-addressed store for content pruned or offloaded from turns.
Initialize the store.
| PARAMETER | DESCRIPTION |
|---|---|
ttl
|
Expiry in seconds for stored content.
TYPE:
|
Source code in packages/ai-parrot/src/parrot/memory/compaction/omission.py
put
abstractmethod
async
¶
Store content under session_key, indexed by turn_id.
Idempotent: storing the same content twice returns the same id and does not create a duplicate index entry.
| PARAMETER | DESCRIPTION |
|---|---|
session_key
|
Opaque scoping key (composed by the memory).
TYPE:
|
content
|
The full text to store.
TYPE:
|
turn_id
|
When given, indexes the resulting id under this turn.
TYPE:
|
| RETURNS | DESCRIPTION |
|---|---|
str
|
The content id. |
Source code in packages/ai-parrot/src/parrot/memory/compaction/omission.py
put_many
async
¶
Store every :class:Omission under its own turn_id (default: loop over :meth:put).
| PARAMETER | DESCRIPTION |
|---|---|
session_key
|
Opaque scoping key (composed by the memory).
TYPE:
|
omissions
|
The omissions to flush.
TYPE:
|
Source code in packages/ai-parrot/src/parrot/memory/compaction/omission.py
get
abstractmethod
async
¶
Return the stored content for content_id, or None if unknown.
| PARAMETER | DESCRIPTION |
|---|---|
session_key
|
Opaque scoping key (composed by the memory).
TYPE:
|
content_id
|
The id returned by a previous :meth:
TYPE:
|
| RETURNS | DESCRIPTION |
|---|---|
Optional[str]
|
The stored content, or |
Optional[str]
|
belongs to a different session. |
Source code in packages/ai-parrot/src/parrot/memory/compaction/omission.py
probe
async
¶
Report whether content_id is still stored, WITHOUT loading it.
Added by FEAT-538. :meth:get fetches the payload text, so using
it to answer "does this still exist?" would drag potentially
large omitted content across the wire purely to compute a
boolean — and recall does exactly that check, for every omission
reference it reports.
Deliberately not abstract: a store written before this method
existed keeps working and inherits this default, which answers
None (unknown). Unknown is never reported as available —
claiming content is present when the store cannot say so would
let recall promise recoverable text that may be long gone.
| PARAMETER | DESCRIPTION |
|---|---|
session_key
|
Opaque scoping key (composed by the memory).
TYPE:
|
content_id
|
The id to probe.
TYPE:
|
| RETURNS | DESCRIPTION |
|---|---|
Optional[bool]
|
|
Optional[bool]
|
known to be absent or expired, and |
Optional[bool]
|
cannot answer cheaply. |
Source code in packages/ai-parrot/src/parrot/memory/compaction/omission.py
probe_many
async
¶
Probe several ids at once (default: loop over :meth:probe).
Backends with a batching primitive should override this; the default keeps the contract satisfiable by any store.
| PARAMETER | DESCRIPTION |
|---|---|
session_key
|
Opaque scoping key (composed by the memory).
TYPE:
|
content_ids
|
The ids to probe.
TYPE:
|
| RETURNS | DESCRIPTION |
|---|---|
Dict[str, Optional[bool]]
|
A mapping of id to availability, using :meth: |
Dict[str, Optional[bool]]
|
three-valued answer. |
Source code in packages/ai-parrot/src/parrot/memory/compaction/omission.py
list_by_turn
abstractmethod
async
¶
Return the content ids stored for turn_id, in insertion order.
| PARAMETER | DESCRIPTION |
|---|---|
session_key
|
Opaque scoping key (composed by the memory).
TYPE:
|
turn_id
|
The turn to look up.
TYPE:
|
| RETURNS | DESCRIPTION |
|---|---|
List[str]
|
A list of content ids (empty when the turn has none). |
Source code in packages/ai-parrot/src/parrot/memory/compaction/omission.py
clear
abstractmethod
async
¶
Delete every stored content and index entry for session_key.
| PARAMETER | DESCRIPTION |
|---|---|
session_key
|
Opaque scoping key (composed by the memory).
TYPE:
|
Source code in packages/ai-parrot/src/parrot/memory/compaction/omission.py
TokenCount
dataclass
¶
Per-turn token accounting.
context_used is deliberately NOT counted here (spec decision).
to_dict ¶
Serialize this token count to a plain dict.
Source code in packages/ai-parrot/src/parrot/memory/compaction/models.py
from_dict
classmethod
¶
Deserialize a token count from a dict.
Source code in packages/ai-parrot/src/parrot/memory/compaction/models.py
TokenCounter ¶
ToolInvocation
dataclass
¶
ToolInvocation(tool_name: str, input: Dict[str, Any], output: Optional[str] = None, status: ToolStatus = ToolStatus.COMPLETED, error: Optional[str] = None, elapsed_ms: Optional[int] = None, output_chars: Optional[int] = None, omitted: Dict[str, str] = dict(), wm_key: Optional[str] = None)
One tool call captured from AIMessage.tool_calls.
See parrot/models/basic.py:23-30 for the source ToolCall shape.
| ATTRIBUTE | DESCRIPTION |
|---|---|
tool_name |
Name of the invoked tool.
TYPE:
|
input |
Canonical (
TYPE:
|
output |
Full text, or the short preview left behind once the original output has been offloaded to the omission store.
TYPE:
|
status |
Whether the invocation completed or errored.
TYPE:
|
error |
Condensed error/traceback text. Never omitted (spec G7/C7).
TYPE:
|
elapsed_ms |
Wall-clock duration of the invocation, in milliseconds.
TYPE:
|
output_chars |
Length of the ORIGINAL output, captured before any offload so the preview notice can report the true size.
TYPE:
|
omitted |
Maps a field name (
TYPE:
|
wm_key |
The FEAT-380 working-memory tee key copied from
TYPE:
|
to_dict ¶
Serialize this invocation to a plain dict.
Source code in packages/ai-parrot/src/parrot/memory/compaction/models.py
from_dict
classmethod
¶
Deserialize an invocation from a dict, tolerant of missing keys.
Source code in packages/ai-parrot/src/parrot/memory/compaction/models.py
ToolStatus ¶
Bases: str, Enum
Outcome of a single tool invocation.
TurnState ¶
Bases: str, Enum
Lifecycle state of a conversation turn.
Storage always writes RAW in v1. PRUNED is a view-only state
produced by :func:parrot.memory.compaction.compact.compact_history.
SUMMARIZED is reserved for Stage 2 (LLM summary turns) and is never
produced by this feature.
TurnView
dataclass
¶
TurnView(turn_id: str, chatbot_id: Optional[str], user_text: str, assistant_text: str, assistant_suffix: str, state: TurnState, estimated_tokens: int)
Materialized text for one turn.
render_history only concatenates user_text and
assistant_text + assistant_suffix — it never re-derives them.
EpisodicMemoryMixin ¶
Mixin that adds automatic episodic memory to bots.
Provides hooks that bot implementations call at appropriate points in their ask() flow. The mixin is opt-in — bots that don't inherit it are completely unaffected.
Configuration attributes (override in subclass or set via kwargs): enable_episodic_memory: Master toggle for the mixin. episodic_backend: Backend type ("pgvector" or "faiss"). episodic_dsn: PostgreSQL DSN for PgVector backend. episodic_faiss_path: Persistence path for FAISS backend. episodic_schema: PostgreSQL schema name. episodic_reflection_enabled: Whether to generate reflections. episodic_inject_warnings: Whether to inject failure warnings pre-LLM. episodic_max_warnings: Maximum warnings to inject. episodic_trivial_tools: Tools to skip when recording. episodic_flush_on_start: Delete persisted episodes (FAISS files + Redis episode cache) when the agent configures, starting each process with a clean episodic slate. Useful while iterating on agent behavior so stale lessons don't reinforce old patterns.
flush_episodic_memory
async
¶
Delete persisted episodic memory for this agent.
Removes the FAISS persistence files (episodes.faiss,
episodes.jsonl, id_order.json) and every episodic:* Redis
cache key scoped to this agent. Safe to call when nothing is
persisted. Only covers the FAISS backend — PgVector-backed agents
must truncate the episodes table instead.
Source code in packages/ai-parrot/src/parrot/memory/episodic/mixin.py
EpisodicMemoryStore ¶
EpisodicMemoryStore(backend: AbstractEpisodeBackend, embedding_provider: EpisodeEmbeddingProvider | None = None, reflection_engine: ReflectionEngine | None = None, redis_cache: EpisodeRedisCache | None = None, default_ttl_days: int = 90, importance_scorer: ImportanceScorer | None = None, recall_strategy: RecallStrategy | None = None)
Main orchestrator for episodic memory operations.
Coordinates a backend (PgVector, FAISS, or RedisVector), an optional embedding provider (sentence-transformers), an optional reflection engine (LLM + heuristic), and an optional Redis cache for fast recent/failure lookups.
Pluggable strategies:
- importance_scorer: When provided, used to compute episode importance
in record_episode() instead of the inline heuristic. Must satisfy
the ImportanceScorer protocol.
- recall_strategy: When provided, used in recall_similar() instead
of calling backend.search_similar() directly. Must satisfy the
RecallStrategy protocol.
When neither is provided, behavior is identical to the pre-FEAT-075 implementation (no breaking changes).
| PARAMETER | DESCRIPTION |
|---|---|
backend
|
Storage backend (PgVector, FAISS, or RedisVector).
TYPE:
|
embedding_provider
|
Optional embedding provider for semantic search.
TYPE:
|
reflection_engine
|
Optional reflection engine for lesson extraction.
TYPE:
|
redis_cache
|
Optional Redis cache for hot episodes.
TYPE:
|
default_ttl_days
|
Default time-to-live for episodes (0 = no expiry).
TYPE:
|
importance_scorer
|
Optional pluggable importance scorer.
TYPE:
|
recall_strategy
|
Optional pluggable recall strategy.
TYPE:
|
Source code in packages/ai-parrot/src/parrot/memory/episodic/store.py
record_episode
async
¶
record_episode(namespace: MemoryNamespace, situation: str, action_taken: str, outcome: EpisodeOutcome, outcome_details: str | None = None, error_type: str | None = None, error_message: str | None = None, category: EpisodeCategory = EpisodeCategory.TOOL_EXECUTION, importance: int | None = None, related_tools: list[str] | None = None, related_entities: list[str] | None = None, metadata: dict[str, Any] | None = None, generate_reflection: bool = True, ttl_days: int | None = None) -> EpisodicMemory
Record a new episode with auto-enrichment.
Auto-computes importance, generates reflection (if engine available), embeds text for similarity search, stores in backend, and caches.
| PARAMETER | DESCRIPTION |
|---|---|
namespace
|
Scoping dimensions for this episode.
TYPE:
|
situation
|
What the agent was trying to do.
TYPE:
|
action_taken
|
What action was executed.
TYPE:
|
outcome
|
The result classification.
TYPE:
|
outcome_details
|
Additional outcome description.
TYPE:
|
error_type
|
Error category if applicable.
TYPE:
|
error_message
|
Detailed error message.
TYPE:
|
category
|
Episode classification.
TYPE:
|
importance
|
Override auto-computed importance (1-10).
TYPE:
|
related_tools
|
Tools involved in this episode.
TYPE:
|
related_entities
|
Entities referenced.
TYPE:
|
metadata
|
Additional key-value metadata.
TYPE:
|
generate_reflection
|
Whether to generate reflection via engine.
TYPE:
|
ttl_days
|
Override default TTL. 0 = no expiry.
TYPE:
|
| RETURNS | DESCRIPTION |
|---|---|
EpisodicMemory
|
The stored EpisodicMemory with all enrichments. |
Source code in packages/ai-parrot/src/parrot/memory/episodic/store.py
106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 | |
record_tool_episode
async
¶
record_tool_episode(namespace: MemoryNamespace, tool_name: str, tool_args: dict[str, Any], tool_result: Any, user_query: str | None = None) -> EpisodicMemory
Record an episode from a tool execution.
Extracts episode fields from a ToolResult and delegates to record_episode().
| PARAMETER | DESCRIPTION |
|---|---|
namespace
|
Scoping dimensions.
TYPE:
|
tool_name
|
Name of the tool that was called.
TYPE:
|
tool_args
|
Arguments passed to the tool.
TYPE:
|
tool_result
|
The ToolResult from the tool execution.
TYPE:
|
user_query
|
The original user query that triggered the tool.
TYPE:
|
| RETURNS | DESCRIPTION |
|---|---|
EpisodicMemory
|
The stored episode. |
Source code in packages/ai-parrot/src/parrot/memory/episodic/store.py
record_crew_episode
async
¶
record_crew_episode(namespace: MemoryNamespace, crew_result: Any, flow_description: str, per_agent: bool = True) -> list[EpisodicMemory]
Record episodes from a crew execution.
Creates a crew-level episode and optionally per-agent episodes.
| PARAMETER | DESCRIPTION |
|---|---|
namespace
|
Scoping dimensions (should include crew_id).
TYPE:
|
crew_result
|
The result from AgentCrew execution.
TYPE:
|
flow_description
|
Description of the workflow.
TYPE:
|
per_agent
|
If True, create one episode per participating agent.
TYPE:
|
| RETURNS | DESCRIPTION |
|---|---|
list[EpisodicMemory]
|
List of all created episodes. |
Source code in packages/ai-parrot/src/parrot/memory/episodic/store.py
recall_similar
async
¶
recall_similar(query: str, namespace: MemoryNamespace, top_k: int = 5, score_threshold: float = 0.3, category: EpisodeCategory | None = None, include_failures_only: bool = False) -> list[EpisodeSearchResult]
Recall episodes similar to a query.
Embeds the query and performs vector similarity search with namespace filtering.
| PARAMETER | DESCRIPTION |
|---|---|
query
|
Natural language query to search for.
TYPE:
|
namespace
|
Scoping dimensions for filtering.
TYPE:
|
top_k
|
Maximum results.
TYPE:
|
score_threshold
|
Minimum similarity score (0-1).
TYPE:
|
category
|
Optional category filter (applied post-search).
TYPE:
|
include_failures_only
|
If True, only return failure episodes.
TYPE:
|
| RETURNS | DESCRIPTION |
|---|---|
list[EpisodeSearchResult]
|
List of episodes ranked by similarity score. |
Source code in packages/ai-parrot/src/parrot/memory/episodic/store.py
get_failure_warnings
async
¶
get_failure_warnings(namespace: MemoryNamespace, current_query: str | None = None, max_warnings: int = 5) -> str
Generate injectable warning text from past failures.
Combines semantically similar failures (if query provided) with recent failures, deduplicates, and formats as text suitable for system prompt injection.
| PARAMETER | DESCRIPTION |
|---|---|
namespace
|
Scoping dimensions.
TYPE:
|
current_query
|
Current user query for semantic matching.
TYPE:
|
max_warnings
|
Maximum number of warnings.
TYPE:
|
| RETURNS | DESCRIPTION |
|---|---|
str
|
Formatted warning text (empty string if no failures found). |
Source code in packages/ai-parrot/src/parrot/memory/episodic/store.py
436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 | |
get_user_preferences
async
¶
Get user preference episodes.
| PARAMETER | DESCRIPTION |
|---|---|
namespace
|
Must include user_id for meaningful results.
TYPE:
|
limit
|
Maximum preferences to return.
TYPE:
|
| RETURNS | DESCRIPTION |
|---|---|
list[EpisodicMemory]
|
List of USER_PREFERENCE category episodes. |
Source code in packages/ai-parrot/src/parrot/memory/episodic/store.py
get_room_context
async
¶
get_room_context(namespace: MemoryNamespace, limit: int = 10, categories: list[EpisodeCategory] | None = None) -> list[EpisodicMemory]
Get recent episodes for a room.
| PARAMETER | DESCRIPTION |
|---|---|
namespace
|
Must include room_id for room scoping.
TYPE:
|
limit
|
Maximum episodes to return.
TYPE:
|
categories
|
Optional category filter (applied post-retrieval).
TYPE:
|
| RETURNS | DESCRIPTION |
|---|---|
list[EpisodicMemory]
|
List of recent room-scoped episodes. |
Source code in packages/ai-parrot/src/parrot/memory/episodic/store.py
mark_consolidated
async
¶
Mark episodes as consolidated into a dream-cycle brain wiki page.
Thin passthrough over backend.update_metadata() (FEAT-390).
Never deletes episodes — existing TTL/compaction keeps pruning.
Backends that do not implement update_metadata are tolerated
(watermark-only mode): this returns 0 with a WARNING logged.
| PARAMETER | DESCRIPTION |
|---|---|
episode_ids
|
Episode ids to mark as consolidated.
TYPE:
|
page_id
|
Brain wiki page id the episodes were distilled into.
TYPE:
|
| RETURNS | DESCRIPTION |
|---|---|
int
|
Number of episodes actually updated. |
Source code in packages/ai-parrot/src/parrot/memory/episodic/store.py
cleanup_expired
async
¶
Delete expired episodes from the backend.
| RETURNS | DESCRIPTION |
|---|---|
int
|
Number of episodes deleted. |
Source code in packages/ai-parrot/src/parrot/memory/episodic/store.py
compact_namespace
async
¶
compact_namespace(namespace: MemoryNamespace, keep_top_n: int = 100, keep_all_failures: bool = True) -> int
Compact a namespace by keeping only the most important episodes.
Retains the top-N episodes by importance score, plus all failure episodes if keep_all_failures is True. Deletes the rest.
| PARAMETER | DESCRIPTION |
|---|---|
namespace
|
The namespace to compact.
TYPE:
|
keep_top_n
|
Number of top episodes to retain.
TYPE:
|
keep_all_failures
|
If True, retain all failure episodes.
TYPE:
|
| RETURNS | DESCRIPTION |
|---|---|
int
|
Number of episodes deleted. |
Source code in packages/ai-parrot/src/parrot/memory/episodic/store.py
export_episodes
async
¶
Export episodes as JSONL string.
| PARAMETER | DESCRIPTION |
|---|---|
namespace
|
The namespace to export.
TYPE:
|
limit
|
Maximum episodes to export.
TYPE:
|
| RETURNS | DESCRIPTION |
|---|---|
str
|
JSONL-formatted string of episodes. |
Source code in packages/ai-parrot/src/parrot/memory/episodic/store.py
create_pgvector
async
classmethod
¶
create_pgvector(dsn: str, schema: str = 'parrot_memory', table: str = 'episodic_memory', embedding_provider: EpisodeEmbeddingProvider | None = None, reflection_engine: ReflectionEngine | None = None, redis_cache: EpisodeRedisCache | None = None, recall_strategy: RecallStrategy | None = None, importance_scorer: ImportanceScorer | None = None, **kwargs: Any) -> 'EpisodicMemoryStore'
Create a store with PgVector backend.
| PARAMETER | DESCRIPTION |
|---|---|
dsn
|
PostgreSQL connection string.
TYPE:
|
schema
|
PostgreSQL schema name.
TYPE:
|
table
|
Table name.
TYPE:
|
embedding_provider
|
Optional embedding provider.
TYPE:
|
reflection_engine
|
Optional reflection engine.
TYPE:
|
redis_cache
|
Optional Redis cache.
TYPE:
|
recall_strategy
|
Optional recall strategy.
TYPE:
|
importance_scorer
|
Optional importance scorer.
TYPE:
|
**kwargs
|
Additional kwargs for EpisodicMemoryStore.
TYPE:
|
| RETURNS | DESCRIPTION |
|---|---|
'EpisodicMemoryStore'
|
Configured EpisodicMemoryStore with PgVector backend. |
Source code in packages/ai-parrot/src/parrot/memory/episodic/store.py
create_redis_vector
async
classmethod
¶
create_redis_vector(redis_url: str, index_name: str = 'idx:episodes', embedding_dim: int = 384, namespace: MemoryNamespace | None = None, embedding_provider: EpisodeEmbeddingProvider | None = None, reflection_engine: ReflectionEngine | None = None, redis_cache: EpisodeRedisCache | None = None, recall_strategy: RecallStrategy | None = None, importance_scorer: ImportanceScorer | None = None, **kwargs: Any) -> 'EpisodicMemoryStore'
Create a store with RedisVectorBackend.
Requires Redis Stack with RediSearch module enabled.
| PARAMETER | DESCRIPTION |
|---|---|
redis_url
|
Redis connection URL (e.g.,
TYPE:
|
index_name
|
RediSearch index name.
TYPE:
|
embedding_dim
|
Dimension of embedding vectors.
TYPE:
|
namespace
|
Optional namespace for default scoping.
TYPE:
|
embedding_provider
|
Optional embedding provider.
TYPE:
|
reflection_engine
|
Optional reflection engine.
TYPE:
|
redis_cache
|
Optional Redis cache (separate from vector backend).
TYPE:
|
recall_strategy
|
Optional recall strategy.
TYPE:
|
importance_scorer
|
Optional importance scorer.
TYPE:
|
**kwargs
|
Additional kwargs for EpisodicMemoryStore.
TYPE:
|
| RETURNS | DESCRIPTION |
|---|---|
'EpisodicMemoryStore'
|
Configured EpisodicMemoryStore with RedisVectorBackend. |
Source code in packages/ai-parrot/src/parrot/memory/episodic/store.py
create_faiss
async
classmethod
¶
create_faiss(persistence_path: str | None = None, dimension: int = 384, max_episodes: int = 10000, embedding_provider: EpisodeEmbeddingProvider | None = None, reflection_engine: ReflectionEngine | None = None, redis_cache: EpisodeRedisCache | None = None, **kwargs: Any) -> 'EpisodicMemoryStore'
Create a store with FAISS backend.
| PARAMETER | DESCRIPTION |
|---|---|
persistence_path
|
Directory for disk persistence (None = in-memory only).
TYPE:
|
dimension
|
Embedding vector dimension.
TYPE:
|
max_episodes
|
Maximum episodes in the FAISS index.
TYPE:
|
embedding_provider
|
Optional embedding provider.
TYPE:
|
reflection_engine
|
Optional reflection engine.
TYPE:
|
redis_cache
|
Optional Redis cache.
TYPE:
|
**kwargs
|
Additional kwargs for EpisodicMemoryStore.
TYPE:
|
| RETURNS | DESCRIPTION |
|---|---|
'EpisodicMemoryStore'
|
Configured EpisodicMemoryStore with FAISS backend. |
Source code in packages/ai-parrot/src/parrot/memory/episodic/store.py
EpisodicMemoryToolkit ¶
Bases: AbstractToolkit
Toolkit exposing episodic memory as agent-callable tools.
Provides three tools for LLM agents: - search_episodic_memory: Semantic search over past experiences. - record_lesson: Explicitly record a lesson for future reference. - get_warnings: Retrieve relevant past failure warnings.
| PARAMETER | DESCRIPTION |
|---|---|
store
|
The EpisodicMemoryStore instance.
TYPE:
|
namespace
|
The namespace scope for all operations.
TYPE:
|
Source code in packages/ai-parrot/src/parrot/memory/episodic/tools.py
search_episodic_memory
async
¶
Search past agent experiences by semantic similarity.
Use this tool to recall what happened in similar past situations, including lessons learned and outcomes.
| PARAMETER | DESCRIPTION |
|---|---|
query
|
What to search for in past experiences.
TYPE:
|
top_k
|
Maximum number of results to return.
TYPE:
|
failures_only
|
If True, only return past failures and mistakes.
TYPE:
|
| RETURNS | DESCRIPTION |
|---|---|
str
|
Formatted list of relevant past experiences with lessons learned. |
Source code in packages/ai-parrot/src/parrot/memory/episodic/tools.py
record_lesson
async
¶
Explicitly record a lesson learned for future reference.
Use this when you discover something important that should be remembered for similar future situations.
| PARAMETER | DESCRIPTION |
|---|---|
situation
|
What was happening when the lesson was learned.
TYPE:
|
lesson
|
The concise lesson or insight to remember.
TYPE:
|
category
|
Type of lesson (decision, user_preference, workflow_pattern).
TYPE:
|
importance
|
How important this lesson is (1-10, default 5).
TYPE:
|
| RETURNS | DESCRIPTION |
|---|---|
str
|
Confirmation that the lesson was recorded. |
Source code in packages/ai-parrot/src/parrot/memory/episodic/tools.py
get_warnings
async
¶
Get warnings about past mistakes relevant to the current task.
Use this before attempting actions that might fail, to check if similar attempts have failed before.
| PARAMETER | DESCRIPTION |
|---|---|
context
|
Description of what you're about to do (for relevance matching).
TYPE:
|
| RETURNS | DESCRIPTION |
|---|---|
str
|
Formatted warnings about past failures and successful approaches, |
str
|
or a message if no relevant warnings exist. |
Source code in packages/ai-parrot/src/parrot/memory/episodic/tools.py
FileConversationMemory ¶
FileConversationMemory(base_path: str = './conversations', *, token_counter: Optional[TokenCounter] = None, omission_store: Optional[OmissionStore] = None, normalize: bool = True)
Bases: ConversationMemory
File-based implementation of conversation memory.
Initialize the store.
| PARAMETER | DESCRIPTION |
|---|---|
base_path
|
Root directory for conversation history files.
TYPE:
|
token_counter
|
Stage 0.5 counter override (see
:class:
TYPE:
|
omission_store
|
Omission-store override; defaults to a
:class:
TYPE:
|
normalize
|
Disables Stage 0 for this instance when
TYPE:
|
Source code in packages/ai-parrot/src/parrot/memory/file.py
create_history
async
¶
create_history(user_id: str, session_id: str, metadata: Optional[Dict[str, Any]] = None, chatbot_id: Optional[str] = None) -> ConversationHistory
Create a new conversation history.
Source code in packages/ai-parrot/src/parrot/memory/file.py
get_history
async
¶
get_history(user_id: str, session_id: str, chatbot_id: Optional[str] = None) -> Optional[ConversationHistory]
Get a conversation history, re-keying a legacy record if needed.
FEAT-524 unified the storage path to {user}/{chatbot}/{session}.json.
Histories written before that live at {user}/{session}.json. When
chatbot_id is given and the segmented path holds nothing, the legacy
path is read once, copied to the segmented path and returned. The legacy
file is deliberately left in place so a rollback still finds it.
| PARAMETER | DESCRIPTION |
|---|---|
user_id
|
Owner of the conversation.
TYPE:
|
session_id
|
Conversation session.
TYPE:
|
chatbot_id
|
Agent path segment. Falsy means "read the legacy path directly" — no re-key is attempted.
TYPE:
|
| RETURNS | DESCRIPTION |
|---|---|
Optional[ConversationHistory]
|
The history, or |
Source code in packages/ai-parrot/src/parrot/memory/file.py
update_history
async
¶
clear_history
async
¶
Clear a conversation history.
Source code in packages/ai-parrot/src/parrot/memory/file.py
list_sessions
async
¶
List all session IDs for a user.
Source code in packages/ai-parrot/src/parrot/memory/file.py
delete_history
async
¶
Delete a conversation history entirely.
Source code in packages/ai-parrot/src/parrot/memory/file.py
InMemoryConversation ¶
InMemoryConversation(*, token_counter: Optional[TokenCounter] = None, omission_store: Optional[OmissionStore] = None, normalize: bool = True)
Bases: ConversationMemory
In-memory implementation of conversation memory.
Initialize the store.
| PARAMETER | DESCRIPTION |
|---|---|
token_counter
|
Stage 0.5 counter override (see
:class:
TYPE:
|
omission_store
|
Omission-store override; defaults to a fresh
:class:
TYPE:
|
normalize
|
Disables Stage 0 for this instance when
TYPE:
|
Source code in packages/ai-parrot/src/parrot/memory/mem.py
create_history
async
¶
create_history(user_id: str, session_id: str, metadata: Optional[Dict[str, Any]] = None, chatbot_id: Optional[str] = None) -> ConversationHistory
Create a new conversation history.
Source code in packages/ai-parrot/src/parrot/memory/mem.py
get_history
async
¶
get_history(user_id: str, session_id: str, chatbot_id: Optional[str] = None) -> Optional[ConversationHistory]
Get a conversation history.
Source code in packages/ai-parrot/src/parrot/memory/mem.py
update_history
async
¶
Update a conversation history.
Source code in packages/ai-parrot/src/parrot/memory/mem.py
clear_history
async
¶
Clear a conversation history.
Source code in packages/ai-parrot/src/parrot/memory/mem.py
list_sessions
async
¶
List all session IDs for a user.
Source code in packages/ai-parrot/src/parrot/memory/mem.py
delete_history
async
¶
Delete a conversation history entirely.
Source code in packages/ai-parrot/src/parrot/memory/mem.py
RedisConversation ¶
RedisConversation(redis_url: str = None, key_prefix: str = 'conversation', use_hash_storage: bool = True, *, token_counter: Optional[TokenCounter] = None, omission_store: Optional[OmissionStore] = None, normalize: bool = True, omission_ttl: Optional[int] = None, history_ttl: Optional[int] = None)
Bases: ConversationMemory
Redis-based conversation memory with proper encoding handling.
Initialize the store.
| PARAMETER | DESCRIPTION |
|---|---|
redis_url
|
Redis connection URL; defaults to
TYPE:
|
key_prefix
|
Prefix for every history key this instance owns
(e.g.
TYPE:
|
use_hash_storage
|
Whether to use Redis hashes (recommended) or plain string keys.
TYPE:
|
token_counter
|
Stage 0.5 counter override (see
:class:
TYPE:
|
omission_store
|
Omission-store override; defaults to a
:class:
TYPE:
|
normalize
|
Disables Stage 0 for this instance when
TYPE:
|
omission_ttl
|
Expiry (seconds) for the default omission store;
TYPE:
|
history_ttl
|
Expiry (seconds) refreshed on every write to a
history key, so an idle conversation expires.
TYPE:
|
Source code in packages/ai-parrot/src/parrot/memory/redis.py
create_history
async
¶
create_history(user_id: str, session_id: str, metadata: Optional[Dict[str, Any]] = None, chatbot_id: Optional[str] = None) -> ConversationHistory
Create a new conversation history.
Source code in packages/ai-parrot/src/parrot/memory/redis.py
get_history
async
¶
get_history(user_id: str, session_id: str, chatbot_id: Optional[str] = None) -> Optional[ConversationHistory]
Get a conversation history, re-keying a legacy record if needed.
FEAT-524 unified the storage key to (chatbot, user, session).
Histories written before that live under the un-segmented
conversation:{user}:{session} key, and these keys carry no TTL, so
without a fallback every live conversation would silently restart the
first time a bot asked for its history under the new key.
When chatbot_id is given and the segmented key holds nothing, the
legacy key is read once, copied under the segmented key and returned.
The legacy record is deliberately left in place so a rollback still
finds it. The copy is idempotent, so two concurrent first reads racing
each other is benign — no locking (spec §7 "Re-key race").
| PARAMETER | DESCRIPTION |
|---|---|
user_id
|
Owner of the conversation.
TYPE:
|
session_id
|
Conversation session.
TYPE:
|
chatbot_id
|
Agent key segment. Falsy means "read the legacy key directly" — no re-key is attempted.
TYPE:
|
| RETURNS | DESCRIPTION |
|---|---|
Optional[ConversationHistory]
|
The history, or |
Source code in packages/ai-parrot/src/parrot/memory/redis.py
update_history
async
¶
Update a conversation history.
Source code in packages/ai-parrot/src/parrot/memory/redis.py
read_metadata
async
¶
read_metadata(user_id: str, session_id: str, chatbot_id: Optional[str] = None) -> Optional[Dict[str, Any]]
Read a conversation's whole metadata blob (FEAT-538).
In hash mode this is a single targeted hget, avoiding the
FEAT-524 lazy legacy re-key that a full :meth:get_history may
perform as a side effect.
| PARAMETER | DESCRIPTION |
|---|---|
user_id
|
Owner of the conversation.
TYPE:
|
session_id
|
Conversation session.
TYPE:
|
chatbot_id
|
Agent key segment.
TYPE:
|
| RETURNS | DESCRIPTION |
|---|---|
Optional[Dict[str, Any]]
|
The metadata dict, or |
Source code in packages/ai-parrot/src/parrot/memory/redis.py
merge_metadata
async
¶
merge_metadata(user_id: str, session_id: str, chatbot_id: Optional[str] = None, *, mutate: Callable[[Dict[str, Any]], Dict[str, Any]], ttl: Optional[int] = None, max_attempts: int = _MERGE_MAX_ATTEMPTS) -> Dict[str, Any]
Atomically compare-and-merge a conversation's metadata (FEAT-538).
metadata is shared by writers that know nothing about each
other: the compaction layer owns metadata["compaction"] and
task memory owns metadata["task_memory"]. The previous
read-modify-write lost whichever update landed second.
A task-scoped lock cannot fix that, because the other writer
would not take it. So this uses Redis' own
WATCH/MULTI/EXEC: the transaction aborts if anyone
touches the key in between, and mutate is re-run against the
freshly read value. Correctness therefore does not depend on every
writer cooperating — only on them going through Redis.
mutate must be a pure function of the metadata it is
given: it may be called several times, and it must merge into the
dict it receives rather than into one captured earlier.
| PARAMETER | DESCRIPTION |
|---|---|
user_id
|
Owner of the conversation.
TYPE:
|
session_id
|
Conversation session.
TYPE:
|
chatbot_id
|
Agent key segment.
TYPE:
|
mutate
|
Pure function from current metadata to new metadata.
TYPE:
|
ttl
|
Optional expiry in seconds applied to the conversation key. Task-memory mode requires an explicit finite hot-key retention when the underlying history has no TTL.
TYPE:
|
max_attempts
|
Bound on compare-and-swap retries.
TYPE:
|
| RETURNS | DESCRIPTION |
|---|---|
Dict[str, Any]
|
The metadata that was written. |
| RAISES | DESCRIPTION |
|---|---|
RuntimeError
|
If the merge still conflicts after
|
Source code in packages/ai-parrot/src/parrot/memory/redis.py
341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 | |
clear_history
async
¶
Clear a conversation history.
Source code in packages/ai-parrot/src/parrot/memory/redis.py
list_sessions
async
¶
List all session IDs for a user.
Source code in packages/ai-parrot/src/parrot/memory/redis.py
delete_history
async
¶
Delete a conversation history entirely.
Source code in packages/ai-parrot/src/parrot/memory/redis.py
close
async
¶
ping
async
¶
get_raw_data
async
¶
Get raw data from Redis for debugging.
Source code in packages/ai-parrot/src/parrot/memory/redis.py
debug_conversation
async
¶
debug_conversation(user_id: str, session_id: str, chatbot_id: Optional[str] = None) -> Dict[str, Any]
Debug method to inspect conversation data.
Source code in packages/ai-parrot/src/parrot/memory/redis.py
list_sessions_by_chatbot
async
¶
List all sessions for a specific chatbot.
| PARAMETER | DESCRIPTION |
|---|---|
chatbot_id
|
The chatbot identifier
TYPE:
|
user_id
|
Optional user filter
TYPE:
|
| RETURNS | DESCRIPTION |
|---|---|
List[str]
|
List of session IDs |
Source code in packages/ai-parrot/src/parrot/memory/redis.py
get_chatbot_stats
async
¶
Get statistics for a specific chatbot.
| RETURNS | DESCRIPTION |
|---|---|
Dict[str, Any]
|
Dictionary with conversation counts, active users, etc. |
Source code in packages/ai-parrot/src/parrot/memory/redis.py
delete_all_chatbot_conversations
async
¶
Delete all conversations for a chatbot.
| PARAMETER | DESCRIPTION |
|---|---|
chatbot_id
|
The chatbot identifier
TYPE:
|
user_id
|
Optional user filter
TYPE:
|
| RETURNS | DESCRIPTION |
|---|---|
int
|
Number of conversations deleted |
Source code in packages/ai-parrot/src/parrot/memory/redis.py
get_chatbot_users
async
¶
Get all users who have interacted with a chatbot.
Source code in packages/ai-parrot/src/parrot/memory/redis.py
HistoryMessage
dataclass
¶
HistoryMessage(role: Literal['user', 'assistant'], content: str, chatbot_id: Optional[str] = None, turn_id: Optional[str] = None)
A single rendered conversation message, provider-neutral and text-only.
| ATTRIBUTE | DESCRIPTION |
|---|---|
role |
Either
TYPE:
|
content |
The message text.
TYPE:
|
chatbot_id |
The agent that produced the turn this message came from,
or
TYPE:
|
turn_id |
The originating :class:
TYPE:
|
ContextAssembler ¶
Assembles context from multiple sources within a token budget.
Priority order (highest first): 1. Episodic failure warnings — critical for avoiding past mistakes 2. Relevant skills — applicable knowledge 3. Conversation history — recent turns (truncated from oldest)
Each section gets a weight-based allocation from the total budget. Unused budget from empty sections rolls forward to the next priority.
| PARAMETER | DESCRIPTION |
|---|---|
config
|
Optional MemoryConfig; defaults to MemoryConfig() if omitted.
TYPE:
|
Example
assembler = ContextAssembler(MemoryConfig(max_context_tokens=2000)) ctx = assembler.assemble( episodic_warnings="Don't call X without auth", relevant_skills="Use get_schema tool", conversation="User: hello\nAssistant: hi", ) print(ctx.tokens_used)
Source code in packages/ai-parrot/src/parrot/memory/unified/context.py
assemble ¶
assemble(episodic_warnings: str = '', relevant_skills: str = '', conversation: str = '', semantic_knowledge: str = '') -> MemoryContext
Assemble context respecting token budget.
Sections are filled in priority order. Any budget left over from an empty (or smaller-than-allocation) section is carried forward and added to the remaining sections' budgets proportionally.
| PARAMETER | DESCRIPTION |
|---|---|
episodic_warnings
|
Past failure lessons from episodic memory.
TYPE:
|
relevant_skills
|
Applicable skills from the skill registry.
TYPE:
|
conversation
|
Recent conversation turns.
TYPE:
|
semantic_knowledge
|
Distilled long-term knowledge from the
agent's brain wiki (FEAT-390); budgeted at
TYPE:
|
| RETURNS | DESCRIPTION |
|---|---|
MemoryContext
|
MemoryContext with filled sections and accurate token accounting. |
Source code in packages/ai-parrot/src/parrot/memory/unified/context.py
LongTermMemoryMixin ¶
Single opt-in mixin for long-term memory in any bot/agent.
Provides unified episodic + skill + conversation memory without requiring the bot to manage individual subsystems.
MRO note: place before AbstractBot (or Agent) in the class
definition so this mixin's methods take priority in the resolution order:
class MyAgent(LongTermMemoryMixin, Agent):
enable_long_term_memory = True
Configuration attributes (override in the subclass or via kwargs):
enable_long_term_memory: Master toggle — all methods are no-ops when False.
episodic_inject_warnings: Retrieve past failure warnings.
episodic_auto_record: Record interactions to episodic memory.
episodic_max_warnings: Maximum failure warnings per context.
skill_inject_context: Retrieve relevant skills into context.
skill_auto_extract: Auto-extract skills from successful interactions.
skill_expose_tools: Register skill tools with the agent's tool manager.
skill_max_context: Maximum skills per context.
memory_max_context_tokens: Total token budget for assembled context.
enable_brain: Master toggle for the dream cycle (FEAT-390) —
episodic-to-wiki brain consolidation. All brain/dream objects
are no-ops (never constructed) when False.
dream_interval_hours: Hours between dream cycles.
dream_importance_threshold: Minimum episode importance eligible
for consolidation (episodes with a lesson are always eligible).
brain_storage_dir: Directory for the agent's brain wiki; defaults
to ~/.parrot/brains/<agent_id>.
brain_promote_to_org: Also maintain an org-level brain wiki and
promote reinforced pages into it.
org_promotion_cycles: Distinct-cycle reinforcement threshold before
a page is promoted to the org wiki.
get_memory_context
async
¶
Return assembled memory context as an injectable prompt string.
| PARAMETER | DESCRIPTION |
|---|---|
query
|
Current user query for semantic retrieval.
TYPE:
|
user_id
|
User identifier for conversation history.
TYPE:
|
session_id
|
Session identifier for conversation history.
TYPE:
|
| RETURNS | DESCRIPTION |
|---|---|
str
|
Formatted multi-section string ready for system prompt injection, |
str
|
or empty string when memory is disabled or not configured. |
Source code in packages/ai-parrot/src/parrot/memory/unified/mixin.py
MemoryConfig ¶
Bases: BaseModel
Configuration for UnifiedMemoryManager.
Controls which subsystems are enabled, token budget allocation, and per-subsystem limits.
MemoryContext ¶
Bases: BaseModel
Assembled context from all memory subsystems.
Holds the text sections retrieved from episodic memory, skill registry, and conversation history, along with token accounting for budget enforcement.
to_prompt_string ¶
Format as injectable system prompt sections.
Only non-empty sections are included. Each section is wrapped in descriptive XML tags so the LLM can distinguish memory types.
| RETURNS | DESCRIPTION |
|---|---|
str
|
Formatted string ready for injection into a system prompt. |
Source code in packages/ai-parrot/src/parrot/memory/unified/models.py
UnifiedMemoryManager ¶
UnifiedMemoryManager(namespace: MemoryNamespace, conversation_memory: Optional[ConversationMemory] = None, episodic_store: Optional[EpisodicMemoryStore] = None, skill_registry: Optional[Any] = None, config: Optional[MemoryConfig] = None, cross_domain_router: Optional[CrossDomainRouter] = None, brain: Optional[BrainStore] = None, org_brain: Optional[BrainStore] = None)
Coordinates episodic memory, skill registry, and conversation memory.
All retrieval in get_context_for_query runs concurrently via
asyncio.gather. Subsystems that are None are silently skipped.
When cross_domain_router is provided, get_context_for_query also
queries episodic memories from relevant agent namespaces identified by the
router. Cross-domain results are labeled and appended to the episodic
warnings text. Cross-domain failures never break the main retrieval flow.
| PARAMETER | DESCRIPTION |
|---|---|
namespace
|
Scoping dimensions for episodic memory queries.
TYPE:
|
conversation_memory
|
Optional conversation history store.
TYPE:
|
episodic_store
|
Optional episodic memory store.
TYPE:
|
skill_registry
|
Optional skill registry (duck-typed via SkillRegistry protocol).
TYPE:
|
config
|
Optional memory configuration; defaults to
TYPE:
|
cross_domain_router
|
Optional router for multi-agent memory sharing.
TYPE:
|
Example
manager = UnifiedMemoryManager( namespace=MemoryNamespace(agent_id="my-agent"), episodic_store=store, cross_domain_router=router, ) ctx = await manager.get_context_for_query("user query", "u1", "s1") prompt += ctx.to_prompt_string()
Source code in packages/ai-parrot/src/parrot/memory/unified/manager.py
configure
async
¶
Initialise all non-None subsystems.
Calls configure(**kwargs) on each subsystem that exposes it.
Subsystems that lack a configure method are silently skipped.
| PARAMETER | DESCRIPTION |
|---|---|
**kwargs
|
Forwarded verbatim to each subsystem's
TYPE:
|
Source code in packages/ai-parrot/src/parrot/memory/unified/manager.py
cleanup
async
¶
Release resources held by all non-None subsystems.
Calls cleanup() on each subsystem that exposes it.
Source code in packages/ai-parrot/src/parrot/memory/unified/manager.py
get_context_for_query
async
¶
Retrieve and assemble context from all memory subsystems.
All three retrieval calls run concurrently via asyncio.gather.
If a subsystem is None or raises an exception its section is
returned as an empty string.
| PARAMETER | DESCRIPTION |
|---|---|
query
|
Current user query — used for semantic similarity search.
TYPE:
|
user_id
|
User identifier for conversation history lookup.
TYPE:
|
session_id
|
Session identifier for conversation history lookup.
TYPE:
|
| RETURNS | DESCRIPTION |
|---|---|
MemoryContext
|
|
Source code in packages/ai-parrot/src/parrot/memory/unified/manager.py
record_interaction
async
¶
record_interaction(query: str, response: Any, tool_calls: list[Any], user_id: str, session_id: str) -> None
Record a completed interaction to episodic and conversation memory.
This method is exception-safe: any error is logged at WARNING level and execution continues. It is designed to be called fire-and-forget after returning a response to the user.
| PARAMETER | DESCRIPTION |
|---|---|
query
|
The user's original query.
TYPE:
|
response
|
The agent's response object (content extracted as str).
TYPE:
|
tool_calls
|
List of tool call objects from the interaction.
TYPE:
|
user_id
|
User identifier.
TYPE:
|
session_id
|
Session identifier.
TYPE:
|
Source code in packages/ai-parrot/src/parrot/memory/unified/manager.py
compact_history ¶
compact_history(history: ConversationHistory, budget: ContextBudget, *, policies: Optional[Dict[str, PrunePolicy]] = None, boundary_turn_id: Optional[str] = None, counter: Optional[TokenCounter] = None, calibration: float = 1.0, current_chatbot_id: Optional[str] = None, include_other_agents: bool = True) -> CompactionResult
Walk a history newest → oldest and classify each turn RAW / PRUNED / DROPPED.
Pure and synchronous (spec G1/G9): never mutates history, its
turns, or their invocations; performs no I/O; the same inputs always
produce an equal :class:CompactionResult.
Three tiers (spec G10), walked newest → oldest with a running calibrated token sum:
- Verbatim (RAW) while
n_raw < budget.min_verbatim_turnsor the cumulative size stays within bothbudget.verbatim_tokensand the high-watermark budget. - Pruned while the cumulative size stays within the high watermark (or the turn is the newest kept turn — the newest is never dropped).
- Dropped beyond that — and every older turn is dropped too
(tiers are contiguous); sets
stage2_needed.
A persisted boundary_turn_id forces every turn at or before it to
render PRUNED regardless of budget (monotonic: turns that once
rendered PRUNED never render RAW again for this history). Any
invocation whose output exceeds budget.oversize_tool_tokens is
pruned in every turn but the newest, even inside the verbatim tier.
| PARAMETER | DESCRIPTION |
|---|---|
history
|
The history to compact.
TYPE:
|
budget
|
The retention configuration.
TYPE:
|
policies
|
Per-tool prune-policy overrides, consulted before the module registry.
TYPE:
|
boundary_turn_id
|
The previously persisted boundary, if any.
TYPE:
|
counter
|
The token counter to size turns and rendered blocks
with. Defaults to :func:
TYPE:
|
calibration
|
Multiplier applied to every calibrated size (the memory's EWMA of provider/estimate ratio).
TYPE:
|
current_chatbot_id
|
The agent doing the asking, for the foreign-turn
rule (mirrors :func:
TYPE:
|
include_other_agents
|
When
TYPE:
|
| RETURNS | DESCRIPTION |
|---|---|
A
|
class:
TYPE:
|
CompactionResult
|
ready for :func: |
Source code in packages/ai-parrot/src/parrot/memory/compaction/compact.py
143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 | |
render_history ¶
render_history(history: Union[Optional[ConversationHistory], Sequence['TurnView']], *, max_turns: Optional[int] = None, current_chatbot_id: Optional[str] = None, include_other_agents: bool = True, other_agent_label: str = '[agent:{chatbot_id}]') -> List[HistoryMessage]
Render a conversation history (or turn views) into alternating messages.
| PARAMETER | DESCRIPTION |
|---|---|
history
|
A :class:
TYPE:
|
max_turns
|
Keep only the most recent
TYPE:
|
current_chatbot_id
|
The agent doing the asking. Turns/views whose
TYPE:
|
include_other_agents
|
When
TYPE:
|
other_agent_label
|
Format string for the foreign-turn prefix; receives
TYPE:
|
| RETURNS | DESCRIPTION |
|---|---|
List[HistoryMessage]
|
A list of :class: |
List[HistoryMessage]
|
|
List[HistoryMessage]
|
|
List[HistoryMessage]
|
|
List[HistoryMessage]
|
|