Skip to content

symfonic.agent.warnings

warnings

Custom warning types for the symfonic agent framework.

Import and use warnings.filterwarnings to silence any of these selectively without silencing the entire Python warning system.

LazySkillResolutionWarning

Bases: UserWarning

Emitted when a procedural skill does not resolve to a registered tool.

v9.3.0 (issue #36). With lazy_tooling=True the engine resolves the per-turn tool subset from the procedural memory layer. Each active skill must name a registered tool: the canonical identifier is the skill's action_tool metadata (the same field the L1 PRE-FLIGHT synthesiser reads) when present, otherwise MemoryEntry.content. Descriptive/instructional skill text belongs in the steps / context metadata, NOT in content when content is being used as the tool identifier.

When a resolved name does not match any registered/bound tool it is dropped (it cannot select a real tool anyway) and this warning fires once per agent instance. Left unresolved, such a name would be rendered into the HMS system prompt as a phantom "active tool" the model is told it can call — degrading routing and inviting hallucinated tool calls.

Fix: store the exact registered tool name in the skill's metadata["action_tool"] (or content); keep prose in the steps / context fields.

To silence this warning once you understand the trade-off::

import warnings
from symfonic.agent.warnings import LazySkillResolutionWarning
warnings.filterwarnings("ignore", category=LazySkillResolutionWarning)

See docs/guides/06-lazy-tooling.md for the storage contract.

LazyToolingWarning

Bases: UserWarning

Emitted when lazy_tooling is enabled but prerequisites are missing.

lazy_tooling=True silently does nothing unless ALL three of the following conditions are met at construction time:

  1. enable_hms_prompt=True — the HMS system-prompt pipeline is the only codepath that calls _lazy_resolve_tools(). Without it, tool filtering is never triggered.
  2. A populated procedural memory layer — the CapabilityRouter queries MemoryLayer.PROCEDURAL to score skills against the query. If the layer is absent (or has no entries), the router has nothing to filter from.
  3. DomainTemplate.tool_manifest is non-empty — the router filters tools by matching procedural skills against the manifest. An empty manifest means every request sends all tool schemas to the LLM.

Consequence of missing prerequisites: all registered tool schemas are sent to the LLM on every request, which can easily consume 3–5 k extra tokens per turn and trigger rate-limit (TPM) errors on smaller tiers.

To silence this warning once you understand the trade-off::

import warnings
from symfonic.agent.warnings import LazyToolingWarning
warnings.filterwarnings("ignore", category=LazyToolingWarning)

See docs/guides/06-lazy-tooling.md for the full activation recipe.

TranscriptPersistenceEphemeralWarning

Bases: UserWarning

Emitted when transcript persistence is on but only MemorySaver is wired.

transcript_persistence_enabled=True requests a durable verbatim transcript (state['messages'] per thread_id) so that SymfonicAgent.get_transcript(...) and working-deque rehydrate-on-resume survive a process restart. Durability requires a durable LangGraph saver:

  1. A Postgres graph backend → PostgresCheckpointerFactory (durable), or
  2. dev_sqlite_checkpoint_path set → SqliteCheckpointerFactory (durable).

When NEITHER is configured the engine falls back to an in-process MemorySaver. That saver IS wired (so get_transcript works WITHIN the process lifetime), but every checkpoint is lost on restart: the transcript will NOT survive a container eviction and working-deque resume will rehydrate nothing. This is almost never what an adopter who flipped transcript_persistence_enabled intended, so the engine refuses to fail silently and emits this warning exactly ONCE per agent instance (mirrors the emit-once shape of :class:~symfonic.memory.warnings.MultiScopeIgnoredWarning).

To get a durable transcript, configure a Postgres graph backend OR set FrameworkConfig.dev_sqlite_checkpoint_path.

To silence this warning once you understand the trade-off (e.g. an intentionally ephemeral dev session)::

import warnings
from symfonic.agent.warnings import TranscriptPersistenceEphemeralWarning
warnings.filterwarnings("ignore", category=TranscriptPersistenceEphemeralWarning)

See docs/concepts/conversation-persistence.md for the durable-saver recipe.