feature/agents-rework #1
@@ -28,14 +28,83 @@
|
||||
# Returns the canonical attrset from lib.loadAgents (keyed by slug).
|
||||
loadCanonical = {agentsInput}: agentsInput.lib.loadAgents;
|
||||
|
||||
# Stub: OpenCode renderer — produces .opencode/agents/*.md files.
|
||||
# To be implemented in Task 9.
|
||||
# OpenCode renderer — produces a directory of .opencode/agents/*.md files.
|
||||
# Each file has YAML frontmatter (description, mode, optional model,
|
||||
# optional permission) followed by the agent's systemPrompt content.
|
||||
renderForOpencode = {
|
||||
pkgs,
|
||||
canonical,
|
||||
modelOverrides ? {},
|
||||
}:
|
||||
pkgs.runCommand "opencode-agents" {} "echo stub > $out";
|
||||
}: let
|
||||
# Split a rule string on the LAST colon to get { pattern, action }.
|
||||
# e.g. "rm -rf *:ask" → pattern="rm -rf *", action="ask"
|
||||
# e.g. "/run/agenix/**:deny" → pattern="/run/agenix/**", action="deny"
|
||||
parseRule = ruleStr: let
|
||||
parts = lib.strings.splitString ":" ruleStr;
|
||||
# last element is the action, everything before joined with ":" is pattern
|
||||
action = lib.last parts;
|
||||
pattern = lib.concatStringsSep ":" (lib.init parts);
|
||||
in {inherit pattern action;};
|
||||
|
||||
# Render one permission section to YAML lines (list of strings).
|
||||
# intent-only → single line: " <tool>: <intent>"
|
||||
# intent+rules → nested block starting with "*": <intent>, then specific rules
|
||||
renderPermSection = tool: section:
|
||||
if !(section ? rules) || section.rules == []
|
||||
then [" ${tool}: ${section.intent}"]
|
||||
else let
|
||||
parsedRules = map parseRule section.rules;
|
||||
wildcardLine = " \"*\": ${section.intent}";
|
||||
ruleLines = map (r: " \"${r.pattern}\": ${r.action}") parsedRules;
|
||||
in
|
||||
[" ${tool}:"] ++ [wildcardLine] ++ ruleLines;
|
||||
|
||||
# Render the full permission block for an agent.
|
||||
# Returns empty list if no permissions.
|
||||
renderPermBlock = permissions:
|
||||
if permissions == {} || permissions == null
|
||||
then []
|
||||
else
|
||||
["permission:"]
|
||||
++ lib.concatLists (
|
||||
lib.mapAttrsToList renderPermSection permissions
|
||||
);
|
||||
|
||||
# Build the YAML frontmatter string for one agent.
|
||||
mkFrontmatter = name: agent: let
|
||||
descLine = "description: \"${agent.description}.\"";
|
||||
modeLine = "mode: ${agent.mode}";
|
||||
modelLine =
|
||||
lib.optionalString
|
||||
(modelOverrides ? ${name})
|
||||
"model: ${modelOverrides.${name}}\n";
|
||||
permBlock = renderPermBlock (agent.permissions or {});
|
||||
permLines =
|
||||
if permBlock == []
|
||||
then ""
|
||||
else lib.concatStringsSep "\n" permBlock + "\n";
|
||||
in "---\n${descLine}\n${modeLine}\n${modelLine}${permLines}---\n";
|
||||
|
||||
# Build the full markdown file content for one agent.
|
||||
mkAgentContent = name: agent:
|
||||
(mkFrontmatter name agent) + agent.systemPrompt;
|
||||
|
||||
# Write each agent as a derivation text file.
|
||||
mkAgentFile = name: agent:
|
||||
pkgs.writeText "${name}.md" (mkAgentContent name agent);
|
||||
|
||||
# Attrset of name → derivation for each agent.
|
||||
agentFiles = lib.mapAttrs mkAgentFile canonical;
|
||||
|
||||
# Shell commands to copy each file into $out.
|
||||
copyCommands = lib.concatStringsSep "\n" (
|
||||
lib.mapAttrsToList (name: file: "cp ${file} $out/${name}.md") agentFiles
|
||||
);
|
||||
in
|
||||
pkgs.runCommand "opencode-agents" {} ''
|
||||
mkdir -p $out
|
||||
${copyCommands}
|
||||
'';
|
||||
|
||||
# Stub: Claude Code renderer — produces .claude/agents/*.md files.
|
||||
# To be implemented in Task 10.
|
||||
|
||||
Reference in New Issue
Block a user