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 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", 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); } }