feat: Vorbereiter-Agent (Preparer) für Sessions
- Neues optionales Session-Feld 'preparerAgentId' (DB + Model + API) - PreparerContext im ChatContext für Agent-Konfiguration - RunPreparer() in AnthropicService: führt Preparer vor dem Worker aus - [FORWARD] → aufbereiteter Prompt wird an Session-Agent weitergegeben - Ohne [FORWARD] → Rückfrage an User, Flow stoppt (preparer_query) - Preparer-System-Prompt: erklärt Rolle, [FORWARD]-Mechanismus, Vorarbeit - Preparer kann eigene Tools + Fähigkeiten aktiv nutzen - ChatEndpoint: Preparer-Phase vor StreamChat integriert - Frontend: SSE-Events (preparer_start/text/tool_use/done) - Preparer-Bubble (Info-Farbe) mit Status Weitergeleitet/Rückfrage - [Preparer: Name] → hübscher Header, [FORWARD] ausgeblendet - [Vorbereitet von Name] → dezenter Header in User-Bubble - Agent-Picker im Session-Form (vor Review-Agent)
This commit is contained in:
1 parent
f12fbfdc3e
commit
494f431963
12 files changed
+306
-8
No files matched your search
@@ -135,6 +135,50 @@ public static class ChatEndpoint
|
||||
res.Headers["Cache-Control"] = "no-cache";
|
||||
res.Headers["Connection"] = "keep-alive";
|
||||
|
||||
// ── Preparer-Agent Phase (vor dem Worker) ──
|
||||
if (ctx.Preparer != null && !isChoiceResponse)
|
||||
{
|
||||
var preparerResult = await anthropic.RunPreparer(
|
||||
res, ctx.Preparer, messages, ctx.ChainId, ctx.Workspace, sessionId, cancellationToken);
|
||||
|
||||
if (!preparerResult.ShouldForward)
|
||||
{
|
||||
// Preparer hat eine Rückfrage → Antwort als Text streamen, Flow beenden
|
||||
// Preparer-Antwort wird schon in RunAgentChat in DB gespeichert
|
||||
await AnthropicService.WriteSseEvent(res, "done", new
|
||||
{
|
||||
chainId = ctx.ChainId,
|
||||
stopReason = "preparer_query",
|
||||
planMode = ctx.PlanMode
|
||||
}, cancellationToken);
|
||||
return;
|
||||
}
|
||||
|
||||
// Preparer ist zufrieden → aufbereiteten Prompt als zusätzlichen Kontext an die History anhängen
|
||||
if (!string.IsNullOrWhiteSpace(preparerResult.ForwardedPrompt))
|
||||
{
|
||||
// Den aufbereiteten Prompt als System-Context-Message einfügen
|
||||
messages.Add(new Dictionary<string, object>
|
||||
{
|
||||
["role"] = "user",
|
||||
["content"] = new List<object>
|
||||
{
|
||||
new { type = "text", text = $"[Vorbereitet von {ctx.Preparer.Agent?.Name ?? "Vorbereiter-Agent"}]:\n{preparerResult.ForwardedPrompt}" }
|
||||
}
|
||||
});
|
||||
|
||||
// Auch in DB speichern
|
||||
await db.SaveMessage(new MessageRecord
|
||||
{
|
||||
ChainId = ctx.ChainId,
|
||||
Iteration = 0,
|
||||
Role = "user",
|
||||
Type = "text",
|
||||
Content = $"[Vorbereitet von {ctx.Preparer.Agent?.Name ?? "Vorbereiter-Agent"}]:\n{preparerResult.ForwardedPrompt}"
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Bei Choice-Response: toolChoice auf "auto" setzen, damit Claude frei antworten kann
|
||||
var effectiveToolChoice = isChoiceResponse ? "auto" : ctx.ToolChoice;
|
||||
|
||||
|
||||
@@ -82,8 +82,9 @@ public static class SessionEndpoint
|
||||
var reviewAgentId = body.TryGetProperty("reviewAgentId", out var ra) ? ra.GetString() : null;
|
||||
var maxReviewIterations = body.TryGetProperty("maxReviewIterations", out var mri) ? mri.GetInt32() : 3;
|
||||
var finalizerAgentId = body.TryGetProperty("finalizerAgentId", out var fa) ? fa.GetString() : null;
|
||||
var preparerAgentId = body.TryGetProperty("preparerAgentId", out var pra) ? pra.GetString() : null;
|
||||
|
||||
var session = await db.CreateSession(userId, name, description, image, agentId, workspace, context, customCommands, avatarScale, avatarOffsetX, avatarOffsetY, reviewAgentId, maxReviewIterations, finalizerAgentId);
|
||||
var session = await db.CreateSession(userId, name, description, image, agentId, workspace, context, customCommands, avatarScale, avatarOffsetX, avatarOffsetY, reviewAgentId, maxReviewIterations, finalizerAgentId, preparerAgentId);
|
||||
await ctx.Response.WriteAsJsonAsync(session);
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user