summaryrefslogtreecommitdiff
path: root/src/Agent.Core
diff options
context:
space:
mode:
Diffstat (limited to 'src/Agent.Core')
-rw-r--r--src/Agent.Core/Prompts/PromptComposer.cs22
-rw-r--r--src/Agent.Core/Runtime/AgentRuntime.cs2
-rw-r--r--src/Agent.Core/Runtime/AgentRuntimeSettings.cs4
-rw-r--r--src/Agent.Core/Skills/AgentSkill.cs15
-rw-r--r--src/Agent.Core/Tools/InternalToolCatalog.cs2
-rw-r--r--src/Agent.Core/Tools/InternalToolValidator.cs2
6 files changed, 43 insertions, 4 deletions
diff --git a/src/Agent.Core/Prompts/PromptComposer.cs b/src/Agent.Core/Prompts/PromptComposer.cs
index e07c7e8..69b18f3 100644
--- a/src/Agent.Core/Prompts/PromptComposer.cs
+++ b/src/Agent.Core/Prompts/PromptComposer.cs
@@ -1,5 +1,6 @@
using Agent.Core.Ollama;
using Agent.Core.Sessions;
+using Agent.Core.Skills;
namespace Agent.Core.Prompts;
@@ -7,7 +8,8 @@ public sealed record PromptContext(
string FixedSystemPrompt,
string UserSystemPrompt,
string Locale,
- IReadOnlyList<string> Skills,
+ IReadOnlyList<AgentSkill> AvailableSkills,
+ IReadOnlyList<AgentSkill> SelectedSkills,
string SandboxCapabilitySummary,
string TaskGraphSummary,
string PreviousSummary,
@@ -24,13 +26,29 @@ public static class PromptComposer
new("system", context.FixedSystemPrompt),
new("system", context.UserSystemPrompt),
new("system", $"Respond in locale: {context.Locale}."),
- new("system", string.Join("\n\n", context.Skills)),
+ new("system", ComposeSkillCatalog(context.AvailableSkills)),
new("system", context.SandboxCapabilitySummary),
new("system", context.TaskGraphSummary),
new("system", context.PreviousSummary)
};
+ // 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;
}
+
+ /// <summary>
+ /// Stage 1 Discovery: only name + description are included. Full instructions are NOT included.
+ /// </summary>
+ private static string ComposeSkillCatalog(IReadOnlyList<AgentSkill> skills)
+ {
+ if (skills.Count == 0) return "No skills available.";
+ var lines = new List<string> { "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);
+ }
}
diff --git a/src/Agent.Core/Runtime/AgentRuntime.cs b/src/Agent.Core/Runtime/AgentRuntime.cs
index 0fcf7d0..228ac41 100644
--- a/src/Agent.Core/Runtime/AgentRuntime.cs
+++ b/src/Agent.Core/Runtime/AgentRuntime.cs
@@ -1,6 +1,7 @@
using Agent.Core.Ollama;
using Agent.Core.Prompts;
using Agent.Core.Sessions;
+using Agent.Core.Skills;
using Agent.Core.Tasks;
using Agent.Core.Tools;
@@ -32,6 +33,7 @@ public sealed class AgentRuntime(TaskRegistry registry, IOllamaClient ollama, Ag
settings.UserSystemPrompt,
settings.Locale,
settings.Skills,
+ [], // SelectedSkills: populated after LLM skill selection (Progressive Disclosure Stage 2→3).
settings.SandboxCapabilitySummary,
"Current task: " + task.Request,
string.Empty,
diff --git a/src/Agent.Core/Runtime/AgentRuntimeSettings.cs b/src/Agent.Core/Runtime/AgentRuntimeSettings.cs
index 9bc04b9..65ee59d 100644
--- a/src/Agent.Core/Runtime/AgentRuntimeSettings.cs
+++ b/src/Agent.Core/Runtime/AgentRuntimeSettings.cs
@@ -1,9 +1,11 @@
+using Agent.Core.Skills;
+
namespace Agent.Core.Runtime;
public sealed record AgentRuntimeSettings(
string UserSystemPrompt,
string Locale,
- IReadOnlyList<string> Skills,
+ IReadOnlyList<AgentSkill> Skills,
string SandboxCapabilitySummary,
int MaxIterations = 128,
int SameFailureLimit = 5,
diff --git a/src/Agent.Core/Skills/AgentSkill.cs b/src/Agent.Core/Skills/AgentSkill.cs
new file mode 100644
index 0000000..fb0e6e9
--- /dev/null
+++ b/src/Agent.Core/Skills/AgentSkill.cs
@@ -0,0 +1,15 @@
+namespace Agent.Core.Skills;
+
+/// <summary>
+/// Agent Skills open standard (agentskills.io) compliant skill model.
+/// Populated from SKILL.md frontmatter and body by the SkillLoader.
+/// </summary>
+public sealed record AgentSkill(
+ string RootPath,
+ string Name,
+ string Description,
+ string Instructions,
+ string? License = null,
+ string? Compatibility = null,
+ IReadOnlyDictionary<string, string>? Metadata = null,
+ string? AllowedTools = null); \ No newline at end of file
diff --git a/src/Agent.Core/Tools/InternalToolCatalog.cs b/src/Agent.Core/Tools/InternalToolCatalog.cs
index 3ab17b1..14cba45 100644
--- a/src/Agent.Core/Tools/InternalToolCatalog.cs
+++ b/src/Agent.Core/Tools/InternalToolCatalog.cs
@@ -17,7 +17,7 @@ public static class InternalToolCatalog
[
Define("file_search", "Search files under an approved root.", """{"type":"object","additionalProperties":false,"required":["root","mode","query"],"properties":{"root":{"type":"string"},"mode":{"type":"string","enum":["glob","name","text","regex","tail"]},"query":{"type":"string"},"max_results":{"type":"integer","minimum":1,"maximum":1000},"tail_lines":{"type":"integer","minimum":1,"maximum":10000}}}"""),
Define("file_read", "Read an approved file.", """{"type":"object","additionalProperties":false,"required":["path","mode"],"properties":{"path":{"type":"string"},"mode":{"type":"string","enum":["whole","range","metadata"]},"start":{"type":"integer","minimum":0},"length":{"type":"integer","minimum":0}}}"""),
- Define("file_edit", "Edit an approved file transactionally.", """{"type":"object","additionalProperties":false,"required":["path","operation"],"properties":{"path":{"type":"string"},"operation":{"type":"string","enum":["overwrite","patch","atomic_replace","delete"]},"content":{"type":["string","null"]},"patch":{"type":["string","null"]},"expected_sha256":{"type":["string","null"]}}}"""),
+ Define("file_edit", "Edit an approved file transactionally.", """{"type":"object","additionalProperties":false,"required":["path","operation"],"properties":{"path":{"type":"string"},"operation":{"type":"string","enum":["overwrite","patch","atomic_replace","delete","rename"]},"content":{"type":["string","null"]},"patch":{"type":["string","null"]},"expected_sha256":{"type":["string","null"]},"new_path":{"type":["string","null"]}}}"""),
Define("process_run", "Run one approved executable with separated arguments.", """{"type":"object","additionalProperties":false,"required":["executable","args","cwd"],"properties":{"executable":{"type":"string"},"args":{"type":"array","items":{"type":"string"}},"cwd":{"type":"string"},"timeout_seconds":{"type":"integer","minimum":1},"stdin":{"type":["string","null"]}}}"""),
Define("task_update", "Update the deterministic task graph.", """{"type":"object","additionalProperties":false,"required":["operation"],"properties":{"operation":{"type":"string","enum":["add","add_dependency","set_state","set_estimate"]},"task_id":{"type":["string","null"]},"description":{"type":["string","null"]},"depends_on":{"type":"array","items":{"type":"string"}},"budget_class":{"type":["string","null"],"enum":["1K","2K","4K","8K","16K","32K","64K","128K",null]},"optimistic_tokens":{"type":"integer","minimum":0},"most_likely_tokens":{"type":"integer","minimum":0},"pessimistic_tokens":{"type":"integer","minimum":0},"state":{"type":["string","null"],"enum":["queued","planning","running","completed","failed","cancelled",null]}}}"""),
Define("dir", "Create, remove, or list directories under an approved root. Only empty directories can be removed.", """{"type":"object","additionalProperties":false,"required":["path","operation"],"properties":{"path":{"type":"string"},"operation":{"type":"string","enum":["mkdir","rmdir","list"]}}}""")
diff --git a/src/Agent.Core/Tools/InternalToolValidator.cs b/src/Agent.Core/Tools/InternalToolValidator.cs
index 091b790..d789dbf 100644
--- a/src/Agent.Core/Tools/InternalToolValidator.cs
+++ b/src/Agent.Core/Tools/InternalToolValidator.cs
@@ -66,6 +66,8 @@ public static class InternalToolValidator
throw new ToolValidationException($"{operation} requires content.");
if (operation == "patch" && (!arguments.TryGetProperty("patch", out JsonElement patch) || patch.ValueKind != JsonValueKind.String))
throw new ToolValidationException("patch requires patch text.");
+ if (operation == "rename" && (!arguments.TryGetProperty("new_path", out JsonElement newPath) || newPath.ValueKind != JsonValueKind.String || string.IsNullOrWhiteSpace(newPath.GetString())))
+ throw new ToolValidationException("rename requires new_path.");
}
if (name == "task_update")
{