Skip to content

feat: allow custom session metadata enrichment in watch() API#439

Open
arcgod-design wants to merge 2 commits into
sreerevanth:mainfrom
arcgod-design:feat/issue-147-session-metadata
Open

feat: allow custom session metadata enrichment in watch() API#439
arcgod-design wants to merge 2 commits into
sreerevanth:mainfrom
arcgod-design:feat/issue-147-session-metadata

Conversation

@arcgod-design

@arcgod-design arcgod-design commented Jun 18, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Adds metadata keyword argument to watch() and GenericAdapter.__init__()
  • Custom metadata is attached to all events emitted in the session
  • Session metadata is seeded from the first event's metadata in TraceCollector.ingest()
  • Adds 5 new tests for metadata enrichment

Changes

  • agentwatch/core/watcher.py: Added metadata param to GenericAdapter.__init__, _emit_safely, _async_emit, and watch(). Merges session metadata into all events.
  • agentwatch/tracing/collector.py: Seeds session metadata from first event's metadata on session creation.
  • tests/test_watcher.py: Added 5 new tests for metadata functionality.

Usage

from agentwatch import watch

agent = MyAgent()
watch(agent, metadata={"user_id": "u-123", "tenant": "acme", "env": "prod"})

Testing

All 28 watcher tests pass, including 5 new metadata tests:

  • test_watch_metadata_attached_to_events
  • test_watch_metadata_merged_with_call_metadata
  • test_watch_no_metadata_empty_dict
  • test_generic_adapter_metadata_stored
  • test_generic_adapter_empty_metadata

Closes

closes #147

Summary by CodeRabbit

  • New Features
    • Added support for custom session metadata when starting agent watching; provided metadata is included in SESSION_START and merged into subsequent agent events.
    • Session metadata is now also propagated into safety-related tool-call events.
  • Bug Fixes
    • Improved trace/session ingestion so trace sessions pick up metadata from incoming events.
  • Tests
    • Added coverage for custom session metadata behavior and default handling.

@coderabbitai

coderabbitai Bot commented Jun 18, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 4d0fe4e2-066d-454a-90af-532614288747

📥 Commits

Reviewing files that changed from the base of the PR and between ec26add and 5eb85df.

📒 Files selected for processing (1)
  • agentwatch/core/watcher.py
🚧 Files skipped from review as they are similar to previous changes (1)
  • agentwatch/core/watcher.py

📝 Walkthrough

Walkthrough

Adds an optional metadata: dict[str, Any] | None parameter to watch() and GenericAdapter.__init__. The adapter stores it as _session_metadata and merges it into the payload of every emitted AgentEvent via _emit_safely, _async_emit, and the safety tool-call paths. TraceCollector.ingest now seeds the AgentSession.metadata from the first event's metadata. Tests cover all new behaviors.

Changes

Custom Session Metadata Enrichment

Layer / File(s) Summary
watch() and GenericAdapter constructor
agentwatch/core/watcher.py
watch() adds metadata: dict[str, Any] | None = None to its signature and docstring, and forwards it to GenericAdapter. GenericAdapter.__init__ accepts the same parameter and stores it as _session_metadata, defaulting to {}.
Framework-specific metadata attachment
agentwatch/core/watcher.py
_attach_langchain, _attach_langgraph, _attach_autogen, and _attach_smolagents now accept metadata and assign it into each adapter's _session_metadata when provided.
Metadata merging in event emission
agentwatch/core/watcher.py
_emit_safely and _async_emit compute a merged dict of _session_metadata and per-event metadata before building AgentEvent, ensuring all events carry session context.
Safety-gated tool-call metadata wiring
agentwatch/core/watcher.py
Both async and sync safety TOOL_CALL event constructions wire _session_metadata into the event payload.
TraceCollector session metadata seeding
agentwatch/tracing/collector.py
TraceCollector.ingest calls trace.session.metadata.update(event.metadata) after creating a new AgentSession for an unseen session_id, when event.metadata is present.
Tests
tests/test_watcher.py
Adds five tests: SESSION_START event carries provided metadata; non-SESSION_START events merge it; absence of metadata yields no user_id; GenericAdapter stores metadata in _session_metadata; GenericAdapter defaults _session_metadata to {}.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

Poem

🐇 Hop, hop, a metadata treat,
A user_id tucked in, oh how neat!
Every event now carries the key,
From watch() to session, flowing free.
The rabbit stamps each trace with care —
Custom context, everywhere! 🌿

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 38.10% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately and concisely summarizes the main change: adding custom session metadata enrichment to the watch() API, which is the primary focus of all modifications across the three files.
Linked Issues check ✅ Passed All coding requirements from issue #147 are met: watch() and GenericAdapter now accept optional metadata parameter, metadata is merged into all emitted events, and session metadata is seeded from first event in TraceCollector.ingest().
Out of Scope Changes check ✅ Passed All changes are directly scoped to issue #147 requirements: metadata parameter additions in watcher.py and GenericAdapter, metadata merging in event emission paths, session metadata seeding in collector.py, and corresponding test coverage for the new functionality.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
agentwatch/core/watcher.py (1)

583-599: ⚠️ Potential issue | 🟠 Major | 🏗️ Heavy lift

Metadata is not propagated for framework-specific adapters.

Line 584, Line 588, Line 592, and Line 596 call framework-specific attachers without forwarding metadata, while only the generic fallback receives it at Line 609. This breaks the watch-level contract for LangChain/LangGraph/Autogen/Smolagents sessions.

Also applies to: 609-610

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@agentwatch/core/watcher.py` around lines 583 - 599, The framework-specific
attacher functions _attach_langchain, _attach_langgraph, _attach_autogen, and
_attach_smolagents are being called without passing the metadata argument, while
the generic fallback case does pass it. Add metadata as an argument to each of
these four function calls to ensure consistent metadata propagation across all
framework adapters and maintain the watch-level contract.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@agentwatch/core/watcher.py`:
- Line 243: The metadata dictionary is stored by reference in
self._session_metadata at line 243 and reused directly in TOOL_CALL events at
lines 310-311 and 386-387. Any downstream mutation of the metadata dict will
affect all future events. Fix this by creating a snapshot copy when storing
metadata in self._session_metadata initialization, and creating independent
copies of self._session_metadata when emitting TOOL_CALL events at those
locations to ensure each event has its own isolated metadata dictionary.

---

Outside diff comments:
In `@agentwatch/core/watcher.py`:
- Around line 583-599: The framework-specific attacher functions
_attach_langchain, _attach_langgraph, _attach_autogen, and _attach_smolagents
are being called without passing the metadata argument, while the generic
fallback case does pass it. Add metadata as an argument to each of these four
function calls to ensure consistent metadata propagation across all framework
adapters and maintain the watch-level contract.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 78293598-1cdf-43a0-b099-2f28a82db6cf

📥 Commits

Reviewing files that changed from the base of the PR and between 3b1f4b5 and ec26add.

📒 Files selected for processing (3)
  • agentwatch/core/watcher.py
  • agentwatch/tracing/collector.py
  • tests/test_watcher.py

Comment thread agentwatch/core/watcher.py Outdated
@github-actions

Copy link
Copy Markdown

🧪 PR Test Results

Check Result
Tests (pytest tests/) ✅ success
Lint (ruff check .) ✅ success
Coverage (agentwatch) 73.27%

Python 3.12 · commit 5eb85df

@sreerevanth

Copy link
Copy Markdown
Owner

@arcgod-design please check your prs

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Feat] allow custom session metadata enrichment in watch() API

2 participants