diff options
| author | tanaka takashi <isazaka@gmail.com> | 2026-08-12 00:21:23 +0900 |
|---|---|---|
| committer | tanaka takashi <isazaka@gmail.com> | 2026-08-12 00:21:23 +0900 |
| commit | 98b6a2aeedd591058c1d81e401d24f3ded162926 (patch) | |
| tree | 74cbb38af825526e4fc90b150feed14426d727b4 /src/Agent.Core/Runtime | |
| parent | ce550a127b7dc972651bd15b9f09979a2c38688f (diff) | |
fix: implement native Ollama thinking semantics
Model Ollama chat thinking separately from final content, preserve it only across assistant tool-call continuation, and keep private reasoning out of user results, session context, and logs.
Accept native boolean and low/medium/high/max think values, normalize YAML booleans, and serialize explicit overrides using the native top-level chat field.
Stop forcing think=false for structured planning, skill selection, and context summaries; corrected retries now retain the configured thinking mode.
Update the specification, design, audit report, and requirement traceability for OLL-14.
Add request/response, configuration, observability, retry, and tool-continuation coverage. Verified with 92 passing Agent.Core tests and a deepseek-v4-flash:cloud think:true MCP operational run.
Diffstat (limited to 'src/Agent.Core/Runtime')
| -rw-r--r-- | src/Agent.Core/Runtime/AgentRuntime.cs | 7 | ||||
| -rw-r--r-- | src/Agent.Core/Runtime/PlannerService.cs | 8 |
2 files changed, 6 insertions, 9 deletions
diff --git a/src/Agent.Core/Runtime/AgentRuntime.cs b/src/Agent.Core/Runtime/AgentRuntime.cs index 31a4414..5ca9d1c 100644 --- a/src/Agent.Core/Runtime/AgentRuntime.cs +++ b/src/Agent.Core/Runtime/AgentRuntime.cs @@ -262,7 +262,7 @@ public sealed class AgentRuntime(TaskRegistry registry, IOllamaClient ollama, Ag IReadOnlyList<OllamaToolCall> calls = result.ToolCalls ?? []; if (calls.Count > 0) { - messages.Add(new OllamaMessage("assistant", result.Content, ToolCalls: calls)); + messages.Add(new OllamaMessage("assistant", result.Content, Thinking: result.Thinking, ToolCalls: calls)); string? failureFingerprint = null; foreach (OllamaToolCall call in calls) { @@ -400,7 +400,7 @@ public sealed class AgentRuntime(TaskRegistry registry, IOllamaClient ollama, Ag callContext = new AgentLlmCallContext(Guid.NewGuid(), task.SessionId, taskId, null, "context_summary", iteration, counters.Replans, settings.Model); _observer.LlmRequest(callContext, messages); - OllamaResult result = await ollama.ChatStructuredAsync(messages, task.Temperature, schema.RootElement.Clone(), false, cancellationToken).ConfigureAwait(false); + OllamaResult result = await ollama.ChatStructuredAsync(messages, task.Temperature, schema.RootElement.Clone(), null, cancellationToken).ConfigureAwait(false); _observer.LlmResponse(callContext, result); registry.AddUsage(taskId, result.InputTokens, result.OutputTokens); registry.UpdateDiagnostics(taskId, counters.Iterations, counters.Replans); @@ -444,8 +444,7 @@ public sealed class AgentRuntime(TaskRegistry registry, IOllamaClient ollama, Ag OllamaResult? result = null; try { - bool? thinkOverride = attempt == 0 ? null : false; - result = await ollama.ChatStructuredAsync(attemptMessages, task.Temperature, formatDoc.RootElement.Clone(), thinkOverride, cancellationToken).ConfigureAwait(false); + result = await ollama.ChatStructuredAsync(attemptMessages, task.Temperature, formatDoc.RootElement.Clone(), null, cancellationToken).ConfigureAwait(false); _observer.LlmResponse(callContext, result); registry.AddUsage(task.TaskId, result.InputTokens, result.OutputTokens); registry.UpdateDiagnostics(task.TaskId, counters.Iterations, counters.Replans); diff --git a/src/Agent.Core/Runtime/PlannerService.cs b/src/Agent.Core/Runtime/PlannerService.cs index bc96ec7..3591259 100644 --- a/src/Agent.Core/Runtime/PlannerService.cs +++ b/src/Agent.Core/Runtime/PlannerService.cs @@ -218,8 +218,7 @@ public sealed class PlannerService(IOllamaClient ollama, AgentRuntimeSettings se OllamaResult? result = null; try { - bool? thinkOverride = attempt == 0 ? null : false; - result = await _ollama.ChatStructuredAsync(attemptMessages, temperature, formatDoc.RootElement.Clone(), thinkOverride, cancellationToken).ConfigureAwait(false); + result = await _ollama.ChatStructuredAsync(attemptMessages, temperature, formatDoc.RootElement.Clone(), null, cancellationToken).ConfigureAwait(false); if (!TryParseSelectedSkills(result.Content, out IReadOnlyList<AgentSkill> selected)) throw new PlannerValidationException("Ollama returned an invalid skill selection object."); observeAttempt?.Invoke("skill_selection", attemptMessages, result, null); @@ -250,8 +249,7 @@ public sealed class PlannerService(IOllamaClient ollama, AgentRuntimeSettings se OllamaResult? result = null; try { - bool? thinkOverride = attempt == 0 ? null : false; - result = await _ollama.ChatStructuredAsync(attemptMessages, temperature, PlanSchema.Element, thinkOverride, cancellationToken).ConfigureAwait(false); + result = await _ollama.ChatStructuredAsync(attemptMessages, temperature, PlanSchema.Element, null, cancellationToken).ConfigureAwait(false); PlanResult? plan = ParsePlan(result.Content); if (plan is null || plan.Tasks.Count == 0) throw new PlannerValidationException("Ollama returned an empty or invalid structured plan."); @@ -274,7 +272,7 @@ public sealed class PlannerService(IOllamaClient ollama, AgentRuntimeSettings se } } } - throw new PlannerValidationException($"Structured {phase} failed after think=false retry: {lastFailure?.Message}"); + throw new PlannerValidationException($"Structured {phase} failed after one corrected retry: {lastFailure?.Message}"); } private bool TryParseSelectedSkills(string content, out IReadOnlyList<AgentSkill> selected) |
