Fuenf Befunde mit einem gemeinsamen Fehlermodus: Keiner erzeugt eine Fehlermeldung. Der Lauf wird fertig, das Ergebnis sieht plausibel aus, und nur die Qualitaet ist schlechter. #547 Der Begleittext zum Werkzeugaufruf ging verloren. AssistantWithToolCalls baute eine neue Nachricht aus nur den Aufrufen; der Text, den das Modell daneben geschrieben hatte, fiel weg. Damit verlor das Modell zwischen zwei Schritten seinen eigenen Plan, und im Audit stand, dass ein Werkzeug lief, nicht warum. #548 finish_reason wurde nirgends gelesen. Eine an der Ausgabegrenze abgeschnittene Antwort galt als fertiges Ergebnis. Das trifft besonders Laeufe im Hintergrund, wo niemand zusieht. Neuer Status Truncated: Das Teilergebnis geht weiter, aber gekennzeichnet. #549 reasoning_details wurde verworfen. Bei Werkzeugnutzung muss der Denkverlauf unveraendert zurueck, sonst beginnt ein Thinking-Modell jedes Mal von vorn. Wird jetzt als rohes JSON durchgereicht - ohne Auslegung, weil Reihenfolge und Signatur daran haengen. #550 Die Anfrage verlangt jetzt einen Anbieter, der alle mitgeschickten Parameter beherrscht. Ohne das durfte ein Anbieter cache_control, reasoning oder sogar tools stillschweigend uebergehen - der Lauf lieferte dann eine gewoehnliche Textantwort, wo ein Werkzeugaufruf hingehoert haette. Dazu usage.include: der abgerechnete Betrag schlaegt die Eigenrechnung, die als Rueckfallebene bleibt. Denktiefe je Agent einstellbar, Vorgabe off. #551 Werkzeuge eines Zuges laufen gleichzeitig, sofern sie sich dafuer freigeben. Die Vorgabe von IsParallelSafe ist false, weil die falsche Antwort hier nicht auffaellt: Zwei schreibende Aufrufe auf derselben Datei scheitern nicht zuverlaessig, sondern gelegentlich. Freigegeben ist bisher nur WebFetch - es liest ausschliesslich. Die Reihenfolge der Ergebnisse folgt den Aufrufen, nicht der Fertigstellung; daran haengen die tool_call_id-Zuordnung und der Cache-Praefix. 27 neue Tests, 887 gesamt, keine Regression. Build ohne Warnungen. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
80 lines
2.1 KiB
C#
80 lines
2.1 KiB
C#
using System.Text.Json.Serialization;
|
|
|
|
namespace ClawdDotNet.Core.Api.Models;
|
|
|
|
public sealed class ChatResponse
|
|
{
|
|
[JsonPropertyName("id")]
|
|
public string Id { get; set; } = "";
|
|
|
|
[JsonPropertyName("choices")]
|
|
public List<Choice> Choices { get; set; } = new();
|
|
|
|
[JsonPropertyName("usage")]
|
|
public Usage? Usage { get; set; }
|
|
|
|
[JsonPropertyName("model")]
|
|
public string? Model { get; set; }
|
|
|
|
[JsonPropertyName("error")]
|
|
public ApiError? Error { get; set; }
|
|
}
|
|
|
|
public sealed class Choice
|
|
{
|
|
[JsonPropertyName("index")]
|
|
public int Index { get; set; }
|
|
|
|
[JsonPropertyName("message")]
|
|
public ChatMessage Message { get; set; } = new();
|
|
|
|
[JsonPropertyName("finish_reason")]
|
|
public string? FinishReason { get; set; }
|
|
}
|
|
|
|
public sealed class Usage
|
|
{
|
|
[JsonPropertyName("prompt_tokens")]
|
|
public int PromptTokens { get; set; }
|
|
|
|
[JsonPropertyName("completion_tokens")]
|
|
public int CompletionTokens { get; set; }
|
|
|
|
[JsonPropertyName("total_tokens")]
|
|
public int TotalTokens { get; set; }
|
|
|
|
[JsonPropertyName("prompt_tokens_details")]
|
|
public PromptTokensDetails? PromptTokensDetails { get; set; }
|
|
|
|
/// <summary>
|
|
/// Der vom Gateway tatsächlich abgerechnete Betrag. Kommt nur, wenn die Anfrage
|
|
/// <c>usage.include</c> gesetzt hat. Null heißt „nicht geliefert" — dann bleibt
|
|
/// es bei der Eigenrechnung aus Preisliste mal Tokenzahl.
|
|
/// </summary>
|
|
[JsonPropertyName("cost")]
|
|
public decimal? Cost { get; set; }
|
|
|
|
/// <summary>
|
|
/// Anteil der Prompt-Tokens, der aus dem Cache gelesen wurde. Nur damit lässt sich
|
|
/// belegen, ob das Prompt-Caching tatsächlich greift — ein still wirkungsloser
|
|
/// Cache wäre sonst nicht zu bemerken.
|
|
/// </summary>
|
|
[JsonIgnore]
|
|
public int CachedTokens => PromptTokensDetails?.CachedTokens ?? 0;
|
|
}
|
|
|
|
public sealed class PromptTokensDetails
|
|
{
|
|
[JsonPropertyName("cached_tokens")]
|
|
public int CachedTokens { get; set; }
|
|
}
|
|
|
|
public sealed class ApiError
|
|
{
|
|
[JsonPropertyName("message")]
|
|
public string Message { get; set; } = "";
|
|
|
|
[JsonPropertyName("code")]
|
|
public int? Code { get; set; }
|
|
}
|