feat: expose tool traces to memory providers#28065
Conversation
b9f553b to
ffbab38
Compare
ffbab38 to
d531b1b
Compare
Added a new function, _record_turn_tool_trace, to facilitate per-turn tool tracing for agents. This function is invoked in multiple locations within execute_tool_calls_concurrent and execute_tool_calls_sequential to record trace data, enhancing the tracking of tool call executions. This change improves the observability of agent actions during tool interactions.
|
Thanks for reworking this as a standalone plugin + generic hook rather than an in-tree provider — that's the right call, and the backward-compat signature inspection is clean. Before we lock in a new structured-trace contract though, I want to make sure we're not adding core surface we already have. A couple of things: The full message list — tool calls and results included — is already handed to providers via The genuine gap is timing/granularity: But the minimal fix for that is to thread the existing The part that genuinely isn't reconstructable from the message list is the per-tool Happy to merge a slimmed-down version quickly. Feel free to push back if I'm missing why the structured envelope needs to live in core. |
|
Thanks for the feedback! That framing makes sense. I’ll slim this down to pass the existing OpenAI-style I don’t think duration/block/cancel metadata is essential, so that is fine! I'll have an updated PR shortly! |
|
@kshitijk4poor this PR has been slimmed down and incorporates the feedback you've provided. Thank you!! |
Adds an optional `messages` keyword to the `MemoryProvider.sync_turn` contract so external/community memory plugins can receive the OpenAI-style conversation message list for the completed turn — including assistant tool calls and tool result content — not just the final assistant text. Dispatch uses signature inspection (`_provider_sync_accepts_messages`): only providers that declare a `messages` parameter (or `**kwargs`) receive it; all existing in-tree providers keep their legacy text-only signature and are called unchanged. No structured-trace envelope is added to core — providers reconstruct whatever they need from the standard message list. Also documents Memori as a standalone community memory provider. Salvaged from NousResearch#28065 — rebased onto current main. Co-authored-by: Dave Heritage <david@memorilabs.ai>
Maps both commit emails (david@memorilabs.ai, dave@devwdave.com) used on NousResearch#28065 to the devwdave GitHub account so the contributor audit in scripts/release.py passes.
…sages feat: expose completed-turn message context to memory providers (salvage #28065)
Adds an optional `messages` keyword to the `MemoryProvider.sync_turn` contract so external/community memory plugins can receive the OpenAI-style conversation message list for the completed turn — including assistant tool calls and tool result content — not just the final assistant text. Dispatch uses signature inspection (`_provider_sync_accepts_messages`): only providers that declare a `messages` parameter (or `**kwargs`) receive it; all existing in-tree providers keep their legacy text-only signature and are called unchanged. No structured-trace envelope is added to core — providers reconstruct whatever they need from the standard message list. Also documents Memori as a standalone community memory provider. Salvaged from NousResearch#28065 — rebased onto current main. Co-authored-by: Dave Heritage <david@memorilabs.ai> #AI commit#
Maps both commit emails (david@memorilabs.ai, dave@devwdave.com) used on NousResearch#28065 to the devwdave GitHub account so the contributor audit in scripts/release.py passes. #AI commit#
Adds an optional `messages` keyword to the `MemoryProvider.sync_turn` contract so external/community memory plugins can receive the OpenAI-style conversation message list for the completed turn — including assistant tool calls and tool result content — not just the final assistant text. Dispatch uses signature inspection (`_provider_sync_accepts_messages`): only providers that declare a `messages` parameter (or `**kwargs`) receive it; all existing in-tree providers keep their legacy text-only signature and are called unchanged. No structured-trace envelope is added to core — providers reconstruct whatever they need from the standard message list. Also documents Memori as a standalone community memory provider. Salvaged from NousResearch#28065 — rebased onto current main. Co-authored-by: Dave Heritage <david@memorilabs.ai>
Maps both commit emails (david@memorilabs.ai, dave@devwdave.com) used on NousResearch#28065 to the devwdave GitHub account so the contributor audit in scripts/release.py passes.
The OpenVikingMemoryProvider.sync_turn() previously only received user_content and assistant_content as plain text (truncated to 4K each), discarding all tool calls, tool results, and intermediate messages from multi-step agent turns. This commit wires the optional messages kwarg (added in commit 5a95fb2 / NousResearch#28065) to OpenViking's session sync path: - Accept messages: Optional[List[Dict]] in sync_turn() signature - Track _last_message_count to POST only the delta of new messages on each turn (avoids re-sending entire history every call) - Serialize tool_calls to compact text form for the session API - Include role:tool messages (tool results) alongside user/assistant - Skip system prompts (session-wide state, not conversational turns) - Reset _last_message_count in initialize() and on_session_switch() - Keep legacy text-only fallback when messages is not provided Closes NousResearch#34762
Adds an optional `messages` keyword to the `MemoryProvider.sync_turn` contract so external/community memory plugins can receive the OpenAI-style conversation message list for the completed turn — including assistant tool calls and tool result content — not just the final assistant text. Dispatch uses signature inspection (`_provider_sync_accepts_messages`): only providers that declare a `messages` parameter (or `**kwargs`) receive it; all existing in-tree providers keep their legacy text-only signature and are called unchanged. No structured-trace envelope is added to core — providers reconstruct whatever they need from the standard message list. Also documents Memori as a standalone community memory provider. Salvaged from NousResearch#28065 — rebased onto current main. Co-authored-by: Dave Heritage <david@memorilabs.ai>
Maps both commit emails (david@memorilabs.ai, dave@devwdave.com) used on NousResearch#28065 to the devwdave GitHub account so the contributor audit in scripts/release.py passes.
Adds an optional `messages` keyword to the `MemoryProvider.sync_turn` contract so external/community memory plugins can receive the OpenAI-style conversation message list for the completed turn — including assistant tool calls and tool result content — not just the final assistant text. Dispatch uses signature inspection (`_provider_sync_accepts_messages`): only providers that declare a `messages` parameter (or `**kwargs`) receive it; all existing in-tree providers keep their legacy text-only signature and are called unchanged. No structured-trace envelope is added to core — providers reconstruct whatever they need from the standard message list. Also documents Memori as a standalone community memory provider. Salvaged from NousResearch#28065 — rebased onto current main. Co-authored-by: Dave Heritage <david@memorilabs.ai>
Maps both commit emails (david@memorilabs.ai, dave@devwdave.com) used on NousResearch#28065 to the devwdave GitHub account so the contributor audit in scripts/release.py passes.
Adds an optional `messages` keyword to the `MemoryProvider.sync_turn` contract so external/community memory plugins can receive the OpenAI-style conversation message list for the completed turn — including assistant tool calls and tool result content — not just the final assistant text. Dispatch uses signature inspection (`_provider_sync_accepts_messages`): only providers that declare a `messages` parameter (or `**kwargs`) receive it; all existing in-tree providers keep their legacy text-only signature and are called unchanged. No structured-trace envelope is added to core — providers reconstruct whatever they need from the standard message list. Also documents Memori as a standalone community memory provider. Salvaged from NousResearch#28065 — rebased onto current main. Co-authored-by: Dave Heritage <david@memorilabs.ai>
Maps both commit emails (david@memorilabs.ai, dave@devwdave.com) used on NousResearch#28065 to the devwdave GitHub account so the contributor audit in scripts/release.py passes.
…ri-trace-messages feat: expose completed-turn message context to memory providers (salvage NousResearch#28065)
What does this PR do?
Adds Memori to the community plugin documentation as a standalone external memory provider, and adds the generic memory-provider trace support needed for providers like Memori to capture meaningful agent memory.
This does not add Memori as an in-tree provider. Memori remains distributed as a standalone community plugin/package. The Hermes-side change is a backward-compatible optional
tracepayload for external memory providers, so they can receive structured completed-turn tool execution metadata.Trace data is critical for agent memory because the final assistant response often does not contain the actual work the agent performed. For example, an assistant may say “Tests passed,” but the useful memory is that Hermes ran
terminal({"command": "pytest"}), received the test output, and then summarized it. Without trace data, external memory only captures what the assistant said, not what the agent actually did.Existing memory providers remain compatible. Hermes only passes
traceto providers whosesync_turn()accepts it.Related Issue
Fixes #
Type of Change
Changes Made
README.mdhermes-memorito the community plugins section.website/docs/user-guide/features/memory-providers.mdagent/memory_provider.pytraceparameter to theMemoryProvider.sync_turn()interface.agent/memory_manager.pysync_all()to accept an optionaltrace.sync_turn(user, assistant, session_id=...)shape.agent/agent_init.pyagent/conversation_loop.pyagent/tool_executor.pyrun_agent.pytests/agent/test_memory_provider.pytests/run_agent/test_memory_sync_interrupted.pywebsite/docs/developer-guide/memory-provider-plugin.mdtraceargument forsync_turn().How to Test
Run the focused memory provider and trace tests:
Verify the focused test suite passes:
Optionally test with a memory provider whose
sync_turn()acceptstrace=Noneand confirm it receives a payload like:{ "version": 1, "capture_policy": "full_raw_after_hermes_processing", "tool_calls": [ { "order": 1, "name": "terminal", "arguments": {"command": "pytest"}, "result_content": "...", "duration_seconds": 2.21, "is_error": false, "blocked": false, "cancelled": false } ] }Checklist
Code
fix(scope):,feat(scope):, etc.)pytest tests/ -qand all tests passDocumentation & Housekeeping
docs/, docstrings) — or N/Acli-config.yaml.exampleif I added/changed config keys — or N/ACONTRIBUTING.mdorAGENTS.mdif I changed architecture or workflows — or N/AFor New Skills
N/A
Screenshots / Logs
Focused test run: