using System.Text.Json; using Agent.Core.Ollama; using Agent.Core.Runtime; using Agent.Core.Tools; namespace Agent.App.Logging; public sealed class JsonLinesRuntimeObserver : IAgentRuntimeObserver, IDisposable { private readonly RollingFileWriter _writer; public JsonLinesRuntimeObserver(string logDirectory, long maxBytes = 10 * 1024 * 1024, int retainedFiles = 5) => _writer = new RollingFileWriter(Path.Combine(logDirectory, "llm.jsonl"), maxBytes, retainedFiles); public void LlmRequest(AgentLlmCallContext context, IReadOnlyList messages) => Write(new { timestamp = DateTimeOffset.UtcNow, event_name = "llm.request", call_id = context.CallId, session_id = context.SessionId, task_id = context.TaskId, planner_task_id = context.PlannerTaskId, phase = context.Phase, iteration = context.Iteration, replan = context.Replan, model = context.Model, messages = messages.Select(static message => new { role = message.Role, content = message.Content, image_count = message.Images?.Count ?? 0, tool_name = message.ToolName }) }); public void LlmResponse(AgentLlmCallContext context, OllamaResult result) => Write(new { timestamp = DateTimeOffset.UtcNow, event_name = "llm.response", call_id = context.CallId, session_id = context.SessionId, task_id = context.TaskId, planner_task_id = context.PlannerTaskId, phase = context.Phase, iteration = context.Iteration, replan = context.Replan, model = context.Model, content = result.Content, input_tokens = result.InputTokens, output_tokens = result.OutputTokens, tool_calls = result.ToolCalls?.Select(static call => call.Function.Name).ToArray() ?? [] }); public void LlmFailure(AgentLlmCallContext context, string errorCode, string message) => Write(new { timestamp = DateTimeOffset.UtcNow, event_name = "llm.failure", call_id = context.CallId, session_id = context.SessionId, task_id = context.TaskId, planner_task_id = context.PlannerTaskId, phase = context.Phase, iteration = context.Iteration, replan = context.Replan, model = context.Model, error_code = errorCode, message }); public void ToolResult(AgentLlmCallContext context, string toolName, ToolExecutionResult result) => Write(new { timestamp = DateTimeOffset.UtcNow, event_name = "llm.tool_result", call_id = context.CallId, session_id = context.SessionId, task_id = context.TaskId, planner_task_id = context.PlannerTaskId, phase = context.Phase, iteration = context.Iteration, replan = context.Replan, model = context.Model, tool_name = toolName, success = result.Success, external_effect = result.ExternalEffect, retry_allowed = result.RetryAllowed, output = result.Output, failure_fingerprint = result.FailureFingerprint }); private void Write(object value) { _writer.WriteLine(JsonSerializer.Serialize(value)); } public void Dispose() => _writer.Dispose(); }