Summary
Session-owned LLM calls are starting to rely on SessionDiagnosticsContext so provider-layer MEL diagnostics can be mirrored into the canonical per-session log. Right now only the main turn path goes through SessionLlmInvoker, but there are still direct IChatClient call sites in session-owned code that can bypass the ambient session diagnostics scope.
Why this matters
When a session-owned code path calls GetResponseAsync or GetStreamingResponseAsync without first establishing the session diagnostics context, those provider logs still land in the daemon log but not in the session log. That makes session-level troubleshooting incomplete and easy to regress when new sidecar paths are added.
Current examples
src/Netclaw.Actors/Memory/MemoryCurationActor.cs
src/Netclaw.Actors/Sessions/LlmSessionActor.cs
src/Netclaw.Actors/Sessions/Pipelines/SessionCompactionPipeline.cs
src/Netclaw.Actors/Sessions/Pipelines/SessionTitleGenerator.cs
src/Netclaw.Actors/Sessions/SessionMemoryObserverActor.cs
src/Netclaw.Actors/SubAgents/SubAgentActor.cs
Proposal
Add a Roslyn analyzer that flags session-owned direct IChatClient.GetResponseAsync(...) / GetStreamingResponseAsync(...) calls unless they are:
- routed through the approved session wrapper/invoker, or
- enclosed in a
SessionDiagnosticsContext.Push(sessionId) scope.
This does not need to solve every possible dataflow case. A targeted analyzer that catches the common direct-call patterns in Netclaw.Actors.Sessions, Netclaw.Actors.SubAgents, and related session-owned actor/pipeline code would still be valuable.
Acceptance criteria
- Analyzer reports a diagnostic for direct session-owned
IChatClient calls that bypass session diagnostics scoping.
- Analyzer documents the approved patterns.
- At least one code fix or remediation message points developers toward the wrapper/scope pattern.
Summary
Session-owned LLM calls are starting to rely on
SessionDiagnosticsContextso provider-layer MEL diagnostics can be mirrored into the canonical per-session log. Right now only the main turn path goes throughSessionLlmInvoker, but there are still directIChatClientcall sites in session-owned code that can bypass the ambient session diagnostics scope.Why this matters
When a session-owned code path calls
GetResponseAsyncorGetStreamingResponseAsyncwithout first establishing the session diagnostics context, those provider logs still land in the daemon log but not in the session log. That makes session-level troubleshooting incomplete and easy to regress when new sidecar paths are added.Current examples
src/Netclaw.Actors/Memory/MemoryCurationActor.cssrc/Netclaw.Actors/Sessions/LlmSessionActor.cssrc/Netclaw.Actors/Sessions/Pipelines/SessionCompactionPipeline.cssrc/Netclaw.Actors/Sessions/Pipelines/SessionTitleGenerator.cssrc/Netclaw.Actors/Sessions/SessionMemoryObserverActor.cssrc/Netclaw.Actors/SubAgents/SubAgentActor.csProposal
Add a Roslyn analyzer that flags session-owned direct
IChatClient.GetResponseAsync(...)/GetStreamingResponseAsync(...)calls unless they are:SessionDiagnosticsContext.Push(sessionId)scope.This does not need to solve every possible dataflow case. A targeted analyzer that catches the common direct-call patterns in
Netclaw.Actors.Sessions,Netclaw.Actors.SubAgents, and related session-owned actor/pipeline code would still be valuable.Acceptance criteria
IChatClientcalls that bypass session diagnostics scoping.