Prompt history: list preview shows the message as written, not the engine's time line (#660)

Version 0.1.13.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Richard
2026-09-19 15:36:55 +02:00
co-authored by Claude Opus 5
parent 5adf4c1ca6
commit 996330a77e
6 changed files with 19 additions and 6 deletions
+3 -2
View File
@@ -217,7 +217,7 @@ public sealed class AgentEngine : IAgentMessageRouter, Staging.IFrozenCallExecut
messages.Add(ChatMessage.System(systemPrompt));
messages.Add(ChatMessage.User(MitZeit(userMessage, source)));
recorder.Begin(systemPrompt, messages[^1].Content?.ToString() ?? userMessage);
recorder.Begin(systemPrompt, messages[^1].Content ?? userMessage, userMessage);
string? finalMessage = null;
var truncated = false;
@@ -556,7 +556,8 @@ public sealed class AgentEngine : IAgentMessageRouter, Staging.IFrozenCallExecut
AddChatEntry(agentConfig.AgentId, "user", userMessage, source);
recorder.Begin(
messages.Count > 0 && messages[0].Role == "system" ? messages[0].Content?.ToString() : null,
messages[^1].Content?.ToString() ?? userMessage);
messages[^1].Content ?? userMessage,
userMessage);
string? finalMessage = null;
var truncated = false;
@@ -64,6 +64,10 @@ public sealed record RunTranscript
public DateTime? CompletedAt { get; init; }
public string Status { get; init; } = "";
public string? SystemPromptHash { get; init; }
/// <summary>The task or message as written, for lists. Falls back to the first user entry.</summary>
public string? PromptPreview { get; init; }
public IReadOnlyList<TranscriptEntry> Entries { get; init; } = [];
/// <summary>Characters stored, after clipping.</summary>
@@ -34,6 +34,9 @@ public sealed class RunTranscriptRecorder
public bool Enabled { get; }
public string? SystemPrompt { get; private set; }
/// <summary>The message as sent by its author - without the time line the engine prepends.</summary>
public string? PromptPreview { get; private set; }
public DateTime StartedAt { get; }
public RunTranscriptRecorder(bool enabled = true, TimeProvider? clock = null)
@@ -45,11 +48,14 @@ public sealed class RunTranscriptRecorder
// ─── Engine hooks ───
public void Begin(string? systemPrompt, string userMessage)
/// <param name="sentMessage">What the model received, including what the engine added.</param>
/// <param name="originalMessage">The message as its author wrote it - the list preview.</param>
public void Begin(string? systemPrompt, string sentMessage, string? originalMessage = null)
{
if (!Enabled) return;
SystemPrompt = string.IsNullOrWhiteSpace(systemPrompt) ? null : SecretScrubber.Scrub(systemPrompt);
Add(TranscriptEntryKind.User, userMessage, MaxTextChars);
PromptPreview = SecretScrubber.Scrub(originalMessage ?? sentMessage);
Add(TranscriptEntryKind.User, sentMessage, MaxTextChars);
}
/// <summary>A message the engine sent on its own (follow-up after an empty answer etc.).</summary>
@@ -127,6 +133,7 @@ public sealed class RunTranscriptRecorder
CompletedAt = _clock.GetUtcNow().UtcDateTime,
Status = status,
SystemPromptHash = SystemPrompt is null ? null : Hash(SystemPrompt),
PromptPreview = PromptPreview,
Entries = _entries.ToList(),
SizeChars = _size,
Truncated = _truncated
@@ -69,7 +69,7 @@ public sealed class SqliteRunTranscriptStore(SqliteStorage storage) : IRunTransc
cmd.Parameters.AddWithValue("@completed", t.CompletedAt is { } c ? Format(c) : DBNull.Value);
cmd.Parameters.AddWithValue("@status", t.Status);
cmd.Parameters.AddWithValue("@hash", (object?)t.SystemPromptHash ?? DBNull.Value);
cmd.Parameters.AddWithValue("@prompt", Snippet(t.Entries.FirstOrDefault(e => e.Kind == TranscriptEntryKind.User)?.Text));
cmd.Parameters.AddWithValue("@prompt", Snippet(t.PromptPreview ?? t.Entries.FirstOrDefault(e => e.Kind == TranscriptEntryKind.User)?.Text));
cmd.Parameters.AddWithValue("@response", Snippet(t.Entries.LastOrDefault(e => e.Kind == TranscriptEntryKind.Assistant && !string.IsNullOrWhiteSpace(e.Text))?.Text));
cmd.Parameters.AddWithValue("@entries", JsonSerializer.Serialize(t.Entries, Json));
cmd.Parameters.AddWithValue("@size", t.SizeChars);