Files
VolcanicAgenticCore/tests/Volcanic.AgenticCore.Telegram.Tests/SkillsChatTests.cs
EugeneTes bb1c534a7a feat(core): always-on INSTRUCTIONS.md in skill directories
A skill directory may hold INSTRUCTIONS.md, with or without SKILL.md. Its body
(frontmatter cut) goes into every system prompt in <skill_instructions>, re-read
on every run: 16 KB per file, 64 KB in total, truncation marked with the file's
path. /skills marks skills with instructions and lists instruction-only dirs.
2026-10-12 10:15:05 +00:00

71 lines
3.2 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using Volcanic.AgenticCore.Telegram.Tests.Support;
using Volcanic.AgenticCore.Testing;
namespace Volcanic.AgenticCore.Telegram.Tests;
public sealed class SkillsChatTests
{
private static void WriteSkill(string workspace, string dir, string name, string description)
{
var path = Path.Combine(workspace, ".volcanic", "skills", dir);
Directory.CreateDirectory(path);
File.WriteAllText(Path.Combine(path, "SKILL.md"), $"---\nname: {name}\ndescription: {description}\n---\nInstructions");
}
[Fact]
public async Task Skills_lists_only_this_chats_workspace_skills()
{
await using var host = new ChatHost();
await host.SendAsync("/skills");
Assert.Equal("No skills yet. Ask me to write one, or put it in .volcanic/skills/<name>/SKILL.md.", host.LastReply());
WriteSkill(host.WorkspaceOf(), "trips", "trip-planner", "Plans trips");
WriteSkill(host.WorkspaceOf(2002), "secret", "other-chat", "Belongs to another chat");
await host.SendAsync("/skills");
Assert.Equal("Skills (.volcanic/skills/<name>/SKILL.md)\n• trip-planner – Plans trips", host.LastReply());
}
[Fact]
public async Task The_model_sees_skills_written_during_the_session_on_the_next_run()
{
await using var host = new ChatHost();
host.Faux.Enqueue(FauxTurn.Say("one"), FauxTurn.Say("two"));
await host.SendAsync("hi");
await host.SettleAsync();
Assert.Contains("No skills yet.", host.Faux.Requests.Last().SystemPrompt);
WriteSkill(host.WorkspaceOf(), "trips", "trip-planner", "Plans trips");
WriteSkill(host.WorkspaceOf(2002), "secret", "other-chat", "Belongs to another chat");
await host.SendAsync("again");
await host.SettleAsync();
var prompt = host.Faux.Requests.Last().SystemPrompt!;
Assert.Contains("<name>trip-planner</name>", prompt);
Assert.Contains(Path.Combine(host.WorkspaceOf(), ".volcanic", "skills", "trips", "SKILL.md"), prompt);
Assert.DoesNotContain("other-chat", prompt);
}
[Fact]
public async Task Skills_marks_instructions_and_lists_instruction_only_folders()
{
await using var host = new ChatHost();
var root = Path.Combine(host.WorkspaceOf(), ".volcanic", "skills");
WriteSkill(host.WorkspaceOf(), "trips", "trip-planner", "Plans trips");
WriteSkill(host.WorkspaceOf(), "mail", "mailer", "Sends mail");
File.WriteAllText(Path.Combine(root, "trips", "INSTRUCTIONS.md"), "Prices in EUR.");
Directory.CreateDirectory(Path.Combine(root, "house-rules"));
File.WriteAllText(Path.Combine(root, "house-rules", "Instructions.md"), "Be brief.");
host.Faux.Enqueue(FauxTurn.Say("ok"));
await host.SendAsync("/skills");
Assert.Equal("Skills (.volcanic/skills/<name>/SKILL.md)\n• mailer – Sends mail\n• trip-planner – Plans trips (+ INSTRUCTIONS.md)\n• house-rules – INSTRUCTIONS.md only", host.LastReply());
await host.SendAsync("hi");
await host.SettleAsync();
var prompt = host.Faux.Requests.Last().SystemPrompt!;
Assert.Contains("<instructions skill=\"house-rules\"", prompt);
Assert.Contains("Prices in EUR.", prompt);
}
}