From 6100e8a76b7d61d2b1b921224ca9b6b606f053ed Mon Sep 17 00:00:00 2001 From: Jesse Liberty Date: Fri, 14 Aug 2026 14:11:31 -0400 Subject: [PATCH] Clean up --- Program.cs | 6 ++---- ReviewerAgent.cs | 19 ++++++++++++------- TokenCapChatClient.cs | 5 +++++ 3 files changed, 19 insertions(+), 11 deletions(-) diff --git a/Program.cs b/Program.cs index a4b37a1..4005ab3 100644 --- a/Program.cs +++ b/Program.cs @@ -8,8 +8,8 @@ using Microsoft.Extensions.Logging; using OpenAI; -// Secrets come from the .NET user-secrets store in development and from -// environment variables in CI/production (env vars win on key collisions). +// Secrets come from the .NET user-secrets store and from +// environment variables (env vars win on key collisions). IConfiguration config = new ConfigurationBuilder() .AddUserSecrets() .AddEnvironmentVariables() @@ -36,8 +36,6 @@ string GetRequired(string key) => // UseFunctionInvocation() adds the middleware that actually *executes* the tool // calls the model requests — without it, attaching the Tavily tool to the // Researcher agent would let the model ask for a search but nothing would run it. -// Middleware is applied inner-to-outer, so function invocation wraps the raw -// OpenAI client. // // UseOpenTelemetry() emits a GenAI span per model round-trip (model name, token // usage, tool calls). Its source is named "BlogWriter.ChatClient" so the diff --git a/ReviewerAgent.cs b/ReviewerAgent.cs index b0a8d47..bd6eec6 100644 --- a/ReviewerAgent.cs +++ b/ReviewerAgent.cs @@ -56,7 +56,7 @@ public async Task InvokeAsync(ResearchState state) if (revisionNum >= ResearchState.MaxRevisions) { - return "Uh oh - Maximum revisions reached."; + return "APPROVED - Maximum revisions reached."; } // Per-turn input only — the evaluation criteria are on the agent. @@ -76,7 +76,7 @@ public async Task InvokeAsync(ResearchState state) }); AgentResponse response = await _agent.RunAsync(message, options: runOptions); string content = response.Text; - return !string.IsNullOrEmpty(content) ? content : "APPROVED"; + return !string.IsNullOrEmpty(content) ? content : ManageError("No review content returned from the agent."); } catch (TokenCapExceededException) { @@ -85,14 +85,19 @@ public async Task InvokeAsync(ResearchState state) } catch (Exception e) { - // Do NOT approve on failure — that would ship an unreviewed draft. - // Returning feedback (not "APPROVED") routes back to the author for - // another attempt; the revision cap still guarantees termination. - Console.WriteLine($"Review error: {e.Message}"); - return "Review could not be completed due to a transient error. Please revise and resubmit the draft."; + return ManageError(e.Message); } } + private string ManageError(string errorMessage) + { + // Do NOT approve on failure — that would ship an unreviewed draft. + // Returning feedback (not "APPROVED") routes back to the author for + // another attempt; the revision cap still guarantees termination. + Console.WriteLine($"Review error: {errorMessage}"); + return "Review could not be completed due to a transient error. Please revise and resubmit the draft."; + } + /// Node that reviews the draft. public async Task ReviewerNodeAsync(ResearchState state) { diff --git a/TokenCapChatClient.cs b/TokenCapChatClient.cs index dfebb06..716dd81 100644 --- a/TokenCapChatClient.cs +++ b/TokenCapChatClient.cs @@ -53,6 +53,11 @@ private void Track(UsageDetails? usage) return; } + if (maxTotalTokens <= 0) + { + throw new InvalidOperationException("Token cap must be a positive number."); + } + long total = Interlocked.Add(ref _totalTokens, used); if (total > maxTotalTokens) {