namespace ClawdDotNet.Web.Contracts;
// ─────────────────────────────────────────────────────────────────────────────
// Die Übertragungstypen der Weboberfläche.
//
// Warum es sie gibt, statt die Kerntypen zu serialisieren:
//
// 1. AgentConfig trägt Zugangsdaten. Ein `return agent;` hätte den
// Werkzeug-Konfigurationsbaum samt Passwörtern ins Netz geschickt — die Sorte
// Fehler, die niemandem auffällt, weil alles funktioniert.
// 2. Die Kerntypen ändern sich mit dem Kern. Ein neues Feld in TaskItem wäre sonst
// still eine API-Änderung, auf die sich jemand verlassen hat.
// 3. Die Grenze soll einen Prozesswechsel überstehen (siehe InstanceHttpHost). Über eine
// Prozessgrenze geht nur, was hier steht.
//
// Namen auf Englisch in camelCase wie im übrigen Code; die Beschreibungen auf Deutsch.
// ─────────────────────────────────────────────────────────────────────────────
/// Antwort auf einen verwaltenden Aufruf — dieselbe Form wie AdminResult.
public sealed record OutcomeDto(bool Ok, string Message);
/// Version, Bau und Instanz. Was auf der Info-Seite steht.
public sealed record InfoDto(
string AppVersion,
string BuildSummary,
string InstanceId,
string InstanceName,
bool EngineActive,
bool SchedulerActive,
bool StagingActive,
bool DeploymentcenterActive);
/// Erreichbarkeit und Guthaben bei OpenRouter.
public sealed record StatusDto(
bool ApiReachable,
string StatusText,
string CreditsText,
double? CreditBalance,
double? CreditRemaining);
/// Ein Agent, ohne alles, was ein Zugangsdatum sein könnte.
public sealed record AgentDto(
string AgentId,
string DisplayName,
string Model,
string Description,
string PromptCaching,
int MaxToolResultChars,
int MaxSteps,
int MaxContextTokens,
int TimeoutSeconds,
decimal DailyCostUsd,
long DailyTokens,
bool IsRunning,
IReadOnlyList Tools,
// #715: What makes the agent read foreign content — its tools, or "setting". Empty: standard tier.
IReadOnlyList ForeignContentSources,
bool TreatAsForeignReader,
// #712
AgentRuntimeDto Runtime);
/// #712: Where an agent's runs happen.
public sealed record AgentRuntimeDto(
string Kind,
IReadOnlyList AllowedTools,
int MaxTurns,
int TimeoutMinutes,
string Command,
IReadOnlyList Arguments,
IReadOnlyList Egress);
/// #712: What foreign runtimes find on this machine — never a key, only whether there is one.
public sealed record RuntimesDto(
bool SandboxAvailable,
string? SandboxReason,
IReadOnlyList Kinds,
IReadOnlyList DefaultAllowedTools,
ClaudeCodeDto ClaudeCode);
public sealed record ClaudeCodeDto(
string Executable,
string? Located,
string Auth,
bool HasApiKey,
bool HasOAuthToken);
/// #712: Changes to the Claude Code account. Empty keys keep the stored ones.
public sealed record ClaudeCodeInputDto(string? Executable, string? Auth, string? ApiKey, string? OAuthToken);
///
/// Ein Werkzeug am Agenten. Ohne die Einstellungen — die stehen in einem freien
/// Wörterbuch und enthalten regelmäßig Passwörter und Schlüssel. Was einstellbar ist und
/// ob etwas gesetzt ist, sagt .
///
public sealed record AgentToolDto(string Name, string Description, bool Enabled, bool ReadsForeignContent = false);
///
/// Die Einstellungen eines Werkzeugs, maskiert.
///
/// Ein Wert, dessen Name ein Zugangsdatum bezeichnet, kommt nie heraus. Statt
/// seiner steht in , ob überhaupt etwas gesetzt ist — mehr braucht
/// eine Anzeige nicht, und mehr darf sie nicht wissen.
///
public sealed record ToolSettingsDto(
string Name,
IReadOnlyDictionary Values,
IReadOnlyDictionary Secrets);
/// Eine Zeile im Chatverlauf.
public sealed record ChatEntryDto(
string Role,
string Content,
DateTime Timestamp,
string? Source);
/// Was der Browser schickt, wenn jemand etwas in den Chat tippt.
public sealed record SendMessageDto(string Message);
/// Ein Dienst der Instanz.
public sealed record ServiceDto(
string ServiceId,
string Name,
string Type,
int Port,
bool Enabled,
bool BuiltIn,
string Description);
/// Was einen neuen Dienst ausmacht.
public sealed record ServiceInputDto(string Name, string Type, int Port, string Description = "");
/// Ein neuer Agent.
public sealed record NewAgentDto(string AgentId, string DisplayName, string Model, string Description = "", string? UnitId = null);
/// Eine Aufgabe vom Taskboard.
public sealed record TaskDto(
string Id,
string Title,
string Status,
string Type,
int Priority,
string Assignee,
bool RequireApproval,
string Acceptance,
IReadOnlyList BlockedBy,
string Body,
DateTime CreatedAt,
DateTime UpdatedAt,
TaskWhenDto? When = null,
DateTime? NextRunUtc = null,
TaskLastRunDto? LastRun = null,
string? Hinweis = null,
TaskBudgetMissDto? BudgetMiss = null,
string? CreatedBy = null,
// #714: the task this one serves.
string? ParentId = null,
// #684: the unit whose board the task is on, computed from the organisation; null on the top level.
string? Board = null,
string? BoardPath = null,
// #697: where the task came from — stamped by the engine.
string? OriginRunId = null,
string? OriginTaskId = null,
// #717: fill work — a deadline instead of an appointment — and the author's estimate per run.
DateTime? FillBy = null,
decimal? EstimateUsd = null,
DateTime? FillAlertedAt = null,
// #686: a meeting's participants, in order.
IReadOnlyList? Participants = null);
/// #713: A personal MCP token as listed — never the token itself.
public sealed record McpTokenDto(
string Id, string AgentId, string Label, DateTime CreatedAt, DateTime ExpiresAt, DateTime? RevokedAt, bool Active);
/// #713: A new personal token — the only answer that carries it in clear.
public sealed record McpTokenIssuedDto(McpTokenDto Info, string Token);
/// #713: What the WebUI sends to issue a personal token.
public sealed record McpTokenInputDto(string AgentId, string? Label = null, int? Days = null);
/// #717: A special budget — the amount a human approved for a task tree, and what it used.
public sealed record SpecialBudgetDto(string TaskId, decimal AmountUsd, decimal SpentUsd, string Reason, string RequestedBy, DateTime ApprovedAt);
///
/// #716: Runs of this task the budget refused — only present while something is open
/// (misses since the last run that took place, a pending catch-up or a deferral).
///
public sealed record TaskBudgetMissDto(int Count, DateTime? LastAt, DateTime? DeferredUntil, bool CatchUpPending, bool CarriedOver);
/// #711: The team overview — every agent and unit, and who reached whom recently.
public sealed record TeamSnapshotDto(
IReadOnlyList Members,
IReadOnlyList Links,
DateTime AtUtc,
IReadOnlyList Units,
IReadOnlyList ConflictHotspots);
/// #720: A file agents keep overwriting each other in — shown with a warning. The path is relative to the instance's Agents folder.
public sealed record ConflictHotspotDto(string Workspace, string Path, int Conflicts, DateTime LastAtUtc, IReadOnlyList Agents);
///
/// #711, stage 1: A unit with the states of everyone in it and below, counted by the
/// instance. maps a state name to a count; is the
/// most urgent state inside.
///
public sealed record TeamUnitDto(
string Id,
string Name,
string? ParentId,
string Path,
string? LeaderAgentId,
string? Goal,
int Agents,
IReadOnlyDictionary States,
int PendingApprovals,
string Worst);
///
/// #711: One agent in the team overview. is one of Idle, Working, Stuck,
/// WaitingForApproval, Problem, BudgetExhausted — decided by the instance, not the page.
///
public sealed record TeamMemberDto(
string AgentId,
string DisplayName,
string Model,
string State,
IReadOnlyList Runs,
int PendingApprovals,
string? LastRunStatus,
DateTime? LastRunAtUtc,
string? LastRunResult,
long TypicalRunMs,
string? UnitId,
bool IsLead);
/// #711: A run in progress.
public sealed record ActiveRunDto(string RunId, string AgentId, string Source, string? TaskId, string? CalledBy, DateTime StartedAtUtc);
/// #711: One agent reaching another.
public sealed record AgentLinkDto(string From, string To, string Kind, DateTime AtUtc);
/// Der letzte Lauf einer Aufgabe (#594) - aus dem Beleg, samt Kosten.
public sealed record TaskLastRunDto(DateTime OccurredAt, string Status, decimal CostUsd, bool CostIsKnown, string ResultRef);
/// Was die Weboberflaeche beim Anlegen oder Aendern einer Aufgabe schickt (#594).
public sealed record TaskInputDto(
string Title,
string Body = "",
string Assignee = "",
string? WhenKind = null,
string? WhenValue = null,
string? TimeZone = null,
string Acceptance = "",
int Priority = 3,
string? ParentId = null,
string? FillBy = null,
decimal? EstimateUsd = null,
// #686: given, the task is a meeting chaired by the assignee.
IReadOnlyList? Participants = null);
/// Die Kostenprognose einer Instanz (#595).
public sealed record ForecastDto(
IReadOnlyList Tasks,
decimal TasksPerDay,
decimal OtherPerDay,
decimal TotalPerDay,
decimal TotalPerMonth,
decimal OneOffOpen,
int WithoutBasis,
IReadOnlyList BudgetWarnings);
/// Ein Agent, dessen geplante Aufgaben laut Prognose sein Tagesbudget uebersteigen (#608).
public sealed record ForecastBudgetDto(string AgentId, decimal CostPerDay, decimal BudgetPerDay);
/// Eine Zeile der Kostenprognose. Basis: Laeufe, Agent, Schaetzung oder Unbekannt.
public sealed record ForecastTaskDto(
string TaskId,
string Title,
string AgentId,
string Model,
double RunsPerDay,
bool OneOffOpen,
decimal? CostPerRun,
string Basis,
int Sample,
decimal CostPerDay);
///
/// Der Termin einer Aufgabe (cron, every, at) samt Zeitzone. Ohne ihn
/// war in der Oberflaeche eine stuendliche Aufgabe von einer einmaligen nicht zu
/// unterscheiden (#591).
///
public sealed record TaskWhenDto(string Kind, string Value, string TimeZone);
/// Ein eingefrorener Aufruf, der auf Freigabe wartet.
/// #641: Wie oft dieselbe Operation dieses Agenten zuletzt schon freigegeben wurde.
/// #641: Ob "Gleichartiges kuenftig erlauben" angeboten werden darf.
/// #641: Ob die Oberflaeche die Dauerfreigabe vorschlagen soll.
public sealed record StagedCallDto(
long Id,
string RunId,
string AgentId,
string Tool,
string? Action,
string Proposal,
string Status,
string ArgumentsJson,
DateTime CreatedAt,
int PreviousApprovals = 0,
bool CanAllowSimilar = false,
bool SuggestAllowSimilar = false,
// #687: the lead that may decide it instead of the human, and until when.
string? WithLead = null,
DateTime? LeadUntil = null);
/// #687: How a lead decided the approvals it was given.
public sealed record LeadApprovalStatsDto(string LeadId, int Routed, int Approved, int Rejected, int Lapsed, double? ApprovalRate);
/// #641: Eine Dauerfreigabe - "Gleichartiges kuenftig erlauben".
public sealed record StandingApprovalDto(
long Id,
string AgentId,
string Tool,
string Operation,
string GrantedBy,
DateTime GrantedAt,
long? SourceId,
DateTime? RevokedAt,
string? RevokedBy);
///
/// #641: Die Rechte eines Agenten an einem Werkzeug, je Operation.
/// Setting: "erlaubt", "verboten" oder "freigabe" (einzeln vorlegen) - so wie es in der
/// Konfiguration steht. Effective: was tatsaechlich geschieht ("auto", "approve",
/// "deny") - einschliesslich Dauerfreigaben und Werkzeugvorgabe.
///
public sealed record ToolRightsDto(
string Tool,
bool Configured,
IReadOnlyList Operations);
public sealed record ToolOperationDto(
string Operation,
string Setting,
string Effective,
string Reason,
bool AlwaysApproval,
long? StandingApprovalId);
/// #641: Neue Rechte. Allowed null = Liste entfernen, Vorgabe des Werkzeugs gilt.
public sealed record ToolRightsInputDto(IReadOnlyList? Allowed, IReadOnlyList? Denied);
/// Warum ein Vorschlag abgelehnt wurde.
public sealed record RejectDto(string Reason);
///
/// Ein Lauf mit dem, was er gekostet hat.
///
/// ist nicht schmückendes Beiwerk: Ohne geladene
/// Preisliste steht in eine Null, die „kostenlos" heißen könnte
/// und „unbekannt" heißt. Eine Anzeige, die das nicht unterscheidet, lügt.
///
public sealed record UsageDto(
long Id,
string AgentId,
string Model,
int PromptTokens,
int CompletionTokens,
int CachedTokens,
decimal CostUsd,
bool CostIsKnown,
string Status,
int StepCount,
DateTime OccurredAt);
/// Eine Protokollzeile.
public sealed record LogLineDto(string Module, string Level, string Text);
/// Eine interne Kommunikation zwischen Agenten (A2A, #208).
public sealed record AgentCommunicationDto(
string TargetAgentId,
string TargetAgentName,
string? SourceAgentId,
string? SourceAgentName,
string Role,
string Content,
DateTime Timestamp);
/// #719: One change in the history. Hashes are not sent — only whether a version exists.
public sealed record FileHistoryEntryDto(
long Id, string Workspace, string Path, string Action, string? AgentId, string? RunId,
bool HasBefore, bool HasAfter, long? SizeAfter, bool Stored, DateTime OccurredAtUtc, string? Note);
/// #719: A version's content. only for text of a showable size.
public sealed record FileVersionDto(string? Text, bool Binary, bool TooLarge, bool Kept, long Bytes);
/// #719: Putting a version back — which one, and why. Without a reason it is refused.
public sealed record FileRestoreInputDto(string? Version, string? Reason);
/// #699: A unit's costs, itself and everything below it. UnitId null: the instance; "": the top level.
public sealed record UnitCostDto(
string? UnitId, string Name, string Path, int Depth, int Agents,
decimal Today, decimal Last7Days, decimal Last30Days, decimal ThisMonth, decimal PreviousMonth,
decimal? MaxPerDay, decimal? AverageDay, decimal? ShareOfMaxToday,
long SubscriptionTokensToday, long SubscriptionTokens30Days);
/// #699: A cost alert as it was raised.
public sealed record CostAlertDto(string Period, string Scope, string Kind, string Message, DateTime RaisedAt);