Plan-Modus: System-Prompt-Blöcke kontextabhängig anpassen

- SystemPromptBuilder.BuildBlocks/Build bekommt planMode-Parameter
- Im Plan-Modus: Tools-Block zeigt nur Read-only-Tools (read_file, list_files, glob, grep)
- Im Plan-Modus: KRITISCH, Verhalten, Erinnerung und Git-Blöcke werden übersprungen
- Im Plan-Modus: Skills als 'nicht ausführbar' markiert
- Plan-Modus-Block zentral im SystemPromptBuilder statt doppelt in AnthropicService + SessionEndpoint
- ChatService reicht planMode an SystemPromptBuilder durch
- SessionEndpoint reicht planMode Query-Parameter an BuildBlocks durch
- System-Prompt-Modal zeigt korrekte Blöcke je nach Plan-Modus-Status
This commit is contained in:
Meleki committed 2026-03-07 12:20:44 +01:00
1 parent 6d95f9aec2
commit 8e0ae90dc6
6 files changed
+55 -32

No files matched your search

+2 -1
View File
@@ -214,7 +214,8 @@ public static class SessionEndpoint
var resolvedWorkspace = WorkspaceHelper.ResolveWorkspace(session, user);
if (string.IsNullOrEmpty(resolvedWorkspace) && agentSkills.Any())
resolvedWorkspace = "/tmp";
var blocks = SystemPromptBuilder.BuildBlocks(agent, session, markedMessages, memoryService, agentMemoryDir, agentSkills, skillService, userPersona: user?.GetEffectivePersona(), resolvedWorkspace: resolvedWorkspace);
var planMode = ctx.Request.Query.ContainsKey("planMode") && ctx.Request.Query["planMode"] == "true";
var blocks = SystemPromptBuilder.BuildBlocks(agent, session, markedMessages, memoryService, agentMemoryDir, agentSkills, skillService, userPersona: user?.GetEffectivePersona(), resolvedWorkspace: resolvedWorkspace, planMode: planMode);
await ctx.Response.WriteAsJsonAsync(blocks.Select(b => new { b.Icon, b.Label, b.Content }));
}
-14
View File
@@ -59,20 +59,6 @@ public class AnthropicService
int reviewRound = 0;
string lastStopReason = "";
// Plan-Modus: System-Prompt-Ergänzung
if (planMode && systemPrompt != null)
{
systemPrompt.Add(new { type = "text", text = @"## Plan-Modus aktiv
Der User hat den Plan-Modus aktiviert. Du DARFST KEINE Änderungen vornehmen:
- KEINE Dateien erstellen, bearbeiten oder löschen
- KEINE Shell-Befehle ausführen die Änderungen vornehmen (Commits, Installationen etc.)
- NUR lesen, analysieren, suchen und planen
- Nutze read_file, list_files, glob, grep und web_search um den Codebase zu verstehen
- Nutze ask_user_choice um Rückfragen zu stellen und Anforderungen zu klären
- Erstelle einen strukturierten Plan mit Aufgaben, Abhängigkeiten und Reihenfolge
- Der User wird den Plan-Modus deaktivieren wenn du mit der Umsetzung beginnen sollst" });
}
var chain = new ChainRecord
{
ChainId = chainId,
+1 -1
View File
@@ -66,7 +66,7 @@ public class ChatService
var systemPromptText = SystemPromptBuilder.Build(
agent, session, markedMessages, _memoryService, agentMemoryDir,
agentSkills, _skillService, userPersona: user?.GetEffectivePersona(),
resolvedWorkspace: workspace);
resolvedWorkspace: workspace, planMode: planMode);
var toolChoice = agent.ToolChoice ?? "any";
var hasWorkspace = !string.IsNullOrEmpty(workspace);
+48 -13
View File
@@ -13,7 +13,7 @@ public class PromptBlock
public static class SystemPromptBuilder
{
public static List<PromptBlock> BuildBlocks(AgentRecord agent, SessionRecord session, IEnumerable<MessageRecord> markedMessages = null, MemoryService memoryService = null, string agentMemoryDir = null, IEnumerable<string> skillSlugs = null, SkillService skillService = null, string userPersona = null, string resolvedWorkspace = null)
public static List<PromptBlock> BuildBlocks(AgentRecord agent, SessionRecord session, IEnumerable<MessageRecord> markedMessages = null, MemoryService memoryService = null, string agentMemoryDir = null, IEnumerable<string> skillSlugs = null, SkillService skillService = null, string userPersona = null, string resolvedWorkspace = null, bool planMode = false)
{
var blocks = new List<PromptBlock>();
@@ -50,7 +50,7 @@ public static class SystemPromptBuilder
var effectiveWorkspace = resolvedWorkspace ?? session.Workspace;
if (!string.IsNullOrWhiteSpace(effectiveWorkspace))
{
if (toolAny)
if (toolAny && !planMode)
{
blocks.Add(new PromptBlock
{
@@ -61,16 +61,32 @@ JEDE Datei-Operation und JEDER Shell-Befehl MUSS über einen Tool-Aufruf erfolge
});
}
blocks.Add(new PromptBlock
if (planMode)
{
Icon = "fa-wrench",
Label = "Session · Workspace",
Content = @$"## Tools
blocks.Add(new PromptBlock
{
Icon = "fa-wrench",
Label = "Session · Workspace (Plan-Modus)",
Content = @$"## Tools
Du hast Read-only-Tools zur Verfügung (read_file, list_files, glob, grep). Benutze sie um den Code zu analysieren und zu verstehen.
Der Workspace-Pfad ist: `{effectiveWorkspace}`
Alle Dateipfade in Tool-Aufrufen müssen relativ zu diesem Workspace sein oder absolute Pfade verwenden, die mit diesem Pfad beginnen."
});
}
else
{
blocks.Add(new PromptBlock
{
Icon = "fa-wrench",
Label = "Session · Workspace",
Content = @$"## Tools
Du hast Tools zur Verfügung (read_file, write_file, edit_file, list_files, delete_file, execute). Benutze sie um Dateien zu lesen, schreiben und bearbeiten.
Der Workspace-Pfad ist: `{effectiveWorkspace}`
Alle Dateipfade in Tool-Aufrufen müssen relativ zu diesem Workspace sein oder absolute Pfade verwenden, die mit diesem Pfad beginnen."
});
});
}
}
// Rückfragen-Hinweis
@@ -113,7 +129,10 @@ Alle Dateipfade in Tool-Aufrufen müssen relativ zu diesem Workspace sein oder a
skillNames.Add(skill.Name ?? slug);
}
var skillLabel = "Agent · Skills: " + string.Join(", ", skillNames);
var skillSection = "## Skills\nDu hast folgende Skills zur Verfügung. Nutze sie über das `execute`-Tool wenn der User etwas anfragt, das ein Skill abdeckt.\n\n"
var skillIntro = planMode
? "## Skills\nFolgende Skills sind verfügbar (im Plan-Modus nur zur Kenntnis – nicht ausführbar):\n\n"
: "## Skills\nDu hast folgende Skills zur Verfügung. Nutze sie über das `execute`-Tool wenn der User etwas anfragt, das ein Skill abdeckt.\n\n";
var skillSection = skillIntro
+ string.Join("\n\n---\n\n", skillParts);
blocks.Add(new PromptBlock { Icon = "fa-puzzle-piece", Label = skillLabel, Content = skillSection });
}
@@ -148,8 +167,8 @@ Alle Dateipfade in Tool-Aufrufen müssen relativ zu diesem Workspace sein oder a
blocks.Add(new PromptBlock { Icon = "fa-database", Label = "Agent · Memory (UseMemory)", Content = string.Join("\n", memoryLines) });
}
// Git-Commit-Verhalten: relevant sobald Workspace vorhanden (unabhängig von ToolChoice)
if (!string.IsNullOrWhiteSpace(effectiveWorkspace))
// Git-Commit-Verhalten: relevant sobald Workspace vorhanden (nicht im Plan-Modus)
if (!string.IsNullOrWhiteSpace(effectiveWorkspace) && !planMode)
{
var autoCommit = (agent.AutoCommit ?? "").ToLowerInvariant();
if (autoCommit == "mention")
@@ -182,7 +201,7 @@ Alle Dateipfade in Tool-Aufrufen müssen relativ zu diesem Workspace sein oder a
// autoCommit == "" → kein Block, Thema wird nicht erwähnt
}
if (toolAny && !string.IsNullOrWhiteSpace(effectiveWorkspace))
if (toolAny && !string.IsNullOrWhiteSpace(effectiveWorkspace) && !planMode)
{
blocks.Add(new PromptBlock
{
@@ -208,6 +227,22 @@ Diese Regel hat höchste Priorität und gilt für JEDE Antwort: Wenn eine Datei
}
// kein extra Erinnerungsblock ohne toolAny – Zeilenreferenz-Hinweise kommen direkt über die Nachricht
// Plan-Modus-Block
if (planMode)
{
blocks.Add(new PromptBlock
{
Icon = "fa-map",
Label = "Plan-Modus aktiv",
Content = "## Plan-Modus\nDer User hat den Plan-Modus aktiviert. Du DARFST KEINE Änderungen vornehmen:\n" +
"- KEINE Dateien schreiben, editieren oder löschen\n" +
"- KEINE Shell-Befehle ausführen (außer read-only wie cat, ls, find, grep)\n" +
"- KEINE Commits erstellen\n\n" +
"Stattdessen: Analysiere, stelle Rückfragen und erstelle einen detaillierten Plan.\n" +
"Der User wird den Plan-Modus deaktivieren wenn du mit der Umsetzung beginnen sollst."
});
}
var marked = markedMessages?.Where(m => !string.IsNullOrWhiteSpace(m.Content)).ToList();
if (marked != null && marked.Count > 0)
{
@@ -223,9 +258,9 @@ Diese Regel hat höchste Priorität und gilt für JEDE Antwort: Wenn eine Datei
return blocks;
}
public static string Build(AgentRecord agent, SessionRecord session, IEnumerable<MessageRecord> markedMessages = null, MemoryService memoryService = null, string agentMemoryDir = null, IEnumerable<string> skillSlugs = null, SkillService skillService = null, string userPersona = null, string resolvedWorkspace = null)
public static string Build(AgentRecord agent, SessionRecord session, IEnumerable<MessageRecord> markedMessages = null, MemoryService memoryService = null, string agentMemoryDir = null, IEnumerable<string> skillSlugs = null, SkillService skillService = null, string userPersona = null, string resolvedWorkspace = null, bool planMode = false)
{
var blocks = BuildBlocks(agent, session, markedMessages, memoryService, agentMemoryDir, skillSlugs, skillService, userPersona, resolvedWorkspace);
var blocks = BuildBlocks(agent, session, markedMessages, memoryService, agentMemoryDir, skillSlugs, skillService, userPersona, resolvedWorkspace, planMode);
return string.Join("\n\n", blocks.Select(b => b.Content));
}
}
+3 -2
View File
@@ -178,8 +178,9 @@ async function apiGetSystemPrompt(sessionId) {
return resp.text();
}
async function apiGetSystemPromptBlocks(sessionId) {
const resp = await fetch(`/api/sessions/${sessionId}/system-prompt-blocks`);
async function apiGetSystemPromptBlocks(sessionId, planMode) {
const url = `/api/sessions/${sessionId}/system-prompt-blocks` + (planMode ? '?planMode=true' : '');
const resp = await fetch(url);
if (!resp.ok) throw new Error('System-Prompt konnte nicht geladen werden');
return resp.json();
}
+1 -1
View File
@@ -1338,7 +1338,7 @@ async function showSystemPromptModal(sessionId) {
// Laden
try {
const blocks = await apiGetSystemPromptBlocks(sessionId);
const blocks = await apiGetSystemPromptBlocks(sessionId, typeof _planModeActive !== 'undefined' && _planModeActive);
body.innerHTML = '';
_renderSystemPromptBlocks(body, blocks);
} catch (e) {