You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: docs/agent-framework.md
+23-2Lines changed: 23 additions & 2 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -48,7 +48,7 @@ derives from `Microsoft.Agents.AI.AIContextProvider` and implements the framewor
48
48
| MAF hook (C#) | When | What AgentMemory does | Python equivalent |
49
49
|---|---|---|---|
50
50
|`ProvideAIContextAsync(InvokingContext)` → `AIContext`|**Before** the model call | Embeds the user turn, recalls relevant memory, and returns it as `AIContext.Messages` to prepend to the prompt. |`before_run`|
51
-
|`StoreAIContextAsync(InvokedContext)`|**After** the response | Persists the response messages and (optionally) runs extraction into the graph. Skipped if the run threw (`context.InvokeException`). |`after_run`|
51
+
|`StoreAIContextAsync(InvokedContext)`|**After** the response | Persists the response messages and (optionally) runs extraction over the complete turn (request + response) into the graph. Skipped if the run threw (`context.InvokeException`). |`after_run`|
52
52
53
53
This is the same **bidirectional** behavior the official provider describes ("auto-retrieve before
54
54
invocation, auto-save after responses") — recall is passive and automatic; you never call it by hand.
@@ -58,7 +58,28 @@ Native recall via `Neo4jMemoryContextProvider` respects your configured `MemoryO
58
58
`IMemoryService.RecallAsync(...)` call (#87). The one exception is `RecallOptions.Scope`: native recall
59
59
always derives scope from the invocation's authenticated owner (via #100's isolation policy), never from a
60
60
statically configured `Scope`, so a global config value can't silently override the real, per-invocation
61
-
owner. `Neo4jMicrosoftMemoryFacade` (the lower-level, manually-driven alternative to the context provider)
61
+
owner. Automatic extraction (`AutoExtractOnPersist`) considers the **complete turn** — both what the user asked
62
+
and what the assistant answered (#89), filtered to user-role content so a system prompt or other non-user
63
+
text isn't minted into spurious entities/facts/preferences every turn — so a preference or fact the user
64
+
states is captured even if the assistant never repeats it back. `Neo4jChatHistoryProvider` persists both
65
+
request and response messages as real `:Message` nodes (unchanged), so extraction there has full
66
+
provenance. `Neo4jMemoryContextProvider` deliberately does **not** persist request messages as new nodes
67
+
— only response messages are — because a host may already have `Neo4jChatHistoryProvider`,
68
+
`Neo4jChatMessageStore`, or their own component persisting the same request messages on the same agent,
69
+
and there is no idempotency mechanism (no caller-supplied message id, no upsert-by-content) that would let
70
+
this provider safely avoid creating a duplicate `:Message` node for the same logical message. The
71
+
practical effect: a fact/preference extracted from the user's own request is still created and recallable,
72
+
but both its `EXTRACTED_FROM` provenance edge and its own `source_message_ids` property will reference a
73
+
message id that was never persisted, unless another component also persisted that exact message.
74
+
75
+
**This asymmetry is deliberate for requests, but note it does not (yet) extend to responses**: both
76
+
`Neo4jMemoryContextProvider` and `Neo4jChatHistoryProvider` persist response messages unconditionally, with
77
+
the same lack of an idempotency mechanism — so combining both providers (or either with
78
+
`Neo4jChatMessageStore`/a custom component) on the same agent can still duplicate **response**`:Message`
79
+
nodes today. Avoid wiring more than one message-persisting component onto the same agent until a real
80
+
cross-component idempotency mechanism exists.
81
+
82
+
`Neo4jMicrosoftMemoryFacade` (the lower-level, manually-driven alternative to the context provider)
62
83
does not yet wire configured `RecallOptions` into its own recall call — a known gap for a future pass, not
0 commit comments