Add LLM tool call diagnostics#351
Conversation
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (2)
🚧 Files skipped from review as they are similar to previous changes (1)
📝 WalkthroughWalkthroughAdds ExceptionExtensions and applies concise exception-summary logging and richer diagnostics across LLM tool execution, MCP orchestration, agent loops, polling/consumption, streaming, and global Serilog configuration; includes Env log-level parsing and tests. ChangesError Logging and Observability Enhancement
Estimated code review effort🎯 4 (Complex) | ⏱️ ~75 minutes Possibly related PRs
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
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. Comment |
There was a problem hiding this comment.
Actionable comments posted: 3
🧹 Nitpick comments (2)
TelegramSearchBot/Service/AI/LLM/ChunkPollingService.cs (1)
75-79: 💤 Low valueConsider adding context to loop-level exception logs.
The exception logs at lines 76 and 78 could benefit from additional context similar to the per-task logs (lines 58, 60). Consider logging the count of tracked tasks or other diagnostic state to aid troubleshooting when the entire polling loop encounters errors.
💡 Example enhancement
} catch (RedisException ex) { - _logger.LogWarning(ex, "Redis error in ChunkPollingService poll loop, retrying after delay"); + _logger.LogWarning(ex, "Redis error in ChunkPollingService poll loop, retrying after delay. TrackedTaskCount={TrackedTaskCount}", _trackedTasks.Count); } catch (Exception ex) { - _logger.LogError(ex, "Unexpected error in ChunkPollingService poll loop"); + _logger.LogError(ex, "Unexpected error in ChunkPollingService poll loop. TrackedTaskCount={TrackedTaskCount}", _trackedTasks.Count); }🤖 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 `@TelegramSearchBot/Service/AI/LLM/ChunkPollingService.cs` around lines 75 - 79, The loop-level exception handlers in ChunkPollingService currently log exceptions without diagnostic state; update the catch blocks around the poll loop to include relevant context (e.g., the current number of tracked tasks and any identifying loop state) in the _logger.LogWarning and _logger.LogError calls — for example include _trackedTasks.Count (or the method/property that exposes tracked tasks) and any loop iteration id or polling interval variable so the log messages mirror the richer per-task logs and aid debugging.TelegramSearchBot.LLM/Service/AI/LLM/McpToolHelper.cs (1)
725-729: 💤 Low valueConsider conditional CDATA stripping for performance.
The regex is applied to every argument value unconditionally. If CDATA markers are rare, consider adding a pre-check to avoid regex overhead:
foreach (var kvp in originalArguments) { var value = kvp.Value; - value = Regex.Replace(value ?? string.Empty, @"<!\[CDATA\[(.*?)\]\]>", "$1").Trim(); + if (!string.IsNullOrEmpty(value) && value.Contains("CDATA")) { + value = Regex.Replace(value, @"<!\[CDATA\[(.*?)\]\]>", "$1"); + } + value = (value ?? string.Empty).Trim(); cleanedArguments[kvp.Key] = value; }🤖 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 `@TelegramSearchBot.LLM/Service/AI/LLM/McpToolHelper.cs` around lines 725 - 729, The loop over originalArguments unconditionally runs Regex.Replace on every value which is wasteful; change the logic in the foreach (var kvp in originalArguments) block that sets cleanedArguments[kvp.Key] so you first null-coalesce and Trim the value, then only call Regex.Replace (the current Regex.Replace(value ?? string.Empty, @"<!\[CDATA\[(.*?)\]\]>", "$1").Trim()) when the string contains the CDATA marker (e.g. value.Contains("<![CDATA[")), otherwise skip the regex and assign the trimmed string directly; keep references to originalArguments, cleanedArguments and Regex.Replace so the change is localized to that loop.
🤖 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 `@TelegramSearchBot.LLM/Service/AI/LLM/OpenAIResponsesService.cs`:
- Around line 1200-1219: When parsing function-call and function-output blocks,
NormalizeToolCallId is called independently which lets malformed snapshots with
empty callId generate different IDs; fix by tracking a lastResolvedCallId in the
surrounding iteration scope and use it when parts[0] is empty: for the func call
branch compute rawCallId = parts.Length > 0 ? parts[0] : "" then resolved =
OpenAIService.NormalizeToolCallId(rawCallId) and set lastResolvedCallId =
resolved (and use that in CreateFunctionCallItem), and in the func output branch
compute rawCallId = parts.Length > 0 ? parts[0] : "" and if rawCallId is empty
use lastResolvedCallId before calling OpenAIService.NormalizeToolCallId (or
reuse lastResolvedCallId directly) so CreateFunctionCallOutputItem receives the
same callId; reference NormalizeToolCallId, CreateFunctionCallItem,
CreateFunctionCallOutputItem, FuncCallMarker, FuncOutputMarker, payload, parts
and msg.Role when making the change.
In `@TelegramSearchBot.LLM/Service/AI/LLM/OpenAIService.cs`:
- Around line 1108-1121: The LogError is serializing full toolCallAccumulators
including raw Arguments which may contain user secrets or large payloads;
replace the direct JsonConvert.SerializeObject(...) with a sanitized/truncated
preview generator: map each kvp to { kvp.Value.Id, kvp.Value.Name,
ArgumentsPreview = SanitizeAndTruncate(kvp.Value.Arguments?.ToString(),
maxChars) } and pass that preview JSON to _logger.LogError instead; implement a
small helper method SanitizeAndTruncateArguments(string, int) (or reuse an
existing sanitizer) to remove sensitive patterns and limit length, and apply the
same change for other LogError occurrences that serialize toolCallAccumulators
(e.g., the similar blocks named around _logger.LogError and references to
toolCallAccumulators).
In `@TelegramSearchBot/Program.cs`:
- Line 24: Add a configurable log level: add a LogLevel property (enum/string)
to the Config class in TelegramSearchBot.Common/Env.cs with default
"Information" (allowing "Verbose" for diagnostics), load it from Config.json,
and expose a parsed Serilog LogEventLevel; then update Program.cs where
MinimumLevel.Verbose() is used to apply the configured level (e.g.,
MinimumLevel.Is(config.LogEventLevel)) instead of hardcoding Verbose, and set
the OpenTelemetry sink call to include restrictedToMinimumLevel using the same
configured LogEventLevel (e.g., restrictedToMinimumLevel: config.LogEventLevel)
so sinks honor the runtime configuration.
---
Nitpick comments:
In `@TelegramSearchBot.LLM/Service/AI/LLM/McpToolHelper.cs`:
- Around line 725-729: The loop over originalArguments unconditionally runs
Regex.Replace on every value which is wasteful; change the logic in the foreach
(var kvp in originalArguments) block that sets cleanedArguments[kvp.Key] so you
first null-coalesce and Trim the value, then only call Regex.Replace (the
current Regex.Replace(value ?? string.Empty, @"<!\[CDATA\[(.*?)\]\]>",
"$1").Trim()) when the string contains the CDATA marker (e.g.
value.Contains("<![CDATA[")), otherwise skip the regex and assign the trimmed
string directly; keep references to originalArguments, cleanedArguments and
Regex.Replace so the change is localized to that loop.
In `@TelegramSearchBot/Service/AI/LLM/ChunkPollingService.cs`:
- Around line 75-79: The loop-level exception handlers in ChunkPollingService
currently log exceptions without diagnostic state; update the catch blocks
around the poll loop to include relevant context (e.g., the current number of
tracked tasks and any identifying loop state) in the _logger.LogWarning and
_logger.LogError calls — for example include _trackedTasks.Count (or the
method/property that exposes tracked tasks) and any loop iteration id or polling
interval variable so the log messages mirror the richer per-task logs and aid
debugging.
🪄 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: defaults
Review profile: CHILL
Plan: Pro
Run ID: 56aff00d-706c-405c-ad72-888b8d5f4dcc
📒 Files selected for processing (17)
TelegramSearchBot.Common/ExceptionExtensions.csTelegramSearchBot.LLM/Service/AI/LLM/AnthropicService.csTelegramSearchBot.LLM/Service/AI/LLM/GeminiService.csTelegramSearchBot.LLM/Service/AI/LLM/McpToolHelper.csTelegramSearchBot.LLM/Service/AI/LLM/OllamaService.csTelegramSearchBot.LLM/Service/AI/LLM/OpenAIResponsesService.csTelegramSearchBot.LLM/Service/AI/LLM/OpenAIService.csTelegramSearchBot.LLMAgent/LLMAgentProgram.csTelegramSearchBot.LLMAgent/Service/AgentLoopService.csTelegramSearchBot.LLMAgent/Service/ToolExecutor.csTelegramSearchBot/AppBootstrap/AppBootstrap.csTelegramSearchBot/Controller/AI/LLM/GeneralLLMController.csTelegramSearchBot/Controller/AI/LLM/LLMIterationCallbackController.csTelegramSearchBot/Program.csTelegramSearchBot/Service/AI/LLM/ChunkPollingService.csTelegramSearchBot/Service/AI/LLM/TelegramTaskConsumer.csTelegramSearchBot/Service/BotAPI/SendMessageService.Streaming.cs
PR Check ReportSummary
Test Results
Code Quality
Test Artifacts
LinksThis report is auto-generated by GitHub Actions |
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 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 `@TelegramSearchBot.Common/Env.cs`:
- Around line 160-166: ResolveSerilogMinimumLevel currently parses numeric
strings like "999" as enums; update the method to only accept defined
LogEventLevel values by, after Enum.TryParse<LogEventLevel>(...), verifying
Enum.IsDefined(typeof(LogEventLevel), parsed) before returning parsed; if
IsDefined is false, fall back to LogEventLevel.Verbose so only valid enum
members are accepted.
🪄 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: defaults
Review profile: CHILL
Plan: Pro
Run ID: a2d9f235-10f2-4c42-9ce2-b948cca78956
📒 Files selected for processing (8)
Docs/Build_and_Test_Guide.mdREADME.mdTelegramSearchBot.Common/Env.csTelegramSearchBot.LLM/Service/AI/LLM/McpToolHelper.csTelegramSearchBot.LLM/Service/AI/LLM/OpenAIResponsesService.csTelegramSearchBot.LLM/Service/AI/LLM/OpenAIService.csTelegramSearchBot/Program.csTelegramSearchBot/Service/AI/LLM/ChunkPollingService.cs
✅ Files skipped from review due to trivial changes (1)
- README.md
🚧 Files skipped from review as they are similar to previous changes (4)
- TelegramSearchBot.LLM/Service/AI/LLM/OpenAIService.cs
- TelegramSearchBot/Service/AI/LLM/ChunkPollingService.cs
- TelegramSearchBot.LLM/Service/AI/LLM/OpenAIResponsesService.cs
- TelegramSearchBot.LLM/Service/AI/LLM/McpToolHelper.cs
Summary
Verification
McpToolHelper|FullyQualifiedNameToolExecutor|FullyQualifiedName~OpenAIToolCallNormalization"AgentIntegrationTests|FullyQualifiedNameAgentRegistryServiceTests|FullyQualifiedNameLLMTaskQueueServiceTests|FullyQualifiedNameChunkPollingServiceTests"Summary by CodeRabbit
New Features
Bug Fixes
Improvements
Tests