Verweis statt Nacherzaehlung: die Engine stempelt den Ursprung (#697, #677)

- Werkzeugkontext kennt Lauf und Aufgabe des Laufs (RunId, RunTaskId); die
  Delegationskette traegt den Lauf des Aufrufers weiter (RunId, CallerRunId)
- Aufgaben tragen origin_run / origin_task (Datei, DB, Taskboard "Arose from"),
  gestempelt, nie vom Agenten behauptet
- Kommentare nennen den Lauf, in dem sie geschrieben wurden
- Laufbeleg: CallerRunId; Laufansicht fuehrt zu "Delegiert von" und "Delegiert an"
- #677: task_update ersetzt den Rumpf nicht mehr, Abnahmekriterien aendert nur der
  Ersteller; Kommentare der Fremdinhalt-Stufe auf fremden Aufgaben kommen gerahmt an
- WebUI: Herkunft auf der Aufgabenkarte mit Link zum Lauf

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Richard
2026-09-25 09:27:47 +02:00
co-authored by Claude Opus 5.5
parent 3f90e0d0cd
commit f812dbd856
26 changed files with 493 additions and 47 deletions
@@ -182,20 +182,16 @@ public static class AnalyticsEndpoints
// ─── Mapping ───
private static RunRowDto ToDto(RunRow row)
{
var r = row.Receipt;
return new RunRowDto(r.RunId, r.AgentId, r.Model, r.Source, r.TaskId, row.TaskTitle, r.Status,
private static RunRowDto ToDto(RunRow row) => Row(row.Receipt, row.TaskTitle);
private static RunRowDto Row(Core.Audit.RunReceipt r, string? taskTitle)
=> new(r.RunId, r.AgentId, r.Model, r.Source, r.TaskId, taskTitle, r.Status,
r.StepCount, r.PromptTokens, r.CompletionTokens, r.CachedTokens, r.CostUsd, r.CostIsKnown,
r.DurationMs, r.ResultRef, r.OccurredAt);
}
r.DurationMs, r.ResultRef, r.OccurredAt, r.CallerRunId);
private static RunDetailDto ToDto(RunDetail d) => new(
d.RunId,
d.Receipt is { } r
? new RunRowDto(r.RunId, r.AgentId, r.Model, r.Source, r.TaskId, d.TaskTitle, r.Status, r.StepCount,
r.PromptTokens, r.CompletionTokens, r.CachedTokens, r.CostUsd, r.CostIsKnown, r.DurationMs, r.ResultRef, r.OccurredAt)
: null,
d.Receipt is { } r ? Row(r, d.TaskTitle) : null,
d.ToolCalls.Select(c => new RunToolCallDto(c.OccurredAt, c.Tool, c.Status.ToString(), c.Arguments, c.Summary, c.DurationMs, c.Source)).ToList(),
d.Approvals.Select(c => c.ToDto()).ToList(),
d.Transcript is { } t
@@ -203,7 +199,8 @@ public static class AnalyticsEndpoints
t.Entries, t.SizeChars, t.Truncated)
: null,
d.SystemPrompt,
d.TranscriptState);
d.TranscriptState,
(d.CalledRuns ?? []).Select(c => Row(c, null)).ToList());
private static PromptHistorySettingsDto SettingsDto(AppHost host)
{
@@ -223,7 +220,9 @@ public static class AnalyticsEndpoints
public sealed record RunRowDto(
string RunId, string AgentId, string Model, string Source, string? TaskId, string? TaskTitle,
string Status, int StepCount, int PromptTokens, int CompletionTokens, int CachedTokens,
decimal CostUsd, bool CostIsKnown, long DurationMs, string Result, DateTime OccurredAt);
decimal CostUsd, bool CostIsKnown, long DurationMs, string Result, DateTime OccurredAt,
// #697: the run this one was delegated from.
string? CallerRunId = null);
public sealed record RunTotalsDto(
int Runs, long PromptTokens, long CompletionTokens, long CachedTokens,
@@ -259,7 +258,9 @@ public sealed record RunDetailDto(
IReadOnlyList<StagedCallDto> Approvals,
TranscriptDto? Transcript,
string? SystemPrompt,
string TranscriptState);
string TranscriptState,
// #697: the runs this one delegated to.
IReadOnlyList<RunRowDto>? CalledRuns = null);
public sealed record TranscriptSummaryDto(
string RunId, string AgentId, string Model, string Source, string? TaskId,