- claude-code 선택적 탐색 흐름을 참고해 Cowork/Code 시스템 프롬프트에서 folder_map 상시 선행 지시를 완화하고 glob/grep 기반 좁은 탐색을 우선하도록 조정함 - FolderMapTool 기본 depth를 2로, include_files 기본값을 false로 낮추고 MultiReadTool 최대 파일 수를 8개로 줄여 초기 과탐색 폭을 보수적으로 조정함 - AgentLoopExplorationPolicy partial을 추가해 탐색 범위 분류, broad-scan corrective hint, exploration_breadth 성능 로그를 연결함 - AgentLoopService에 탐색 범위 가이드 주입과 실행 중 탐색 폭 추적을 추가하고, 좁은 질문에서 반복적인 folder_map/대량 multi_read를 교정하도록 정리함 - DocxToHtmlConverter nullable 경고를 수정해 Release 빌드 경고 0 / 오류 0 기준을 다시 충족함 - README와 docs/DEVELOPMENT.md에 2026-04-09 10:36 (KST) 기준 개발 이력을 반영함
This commit is contained in:
@@ -4,6 +4,7 @@ using System.Runtime.CompilerServices;
|
||||
using System.Text;
|
||||
using System.Text.Json;
|
||||
using AxCopilot.Models;
|
||||
using AxCopilot.Services.Agent;
|
||||
|
||||
namespace AxCopilot.Services;
|
||||
|
||||
@@ -403,17 +404,17 @@ public partial class LlmService : IDisposable
|
||||
try
|
||||
{
|
||||
using var doc = JsonDocument.Parse(m.Content);
|
||||
if (doc.RootElement.TryGetProperty("_tool_use_blocks", out var blocks))
|
||||
if (doc.RootElement.SafeTryGetProperty("_tool_use_blocks", out var blocks))
|
||||
{
|
||||
var parts = new List<string>();
|
||||
foreach (var block in blocks.EnumerateArray())
|
||||
{
|
||||
if (!block.TryGetProperty("type", out var typeEl)) continue;
|
||||
var type = typeEl.GetString();
|
||||
if (type == "text" && block.TryGetProperty("text", out var textEl))
|
||||
parts.Add(textEl.GetString() ?? "");
|
||||
else if (type == "tool_use" && block.TryGetProperty("name", out var nameEl))
|
||||
parts.Add($"[도구 호출: {nameEl.GetString()}]");
|
||||
if (!block.SafeTryGetProperty("type", out var typeEl)) continue;
|
||||
var type = typeEl.SafeGetString();
|
||||
if (type == "text" && block.SafeTryGetProperty("text", out var textEl))
|
||||
parts.Add(textEl.SafeGetString() ?? "");
|
||||
else if (type == "tool_use" && block.SafeTryGetProperty("name", out var nameEl))
|
||||
parts.Add($"[도구 호출: {nameEl.SafeGetString()}]");
|
||||
}
|
||||
var content = string.Join("\n", parts).Trim();
|
||||
if (!string.IsNullOrEmpty(content))
|
||||
@@ -431,8 +432,8 @@ public partial class LlmService : IDisposable
|
||||
{
|
||||
using var doc = JsonDocument.Parse(m.Content);
|
||||
var root = doc.RootElement;
|
||||
var toolName = root.TryGetProperty("tool_name", out var tn) ? tn.GetString() ?? "tool" : "tool";
|
||||
var toolContent = root.TryGetProperty("content", out var tc) ? tc.GetString() ?? "" : "";
|
||||
var toolName = root.SafeTryGetProperty("tool_name", out var tn) ? tn.SafeGetString() ?? "tool" : "tool";
|
||||
var toolContent = root.SafeTryGetProperty("content", out var tc) ? tc.SafeGetString() ?? "" : "";
|
||||
msgs.Add(new { role = "user", content = $"[{toolName} 결과]\n{toolContent}" });
|
||||
continue;
|
||||
}
|
||||
@@ -461,41 +462,41 @@ public partial class LlmService : IDisposable
|
||||
|
||||
private static string ExtractIbmDeploymentText(JsonElement root)
|
||||
{
|
||||
if (root.TryGetProperty("choices", out var choices) && choices.ValueKind == JsonValueKind.Array && choices.GetArrayLength() > 0)
|
||||
if (root.SafeTryGetProperty("choices", out var choices) && choices.ValueKind == JsonValueKind.Array && choices.GetArrayLength() > 0)
|
||||
{
|
||||
var message = choices[0].TryGetProperty("message", out var choiceMessage) ? choiceMessage : default;
|
||||
var message = choices[0].SafeTryGetProperty("message", out var choiceMessage) ? choiceMessage : default;
|
||||
if (message.ValueKind == JsonValueKind.Object)
|
||||
{
|
||||
if (message.TryGetProperty("content", out var content))
|
||||
if (message.SafeTryGetProperty("content", out var content))
|
||||
{
|
||||
var text = content.GetString();
|
||||
var text = content.SafeGetString();
|
||||
if (!string.IsNullOrEmpty(text))
|
||||
return text;
|
||||
}
|
||||
// Qwen3.5 thinking 모드 폴백
|
||||
if (message.TryGetProperty("reasoning_content", out var reasoning))
|
||||
if (message.SafeTryGetProperty("reasoning_content", out var reasoning))
|
||||
{
|
||||
var text = reasoning.GetString();
|
||||
var text = reasoning.SafeGetString();
|
||||
if (!string.IsNullOrEmpty(text))
|
||||
return text;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (root.TryGetProperty("results", out var results) && results.ValueKind == JsonValueKind.Array && results.GetArrayLength() > 0)
|
||||
if (root.SafeTryGetProperty("results", out var results) && results.ValueKind == JsonValueKind.Array && results.GetArrayLength() > 0)
|
||||
{
|
||||
var first = results[0];
|
||||
if (first.TryGetProperty("generated_text", out var generatedText))
|
||||
return generatedText.GetString() ?? "";
|
||||
if (first.TryGetProperty("output_text", out var outputText))
|
||||
return outputText.GetString() ?? "";
|
||||
if (first.SafeTryGetProperty("generated_text", out var generatedText))
|
||||
return generatedText.SafeGetString() ?? "";
|
||||
if (first.SafeTryGetProperty("output_text", out var outputText))
|
||||
return outputText.SafeGetString() ?? "";
|
||||
}
|
||||
|
||||
if (root.TryGetProperty("generated_text", out var generated))
|
||||
return generated.GetString() ?? "";
|
||||
if (root.SafeTryGetProperty("generated_text", out var generated))
|
||||
return generated.SafeGetString() ?? "";
|
||||
|
||||
if (root.TryGetProperty("message", out var messageValue) && messageValue.ValueKind == JsonValueKind.String)
|
||||
return messageValue.GetString() ?? "";
|
||||
if (root.SafeTryGetProperty("message", out var messageValue) && messageValue.ValueKind == JsonValueKind.String)
|
||||
return messageValue.SafeGetString() ?? "";
|
||||
|
||||
return "";
|
||||
}
|
||||
@@ -719,7 +720,10 @@ public partial class LlmService : IDisposable
|
||||
return SafeParseJson(resp, root =>
|
||||
{
|
||||
TryParseOllamaUsage(root);
|
||||
return root.GetProperty("message").GetProperty("content").GetString() ?? "";
|
||||
var msg = root.SafeGetProperty("message");
|
||||
if (msg == null) return root.SafeGetString() ?? "(빈 응답)";
|
||||
if (msg.Value.ValueKind == JsonValueKind.String) return msg.Value.SafeGetString() ?? "";
|
||||
return msg.Value.SafeGetProperty("content")?.SafeGetString() ?? "";
|
||||
}, "Ollama 응답");
|
||||
}
|
||||
|
||||
@@ -759,10 +763,10 @@ public partial class LlmService : IDisposable
|
||||
try
|
||||
{
|
||||
using var doc = JsonDocument.Parse(line);
|
||||
if (doc.RootElement.TryGetProperty("message", out var msg) &&
|
||||
msg.TryGetProperty("content", out var c))
|
||||
text = c.GetString();
|
||||
if (doc.RootElement.TryGetProperty("done", out var done) && done.GetBoolean())
|
||||
if (doc.RootElement.SafeTryGetProperty("message", out var msg) &&
|
||||
msg.SafeTryGetProperty("content", out var c))
|
||||
text = c.SafeGetString();
|
||||
if (doc.RootElement.SafeTryGetProperty("done", out var done) && done.GetBoolean())
|
||||
TryParseOllamaUsage(doc.RootElement);
|
||||
}
|
||||
catch (JsonException ex)
|
||||
@@ -827,9 +831,15 @@ public partial class LlmService : IDisposable
|
||||
return string.IsNullOrWhiteSpace(parsed) ? "(빈 응답)" : parsed;
|
||||
}
|
||||
|
||||
var choices = root.GetProperty("choices");
|
||||
if (choices.GetArrayLength() == 0) return "(빈 응답)";
|
||||
return choices[0].GetProperty("message").GetProperty("content").GetString() ?? "";
|
||||
if (!root.SafeTryGetProperty("choices", out var choices)
|
||||
|| choices.ValueKind != JsonValueKind.Array
|
||||
|| choices.GetArrayLength() == 0)
|
||||
return "(빈 응답)";
|
||||
var firstChoice = choices[0];
|
||||
var msg = firstChoice.SafeGetProperty("message");
|
||||
if (msg == null) return firstChoice.SafeGetString() ?? "(빈 응답)";
|
||||
if (msg.Value.ValueKind == JsonValueKind.String) return msg.Value.SafeGetString() ?? "";
|
||||
return msg.Value.SafeGetProperty("content")?.SafeGetString() ?? "";
|
||||
}, "vLLM 응답");
|
||||
}
|
||||
|
||||
@@ -867,27 +877,27 @@ public partial class LlmService : IDisposable
|
||||
{
|
||||
using var doc = JsonDocument.Parse(data);
|
||||
// 스트리밍 청크(delta) → content 누적
|
||||
if (doc.RootElement.TryGetProperty("choices", out var ch) && ch.GetArrayLength() > 0)
|
||||
if (doc.RootElement.SafeTryGetProperty("choices", out var ch) && ch.GetArrayLength() > 0)
|
||||
{
|
||||
var first = ch[0];
|
||||
if (first.TryGetProperty("delta", out var delta))
|
||||
if (first.SafeTryGetProperty("delta", out var delta))
|
||||
{
|
||||
string? txt = null;
|
||||
if (delta.TryGetProperty("content", out var cnt))
|
||||
txt = cnt.GetString();
|
||||
if (delta.SafeTryGetProperty("content", out var cnt))
|
||||
txt = cnt.SafeGetString();
|
||||
// Qwen3.5 thinking 모드 폴백: content가 비어있으면 reasoning_content 사용
|
||||
if (string.IsNullOrEmpty(txt) && delta.TryGetProperty("reasoning_content", out var rc))
|
||||
txt = rc.GetString();
|
||||
if (string.IsNullOrEmpty(txt) && delta.SafeTryGetProperty("reasoning_content", out var rc))
|
||||
txt = rc.SafeGetString();
|
||||
if (!string.IsNullOrEmpty(txt)) { sb.Append(txt); collectingChunks = true; }
|
||||
}
|
||||
else if (first.TryGetProperty("message", out _))
|
||||
else if (first.SafeTryGetProperty("message", out _))
|
||||
{
|
||||
// 완성 응답 → 이 JSON을 그대로 사용
|
||||
return data;
|
||||
}
|
||||
}
|
||||
// IBM results[] 형식
|
||||
else if (doc.RootElement.TryGetProperty("results", out var res) && res.GetArrayLength() > 0)
|
||||
else if (doc.RootElement.SafeTryGetProperty("results", out var res) && res.GetArrayLength() > 0)
|
||||
{
|
||||
return data;
|
||||
}
|
||||
@@ -960,44 +970,67 @@ public partial class LlmService : IDisposable
|
||||
TryParseOpenAiUsage(doc.RootElement);
|
||||
if (usesIbmDeploymentApi)
|
||||
{
|
||||
if (doc.RootElement.TryGetProperty("status", out var status) &&
|
||||
string.Equals(status.GetString(), "error", StringComparison.OrdinalIgnoreCase))
|
||||
if (doc.RootElement.SafeTryGetProperty("status", out var status) &&
|
||||
string.Equals(status.SafeGetString(), "error", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
var detail = doc.RootElement.TryGetProperty("message", out var message)
|
||||
? message.GetString()
|
||||
var detail = doc.RootElement.SafeTryGetProperty("message", out var message)
|
||||
? message.SafeGetString()
|
||||
: "IBM vLLM 스트리밍 오류";
|
||||
throw new InvalidOperationException(detail);
|
||||
}
|
||||
|
||||
if (doc.RootElement.TryGetProperty("results", out var results) &&
|
||||
if (doc.RootElement.SafeTryGetProperty("results", out var results) &&
|
||||
results.ValueKind == JsonValueKind.Array &&
|
||||
results.GetArrayLength() > 0)
|
||||
{
|
||||
var first = results[0];
|
||||
if (first.TryGetProperty("generated_text", out var generatedText))
|
||||
text = generatedText.GetString();
|
||||
else if (first.TryGetProperty("output_text", out var outputText))
|
||||
text = outputText.GetString();
|
||||
if (first.SafeTryGetProperty("generated_text", out var generatedText))
|
||||
text = generatedText.SafeGetString();
|
||||
else if (first.SafeTryGetProperty("output_text", out var outputText))
|
||||
text = outputText.SafeGetString();
|
||||
}
|
||||
else if (doc.RootElement.TryGetProperty("choices", out var ibmChoices) && ibmChoices.GetArrayLength() > 0)
|
||||
else if (doc.RootElement.SafeTryGetProperty("choices", out var ibmChoices)
|
||||
&& ibmChoices.ValueKind == JsonValueKind.Array
|
||||
&& ibmChoices.GetArrayLength() > 0)
|
||||
{
|
||||
var delta = ibmChoices[0].GetProperty("delta");
|
||||
if (delta.TryGetProperty("content", out var c))
|
||||
text = c.GetString();
|
||||
if (string.IsNullOrEmpty(text) && delta.TryGetProperty("reasoning_content", out var rc))
|
||||
text = rc.GetString();
|
||||
var fc = ibmChoices[0];
|
||||
if (fc.SafeTryGetProperty("delta", out var delta))
|
||||
{
|
||||
if (delta.ValueKind == JsonValueKind.String)
|
||||
text = delta.SafeGetString();
|
||||
else
|
||||
{
|
||||
if (delta.SafeTryGetProperty("content", out var c))
|
||||
text = c.SafeGetString();
|
||||
if (string.IsNullOrEmpty(text) && delta.SafeTryGetProperty("reasoning_content", out var rc))
|
||||
text = rc.SafeGetString();
|
||||
}
|
||||
}
|
||||
else if (fc.ValueKind == JsonValueKind.String)
|
||||
text = fc.SafeGetString();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
var choices = doc.RootElement.GetProperty("choices");
|
||||
if (choices.GetArrayLength() > 0)
|
||||
if (doc.RootElement.SafeTryGetProperty("choices", out var choices)
|
||||
&& choices.ValueKind == JsonValueKind.Array
|
||||
&& choices.GetArrayLength() > 0)
|
||||
{
|
||||
var delta = choices[0].GetProperty("delta");
|
||||
if (delta.TryGetProperty("content", out var c))
|
||||
text = c.GetString();
|
||||
if (string.IsNullOrEmpty(text) && delta.TryGetProperty("reasoning_content", out var rc2))
|
||||
text = rc2.GetString();
|
||||
var fc = choices[0];
|
||||
if (fc.SafeTryGetProperty("delta", out var delta))
|
||||
{
|
||||
if (delta.ValueKind == JsonValueKind.String)
|
||||
text = delta.SafeGetString();
|
||||
else
|
||||
{
|
||||
if (delta.SafeTryGetProperty("content", out var c))
|
||||
text = c.SafeGetString();
|
||||
if (string.IsNullOrEmpty(text) && delta.SafeTryGetProperty("reasoning_content", out var rc2))
|
||||
text = rc2.SafeGetString();
|
||||
}
|
||||
}
|
||||
else if (fc.ValueKind == JsonValueKind.String)
|
||||
text = fc.SafeGetString();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1021,6 +1054,9 @@ public partial class LlmService : IDisposable
|
||||
["temperature"] = ResolveTemperature(),
|
||||
["max_tokens"] = ResolveOpenAiCompatibleMaxTokens()
|
||||
};
|
||||
// 스트리밍 시 마지막 청크에 토큰 사용량을 포함하도록 요청 (vLLM/OpenAI 호환)
|
||||
if (stream)
|
||||
body["stream_options"] = new { include_usage = true };
|
||||
var effort = ResolveReasoningEffort();
|
||||
if (!string.IsNullOrWhiteSpace(effort))
|
||||
body["reasoning_effort"] = effort;
|
||||
@@ -1045,11 +1081,16 @@ public partial class LlmService : IDisposable
|
||||
return SafeParseJson(resp, root =>
|
||||
{
|
||||
TryParseGeminiUsage(root);
|
||||
var candidates = root.GetProperty("candidates");
|
||||
if (candidates.GetArrayLength() == 0) return "(빈 응답)";
|
||||
var parts = candidates[0].GetProperty("content").GetProperty("parts");
|
||||
if (parts.GetArrayLength() == 0) return "(빈 응답)";
|
||||
return parts[0].GetProperty("text").GetString() ?? "";
|
||||
if (!root.SafeTryGetProperty("candidates", out var candidates)
|
||||
|| candidates.ValueKind != JsonValueKind.Array
|
||||
|| candidates.GetArrayLength() == 0)
|
||||
return "(빈 응답)";
|
||||
var first = candidates[0];
|
||||
var content = first.SafeGetProperty("content");
|
||||
if (content == null || !content.Value.SafeTryGetProperty("parts", out var parts)
|
||||
|| parts.ValueKind != JsonValueKind.Array || parts.GetArrayLength() == 0)
|
||||
return first.SafeGetString() ?? "(빈 응답)";
|
||||
return parts[0].SafeGetProperty("text")?.SafeGetString() ?? "";
|
||||
}, "Gemini 응답");
|
||||
}
|
||||
|
||||
@@ -1093,15 +1134,19 @@ public partial class LlmService : IDisposable
|
||||
{
|
||||
using var doc = JsonDocument.Parse(data);
|
||||
TryParseGeminiUsage(doc.RootElement);
|
||||
var candidates = doc.RootElement.GetProperty("candidates");
|
||||
if (candidates.GetArrayLength() == 0) continue;
|
||||
if (!doc.RootElement.SafeTryGetProperty("candidates", out var candidates)
|
||||
|| candidates.ValueKind != JsonValueKind.Array
|
||||
|| candidates.GetArrayLength() == 0) continue;
|
||||
var sb = new StringBuilder();
|
||||
var parts = candidates[0].GetProperty("content").GetProperty("parts");
|
||||
var firstCand = candidates[0];
|
||||
var contentEl = firstCand.SafeGetProperty("content");
|
||||
if (contentEl == null || !contentEl.Value.SafeTryGetProperty("parts", out var parts)
|
||||
|| parts.ValueKind != JsonValueKind.Array) continue;
|
||||
foreach (var part in parts.EnumerateArray())
|
||||
{
|
||||
if (part.TryGetProperty("text", out var t))
|
||||
if (part.SafeTryGetProperty("text", out var t))
|
||||
{
|
||||
var text = t.GetString();
|
||||
var text = t.SafeGetString();
|
||||
if (!string.IsNullOrEmpty(text)) sb.Append(text);
|
||||
}
|
||||
}
|
||||
@@ -1185,9 +1230,11 @@ public partial class LlmService : IDisposable
|
||||
return SafeParseJson(respJson, root =>
|
||||
{
|
||||
TryParseSigmoidUsage(root);
|
||||
var content = root.GetProperty("content");
|
||||
if (content.GetArrayLength() == 0) return "(빈 응답)";
|
||||
return content[0].GetProperty("text").GetString() ?? "";
|
||||
if (!root.SafeTryGetProperty("content", out var content)
|
||||
|| content.ValueKind != JsonValueKind.Array
|
||||
|| content.GetArrayLength() == 0)
|
||||
return root.SafeGetString() ?? "(빈 응답)";
|
||||
return content[0].SafeGetProperty("text")?.SafeGetString() ?? "";
|
||||
}, "Claude 응답");
|
||||
}
|
||||
|
||||
@@ -1237,20 +1284,20 @@ public partial class LlmService : IDisposable
|
||||
try
|
||||
{
|
||||
using var doc = JsonDocument.Parse(data);
|
||||
var type = doc.RootElement.GetProperty("type").GetString();
|
||||
var type = doc.RootElement.SafeGetProperty("type")?.SafeGetString();
|
||||
if (type == "content_block_delta")
|
||||
{
|
||||
var delta = doc.RootElement.GetProperty("delta");
|
||||
if (delta.TryGetProperty("text", out var t))
|
||||
text = t.GetString();
|
||||
if (!doc.RootElement.SafeTryGetProperty("delta", out var delta)) continue;
|
||||
if (delta.SafeTryGetProperty("text", out var t))
|
||||
text = t.SafeGetString();
|
||||
}
|
||||
else if (type is "message_start" or "message_delta")
|
||||
{
|
||||
// message_start: usage in .message.usage, message_delta: usage in .usage
|
||||
if (doc.RootElement.TryGetProperty("message", out var msg) &&
|
||||
msg.TryGetProperty("usage", out var u1))
|
||||
if (doc.RootElement.SafeTryGetProperty("message", out var msg) &&
|
||||
msg.SafeTryGetProperty("usage", out var u1))
|
||||
TryParseSigmoidUsageFromElement(u1);
|
||||
else if (doc.RootElement.TryGetProperty("usage", out var u2))
|
||||
else if (doc.RootElement.SafeTryGetProperty("usage", out var u2))
|
||||
TryParseSigmoidUsageFromElement(u2);
|
||||
}
|
||||
}
|
||||
@@ -1434,9 +1481,9 @@ public partial class LlmService : IDisposable
|
||||
using var doc = JsonDocument.Parse(json);
|
||||
|
||||
// API 에러 응답 감지
|
||||
if (doc.RootElement.TryGetProperty("error", out var error))
|
||||
if (doc.RootElement.SafeTryGetProperty("error", out var error))
|
||||
{
|
||||
var msg = error.TryGetProperty("message", out var m) ? m.GetString() : error.ToString();
|
||||
var msg = error.SafeTryGetProperty("message", out var m) ? m.SafeGetString() : error.ToString();
|
||||
throw new HttpRequestException($"[{context}] API 에러: {msg}");
|
||||
}
|
||||
|
||||
@@ -1468,12 +1515,12 @@ public partial class LlmService : IDisposable
|
||||
try
|
||||
{
|
||||
using var doc = JsonDocument.Parse(body);
|
||||
if (doc.RootElement.TryGetProperty("error", out var err))
|
||||
if (doc.RootElement.SafeTryGetProperty("error", out var err))
|
||||
{
|
||||
if (err.ValueKind == JsonValueKind.Object && err.TryGetProperty("message", out var m))
|
||||
detail = m.GetString() ?? "";
|
||||
if (err.ValueKind == JsonValueKind.Object && err.SafeTryGetProperty("message", out var m))
|
||||
detail = m.SafeGetString() ?? "";
|
||||
else if (err.ValueKind == JsonValueKind.String)
|
||||
detail = err.GetString() ?? "";
|
||||
detail = err.SafeGetString() ?? "";
|
||||
}
|
||||
}
|
||||
catch { }
|
||||
@@ -1506,8 +1553,8 @@ public partial class LlmService : IDisposable
|
||||
{
|
||||
try
|
||||
{
|
||||
var prompt = root.TryGetProperty("prompt_eval_count", out var p) ? p.GetInt32() : 0;
|
||||
var completion = root.TryGetProperty("eval_count", out var e) ? e.GetInt32() : 0;
|
||||
var prompt = root.SafeTryGetProperty("prompt_eval_count", out var p) ? p.GetInt32() : 0;
|
||||
var completion = root.SafeTryGetProperty("eval_count", out var e) ? e.GetInt32() : 0;
|
||||
if (prompt > 0 || completion > 0)
|
||||
LastTokenUsage = new TokenUsage(prompt, completion);
|
||||
}
|
||||
@@ -1518,9 +1565,9 @@ public partial class LlmService : IDisposable
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!root.TryGetProperty("usage", out var usage)) return;
|
||||
var prompt = usage.TryGetProperty("prompt_tokens", out var p) ? p.GetInt32() : 0;
|
||||
var completion = usage.TryGetProperty("completion_tokens", out var c) ? c.GetInt32() : 0;
|
||||
if (!root.SafeTryGetProperty("usage", out var usage)) return;
|
||||
var prompt = usage.SafeTryGetProperty("prompt_tokens", out var p) ? p.SafeGetInt32(0) : 0;
|
||||
var completion = usage.SafeTryGetProperty("completion_tokens", out var c) ? c.SafeGetInt32(0) : 0;
|
||||
if (prompt > 0 || completion > 0)
|
||||
LastTokenUsage = new TokenUsage(prompt, completion);
|
||||
}
|
||||
@@ -1531,9 +1578,9 @@ public partial class LlmService : IDisposable
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!root.TryGetProperty("usageMetadata", out var usage)) return;
|
||||
var prompt = usage.TryGetProperty("promptTokenCount", out var p) ? p.GetInt32() : 0;
|
||||
var completion = usage.TryGetProperty("candidatesTokenCount", out var c) ? c.GetInt32() : 0;
|
||||
if (!root.SafeTryGetProperty("usageMetadata", out var usage)) return;
|
||||
var prompt = usage.SafeTryGetProperty("promptTokenCount", out var p) ? p.GetInt32() : 0;
|
||||
var completion = usage.SafeTryGetProperty("candidatesTokenCount", out var c) ? c.GetInt32() : 0;
|
||||
if (prompt > 0 || completion > 0)
|
||||
LastTokenUsage = new TokenUsage(prompt, completion);
|
||||
}
|
||||
@@ -1544,7 +1591,7 @@ public partial class LlmService : IDisposable
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!root.TryGetProperty("usage", out var usage)) return;
|
||||
if (!root.SafeTryGetProperty("usage", out var usage)) return;
|
||||
TryParseSigmoidUsageFromElement(usage);
|
||||
}
|
||||
catch { }
|
||||
@@ -1554,8 +1601,8 @@ public partial class LlmService : IDisposable
|
||||
{
|
||||
try
|
||||
{
|
||||
var input = usage.TryGetProperty("input_tokens", out var i) ? i.GetInt32() : 0;
|
||||
var output = usage.TryGetProperty("output_tokens", out var o) ? o.GetInt32() : 0;
|
||||
var input = usage.SafeTryGetProperty("input_tokens", out var i) ? i.GetInt32() : 0;
|
||||
var output = usage.SafeTryGetProperty("output_tokens", out var o) ? o.GetInt32() : 0;
|
||||
if (input > 0 || output > 0)
|
||||
LastTokenUsage = new TokenUsage(input, output);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user