Files
gott/Models/ChatModels.cs
MelekiandClaude Opus 4.8 b6e546f618 Add workflow-status telemetry view and make panel modes on-demand
Workflow-status: a new WorkflowProgressTracker singleton taps the
suppressed dynamic-workflow subagent events (those carrying
parent_tool_use_id) into per-session telemetry without altering the
existing guard; the snapshot is serialized into the new chains.workflow_info
column on FinalizeChain (ChainId-matched so a panel member of the same
session cannot clear it) and exposed via GET /api/sessions/{id}/workflow-status
(live -> persisted -> none). The header menu gains a 'Workflow-Status' entry
with a modal that live-polls every 2s while running and self-stops on close.

Panel on-demand: Fusion/MoA is now a transient per-request multiModelMode
flag (like plan/ultracode) instead of a persisted session column. Session
settings keep only the panel members + moa_layers; the mode <select> was
removed and the composer dropdown drives the mode per request.

Docs: ARCHITECTURE.md, ARCHITECTURE_QUICK.md and README.md updated for both
features plus the already-shipped z.ai/GLM provider, GLM 5.2+ effort
passthrough, web-search-prime MCP and the ultracode toggle.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-20 17:27:46 +02:00

171 lines
5.8 KiB
C#
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using System.Collections.Generic;
using System.Text.Json;
using System.Text.Json.Serialization;
namespace Gott.Models;
public class ChatMessage
{
[JsonPropertyName("role")]
public string Role { get; set; } = "";
[JsonPropertyName("content")]
public JsonElement Content { get; set; }
/// <summary>
/// Extrahiert den reinen Text aus Content (egal ob string oder content-block array).
/// </summary>
public string GetTextContent()
{
if (Content.ValueKind == JsonValueKind.String)
return Content.GetString() ?? "";
if (Content.ValueKind == JsonValueKind.Array)
{
var parts = new List<string>();
foreach (var block in Content.EnumerateArray())
{
if (block.TryGetProperty("type", out var t) && t.GetString() == "text"
&& block.TryGetProperty("text", out var txt))
parts.Add(txt.GetString() ?? "");
}
return string.Join("\n", parts);
}
return Content.ToString();
}
/// <summary>
/// Prüft ob Datei-Attachments (image/document) enthalten sind.
/// </summary>
public bool HasAttachments()
{
if (Content.ValueKind != JsonValueKind.Array) return false;
foreach (var block in Content.EnumerateArray())
{
if (block.TryGetProperty("type", out var t))
{
var type = t.GetString();
if (type == "image" || type == "document") return true;
}
}
return false;
}
/// <summary>
/// Gibt Attachment-Infos zurück (type + media_type).
/// </summary>
public List<AttachmentInfo> GetAttachments()
{
var result = new List<AttachmentInfo>();
if (Content.ValueKind != JsonValueKind.Array) return result;
foreach (var block in Content.EnumerateArray())
{
if (block.TryGetProperty("type", out var t))
{
var type = t.GetString();
if (type == "image" || type == "document")
{
var mediaType = "";
if (block.TryGetProperty("source", out var src) && src.TryGetProperty("media_type", out var mt))
mediaType = mt.GetString() ?? "";
result.Add(new AttachmentInfo { Type = type, MediaType = mediaType });
}
}
}
return result;
}
/// <summary>
/// Gibt vollständige Attachment-Blöcke zurück (inkl. Base64-Daten).
/// </summary>
public List<AttachmentBlock> GetAttachmentBlocks()
{
var result = new List<AttachmentBlock>();
if (Content.ValueKind != JsonValueKind.Array) return result;
foreach (var block in Content.EnumerateArray())
{
if (block.TryGetProperty("type", out var t))
{
var type = t.GetString();
if (type == "image" || type == "document")
{
var mediaType = "";
var data = "";
var fileName = "";
if (block.TryGetProperty("source", out var src))
{
if (src.TryGetProperty("media_type", out var mt))
mediaType = mt.GetString() ?? "";
if (src.TryGetProperty("data", out var d))
data = d.GetString() ?? "";
}
if (block.TryGetProperty("_file_name", out var fn))
fileName = fn.GetString() ?? "";
result.Add(new AttachmentBlock { Type = type, MediaType = mediaType, Data = data, FileName = fileName });
}
}
}
return result;
}
}
public class AttachmentBlock
{
public string Type { get; set; } = "";
public string MediaType { get; set; } = "";
public string Data { get; set; } = "";
public string FileName { get; set; } = "";
}
public class AttachmentInfo
{
public string Type { get; set; } = "";
public string MediaType { get; set; } = "";
}
public class ChatRequest
{
[JsonPropertyName("content")]
public JsonElement Content { get; set; }
[JsonPropertyName("sessionId")]
public string SessionId { get; set; } = "";
/// <summary>
/// Wenn gesetzt: Dies ist eine Antwort auf ein ask_user_choice Tool.
/// Enthält die tool_use_id des offenen ask_user_choice-Calls.
/// </summary>
[JsonPropertyName("choiceToolCallId")]
public string ChoiceToolCallId { get; set; }
/// <summary>
/// Der gewählte Text aus den Auswahloptionen.
/// </summary>
[JsonPropertyName("choiceResult")]
public string ChoiceResult { get; set; }
/// <summary>
/// Wenn true: Plan-Modus aktiv. Nur Read-only Tools, keine Datei-Änderungen.
/// </summary>
[JsonPropertyName("planMode")]
public bool PlanMode { get; set; }
/// <summary>
/// Wenn true: Ultracode aktiv. Die Anfrage wird als nativer dynamischer Workflow
/// (mehrere Subagenten) gefahren – das Workflow-Tool wird freigeschaltet, Effort = xhigh.
/// Nur für den Claude-CLI-Pfad relevant (z.ai/GLM und der API-Pfad haben kein Workflow-Runtime).
/// </summary>
[JsonPropertyName("ultracode")]
public bool Ultracode { get; set; }
/// <summary>
/// On-demand Panel-Modus für genau diese Anfrage (transient, NICHT persistent):
/// "" / "off" / "fusion" / "moa". Wie Plan-/Ultracode-Modus pro Request gewählt.
/// Die Panel-Mitglieder kommen weiterhin aus der persistierten Session (PanelAgentIds),
/// nur der Modus (ob/wie das Panel läuft) wird hier pro Anfrage gesetzt.
/// </summary>
[JsonPropertyName("multiModelMode")]
public string MultiModelMode { get; set; } = "";
}