using Agent.Core.Ollama; using Agent.Core.Sessions; using Agent.Core.Skills; namespace Agent.Core.Prompts; public sealed record PromptContext( string FixedSystemPrompt, string UserSystemPrompt, string Locale, IReadOnlyList AvailableSkills, IReadOnlyList SelectedSkills, string SandboxCapabilitySummary, string TaskGraphSummary, string PreviousSummary, IReadOnlyList ExecutionResults, IReadOnlyList Conversation, string OriginalRequest, string Request, bool RequiresExternalEffect, IReadOnlyList? Images = null); public static class PromptComposer { public static IReadOnlyList Compose(PromptContext context) { var messages = new List { new("system", context.FixedSystemPrompt), new("system", context.UserSystemPrompt), new("system", $"Respond in locale: {context.Locale}."), new("system", ComposeSkillCatalog(context.AvailableSkills)), new("system", context.SandboxCapabilitySummary), new("system", context.TaskGraphSummary), new("system", context.PreviousSummary), new("system", ComposeExecutionResults(context.ExecutionResults)), new("system", $"Original MCP Task request (reference for exact paths, arguments, constraints, and literals; perform only the current Running Planner Task):\n{context.OriginalRequest}"), new("system", ComposeExecutionRequirement(context.RequiresExternalEffect)) }; // Inject selected skill instructions (Progressive Disclosure Stage 3). foreach (AgentSkill skill in context.SelectedSkills) messages.Add(new("system", skill.Instructions)); messages.AddRange(context.Conversation.Select(static item => new OllamaMessage(item.Role, item.Content))); messages.Add(new OllamaMessage("user", context.Request, context.Images)); return messages; } private static string ComposeExecutionRequirement(bool requiresExternalEffect) => requiresExternalEffect ? "Perform only the current Running Planner Task; do not perform Queued Tasks. The current Planner Task requires a verified external effect. Call the appropriate available Internal Tool now. " + "A prose description, promise, plan, or fenced JSON example does not perform the operation and cannot complete this Task. " + "After a successful read, use its returned content and proceed to the required write or process operation without repeating the read unnecessarily." : "Perform only the current Running Planner Task; do not perform Queued Tasks. The current Planner Task does not require an external effect. Use an Internal Tool only when its verified result is needed; do not claim an unverified result."; private static string ComposeExecutionResults(IReadOnlyList results) { if (results.Count == 0) return "No prior Execution Results are available for the current Session."; var lines = new List { "Recent verified Execution Results:" }; foreach (ExecutionResult result in results) lines.Add($"- {result.ToolName} ({(result.Success ? "success" : "failed")}): {result.Output}"); return string.Join("\n", lines); } /// /// Stage 1 Discovery: only name + description are included. Full instructions are NOT included. /// private static string ComposeSkillCatalog(IReadOnlyList skills) { if (skills.Count == 0) return "No skills available."; var lines = new List { "Available skills:" }; foreach (AgentSkill skill in skills) lines.Add($"- {skill.Name}: {skill.Description}"); lines.Add("If a skill is relevant to the request, indicate which skills to use."); return string.Join("\n", lines); } }