Skip to content

Enable fact and instruction memories from Chat admin settings without agents or actions - #1356

Merged
Paul Lizer (paullizer) merged 3 commits into
Developmentfrom
paullizer-chat-facts-memories-toggle
Aug 25, 2026
Merged

Enable fact and instruction memories from Chat admin settings without agents or actions#1356
Paul Lizer (paullizer) merged 3 commits into
Developmentfrom
paullizer-chat-facts-memories-toggle

Conversation

@paullizer

Copy link
Copy Markdown
Contributor

Fixes #1352
Partially advances #1153

Version locked at 0.261.001.

Problem

Fact memory was presented purely as an agent action, which caused two distinct problems.

Discoverability. The only control was enable_fact_memory_plugin in Agents & Actions → Actions, labeled "Enable Fact Memory Action". An admin running plain chat had no reason to open that tab, so they never found the switch — even though memory recall already worked without agents.

A real functional gap. Recall was agent-free, but creating, updating, and deleting memories was not. FactMemoryPlugin was only attached to a kernel with automatic function calling on the Semantic Kernel agent path, so "remember that I prefer bullet points" or "stop calling me Paul" silently did nothing unless agents were enabled.

Approach

Mirrors the existing Tabular Processing precedent: the capability is owned by the tab it actually belongs to, and the Actions pane keeps a read-only dependency note.

Admin control moved to Chat

enable_fact_memory_plugin remains the single settings key, so existing deployments keep their value and no migration is required. What changed is ownership:

  • Live toggle now renders in Chat → Chat Experience → Fact Memory (fact-memory-section), saved by the main admin settings form.
  • Actions pane shows a read-only fact-memory-dependency-note pointing at Chat, exactly like tabular-processing-dependency-note points at Enhanced Citations.
  • Added is_fact_memory_enabled() to functions_settings.py and registered the section in admin_settings_nav.py.

⚠️ Save-path hazard this created, and how it's handled

The Actions toggle saved through POST /api/admin/plugins/settings, where enable_fact_memory_plugin was a required field. Removing the input without relaxing that contract would have made admin_settings.js resolve the element to null and post enable_fact_memory_plugin: false — meaning toggling any unrelated core action would have silently disabled fact memory.

The key moves to deprecated_optional_keys: accepted so older clients don't 400, never written from that endpoint. The JS no longer sends it, and instead refreshes the Actions note from the GET response.

Agent-free memory writes

New application/single_app/functions_fact_memory_autosave.py, modeled on the existing tabular mini-SK runner:

  • user_requested_memory_update() — pure intent pre-filter in the style of the existing user_requested_chart_visualization(). Matches explicit save/change/forget language and screens out recall questions ("do you remember…") so the broad remember pattern doesn't fire a write pass on every such turn.
  • should_run_fact_memory_autosave() — combines the filter with the admin toggle, and skips when an agent ran since that path already had the tool inline.
  • run_fact_memory_autosave() — a Kernel carrying only FactMemoryPlugin, service id fact-memory-autosave, executed with FunctionChoiceBehavior.Auto filtered to the fact_memory plugin.

Design constraints that shaped this:

  • Runs after the assistant response is finalized in both the standard and streaming paths, so it can never alter or delay the answer the user sees.
  • Runs inside the originating requestFactMemoryPlugin resolves its authorization boundary from g.authorized_chat_context, which is what prevents a tool call from writing outside the caller's own user or group scope. This rules out background execution.
  • Gated by the pre-filter, so ordinary chat turns pay no extra model call.
  • Every failure is contained and logged. A memory problem never breaks a chat response.

Changes surface as fact_memory processing thoughts in both paths.

flowchart TD
    A[User turn] --> B{enable_fact_memory_plugin?}
    B -- no --> Z[Normal chat, no memory]
    B -- yes --> C[Recall: inject instruction + relevant fact memories]
    C --> D[Generate assistant response]
    D --> E{Agent path handled it?}
    E -- yes --> Y[Agent already had fact_memory tool - skip]
    E -- no --> F{user_requested_memory_update?}
    F -- no --> Y2[Skip - no extra model call]
    F -- yes --> G[Mini-SK kernel: FactMemoryPlugin only]
    G --> H[set_fact / update_fact / delete_fact]
    H --> I[Emit fact_memory thought + persist message]
Loading

Validation

New coverage:

Test Result Covers
test_chat_fact_memory_admin_placement.py 8/8 Chat pane card, Actions read-only note, single form-field ownership across every admin pane, nav registration, admin form persistence, plugins endpoint contract, JS payload regression
test_chat_fact_memory_autosave.py 7/7 Intent positives/negatives, gating, mini-kernel composition and tool filtering, change reporting, graceful degradation, route wiring across both paths

Existing suites re-run green: test_fact_memory_profile_and_mini_sk.py, test_admin_settings_field_contract.py (451 baseline fields intact, no duplicate field names), test_docs_app_surface_coverage.py, test_docs_site_quality.py, and all three route_tests/ policy suites.

Nine adjacent tests fail, but they fail identically on a clean worktree at HEAD — verified with git worktree add --detach — so no regressions were introduced by this change.

Also repairs a stale path in test_fact_memory_profile_and_mini_sk.py that had been silently breaking since the feature doc moved into docs/explanation/features/v0.241.001/.

Documentation

  • New feature doc: docs/explanation/features/v0.261.001/CHAT_FACT_MEMORY_WITHOUT_AGENTS.md
  • docs/admin/chat.md — new Fact Memory section and settings row
  • docs/admin/agents-actions.md and docs/reference/actions/fact-memory.md — now point at Chat
  • docs/_data/features.yml — key re-claimed under a new chat-memory feature (admin_tab: chat), removed from core-actions
  • docs/_data/app_surface.yml — regenerated via scripts/build_docs_inventory.py
  • docs/explanation/release_notes.md — new v0.261.001 section

Notes for reviewers

  • No new Flask routes, so no new @swagger_route decorators are needed; route policy suites confirm this.
  • No new browser assets — all JS changes are within the existing local static/js/admin/admin_settings.js.
  • Nothing under deployers/ changed, so deployers/version.txt is untouched.
  • Scope: this delivers the explicit save/update/forget path. The inferred memory proposal cards with approve/deny/edit remain tracked in Add normal chat support for creating fact and instruction memories #1153; the first two acceptance criteria there are now satisfied.

Paul Lizer (paullizer) and others added 3 commits August 25, 2026 16:39
Fact memory was configured only from Agents & Actions, which hid a plain-chat
capability behind an agents workflow, and memory writes genuinely required
agents because FactMemoryPlugin was only attached to a kernel with automatic
function calling on the Semantic Kernel agent path.

Move the control to Chat > Chat Experience as the single source of truth,
reusing enable_fact_memory_plugin so no migration is needed. The Actions pane
now carries a read-only dependency note, mirroring how Tabular Processing
points at Enhanced Citations.

The Actions toggle previously saved through POST /api/admin/plugins/settings
where the key was a REQUIRED field, so removing the input without relaxing
that contract would have made the browser post enable_fact_memory_plugin:
false. Toggling any unrelated core action would then have silently disabled
fact memory. The key moves to deprecated_optional_keys: accepted for older
clients, never written from that endpoint.

Add agent-free memory writes via functions_fact_memory_autosave.py, a small
kernel carrying only the fact-memory plugin, modeled on the existing tabular
mini-SK runner. It runs after the assistant response is finalized in both the
standard and streaming paths, so it cannot alter or delay the answer, and is
gated by user_requested_memory_update() so ordinary turns pay no extra model
call. The pass must run inside the originating request because the plugin
resolves its authorization boundary from g.authorized_chat_context, which is
what keeps a tool call inside the caller's own user or group scope. All
failures are contained and logged.

Also repairs a stale feature-doc path in test_fact_memory_profile_and_mini_sk
that broke when the doc moved into docs/explanation/features/v0.241.001/.

Version locked at 0.261.001.

Refs #1352
Partially advances #1153

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
…-facts-memories-toggle

# Conflicts:
#	docs/_data/app_surface.yml
The in-app Latest Features catalog still described fact memory as a
profile-only experience. Update the card so it reflects that the
assistant now saves, changes, and removes memories during normal chat
when a user asks, and that profile remains the place to review and
edit everything saved.

Refs #1352

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
@paullizer
Paul Lizer (paullizer) merged commit caac445 into Development Aug 25, 2026
12 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant