Migrating from symfonic-core v6.x to v7.0¶
v7.0.0 is a major release. It introduces the four v7.0 Thalamic
Architecture subsystems (intent filter, N-hop spreading, STM summary,
fabrication executor, nightly_nap) and removes one long-deprecated
constructor kwarg. Everything else is additive with v6.x observable
behaviour preserved at defaults.
TL;DR — if your code does not reference
SymfonicAgent(enable_hms_prompt=...), upgrading is a drop-in.
Breaking changes¶
B1 — SymfonicAgent(enable_hms_prompt=...) removed¶
Status: Landed.
The constructor kwarg has emitted DeprecationWarning since v5.6.0.
In v7.0 it raises TypeError because Python does not accept unknown
keyword arguments.
Before (v6.x)¶
from symfonic.agent.engine import SymfonicAgent
agent = SymfonicAgent(
model_provider=provider,
enable_hms_prompt=True, # deprecated kwarg
)
After (v7.0)¶
from symfonic.agent.config import FrameworkConfig
from symfonic.agent.engine import SymfonicAgent
config = FrameworkConfig(enable_hms_prompt=True)
agent = SymfonicAgent(
model_provider=provider,
config=config,
)
The FrameworkConfig path has been available since v6.0 and is
unchanged in v7.0.
Migration script¶
Run this one-liner to detect the pattern across a codebase:
If nothing matches, you are done.
Additive changes (no migration required)¶
FrameworkConfig knobs¶
| Field | Default | v6.x behaviour at default | To change behaviour |
|---|---|---|---|
intent_filter_mode |
"off" |
Classifier never runs; full hydration every turn | "observe" for telemetry only; "enforce" to skip semantic/episodic/procedural on action verdicts |
hydration_max_hops |
0 |
Single asyncio.gather of 1st-degree neighbours (byte-identical to v6.1.x) |
>=1 enables BFS with per-hop decay |
stm_summary_mode |
"off" |
WorkingLayer.summarize() returns "" (legacy stub) |
"extractive" produces bullets with no LLM cost; "llm" issues one micro-call with extractive fallback |
fabrication_check_mode |
"off" |
Detector never runs; v6.1.10 TOOL DISCIPLINE prompt directive is the only defence | "observe" emits telemetry; "revise" forces metacog revise; "refuse" replaces draft with safe envelope |
nightly_nap_enabled |
False |
nightly_nap method available but operator-invoked |
Schedule agent._sleep_consolidator.nightly_nap(scope) via your scheduler |
nightly_nap_cron |
"0 3 * * *" |
No effect — recommendation only | Set to your preferred off-peak cron expression |
DomainTemplate additions¶
| Field | Default | Purpose |
|---|---|---|
identifier_keys |
[] |
Extra keys the fabrication detector should flag in addition to the built-in lexicon (task_id, pid, job_id, ...). Empty preserves v6.x behaviour. |
AgentResponse additions¶
| Field | Default | Populated when |
|---|---|---|
intent_verdict |
None |
intent_filter_mode != "off" |
fabrication_findings |
None |
fabrication_check_mode != "off" AND detector fires |
Enabling the new subsystems¶
The v7.0 subsystems are opt-in. Here is a recommended adoption order:
1. Intent filter (lowest risk)¶
Start in observe mode for a burn-in week. The classifier emits
ExtensionEvent(type="intent_classified") to callback handlers that
implement on_intent_classified. Tune the corpus before flipping to
enforce.
Once confident, flip to enforce:
2. N-hop spreading¶
Start with hydration_max_hops=1 (explicit 1-hop, still a single
BFS level but now with spreading_access_count bumping per v6.2 T02).
Measure payload size and latency before raising:
The default base_decay=0.5 and max_total_nodes=50 guard against
runaway expansion.
3. STM summary¶
Start with extractive — zero LLM cost, deterministic output:
Upgrade to "llm" if your domain needs better compression and you
are willing to pay one micro-call per summary. The extractive path
is the automatic fallback on LLM failure.
4. Fabrication check¶
Start in observe to collect findings:
Implement on_fabrication_detected on your callback handler to
capture the events. When confident the detector is not producing
false positives, escalate to revise or refuse.
fabrication_check_mode='revise'requiresmetacognition_enabled=True. Therevisepath threads findings intoMetacognitiveMiddleware.evaluate()to produce a genuine revised draft. Without metacog enabled there is no reviser to run, so the agent emits aUserWarningat construction and downgrades the effective mode torefusesemantics (safe-envelope replacement +fabrication_blockedevent). If you want real revise behaviour, pair the two flags:
5. nightly_nap¶
Enable the entrypoint:
config = FrameworkConfig(
nightly_nap_enabled=True,
nightly_nap_cron="0 3 * * *", # 03:00 UTC daily
)
Wire your scheduler (APScheduler / celery-beat / external cron) to
invoke agent._sleep_consolidator.nightly_nap(scope) per tenant at
the recommended cron cadence. The engine does not schedule this
itself — operator responsibility.
Tests¶
v7.0.0 adds dedicated test files per subsystem; your test suite should remain green after the upgrade because defaults preserve v6.x behaviour. If a v6-era test fails, please file an issue — it indicates an inadvertent default flip.
tests/agent/triage/test_intent_classifier.py— T06tests/agent/triage/test_intent_wiring.py— T07tests/memory/unit/test_spreading_nhop.py— T08tests/memory/unit/working/test_stm_summary.py— T09tests/agent/middleware/test_fabrication.py— T10tests/agent/middleware/test_fabrication_wiring.py— T11tests/core/learning/test_nightly_nap.py— T12tests/release/test_v7_0_0_release_gate.py— T15 pin
v7.0.2 note — DomainTemplate.description now reaches the LLM¶
DomainTemplate.description has been a public field since v5.6.x,
but no prompt builder ever consumed it — every value set there was
silently dropped. v7.0.2 wires it into both the full HMS and JIT
system prompts for the first time.
If your v6.x / v7.0.0 / v7.0.1 deployment set
DomainTemplate(description="..."), upgrading to v7.0.2 will cause
that prose to reach the LLM's system prompt. This can affect:
- Token budgets — the prompt will be larger in both modes.
- LLM behaviour — the directives will actually steer responses. Review the description text before upgrading.
- Truncation — descriptions over 2000 chars (full HMS) or 400
chars (JIT) are capped and marked
... [truncated], with a single WARNING log per agent lifetime. Raise the caps via the newFrameworkConfig.domain_description_max_charstuple if needed:
cfg = FrameworkConfig(
domain=DomainTemplate(description="..."),
domain_description_max_chars=(5000, 800), # (full_hms, jit)
)
No migration is required for callers who never populated
domain.description — the rendered prompt shows a short fallback
which the LLM treats as a no-op.
See docs/releases/v7.0.2.md for the full
rationale including why the JIT template uses an inline line
instead of a new ## 1a. section.
References¶
docs/releases/v7.0.0.md— full release notes.docs/releases/v7.0-plan.md— execution plan with per-task acceptance criteria.docs/releases/v6.2.0.md— preceding additive carve-out (T01-T05).