ollie/tools/subagent_generate

110 lines
2.7 KiB
Python
Executable File

#!/usr/bin/env python3
# ollie:prompt
# ## subagent_generate
#
# Generate a JIT subagent config. No args prints the JSON template.
# With JSON input, creates the config and prints the agent name.
#
# **Args**: `[]` (prints template) or `[json_config]`
#
# ```
# call_tool: calls=[{tool: "subagent_generate", args: []}]
# call_tool: calls=[{tool: "subagent_generate", args: ["{...}"]}]
# ```
# ollie:end
import json
import os
import secrets
import sys
AGENTS_DIR = os.path.expanduser("~/.config/ollie/agents")
BASE_CONFIG = os.path.join(AGENTS_DIR, "default.json")
TEMPLATE = {
"name": "",
"role": "",
"roster": "",
"shared_task": "",
"protocol": "",
"constraints": [],
"prompt": "",
}
def die(msg):
print(f"subagent_generate: {msg}", file=sys.stderr)
sys.exit(1)
def main():
# No input: print template.
if len(sys.argv) < 2 and sys.stdin.isatty():
json.dump(TEMPLATE, sys.stdout, indent=2)
print()
return
# Read config from arg or stdin.
if len(sys.argv) > 1:
text = sys.argv[1]
else:
text = sys.stdin.read()
if not text.strip():
die("empty input")
try:
raw = json.loads(text)
except json.JSONDecodeError as e:
die(f"invalid JSON: {e}")
name = raw.get("name", "") or f"jit-{secrets.token_hex(8)}"
role = raw.get("role", "")
roster = raw.get("roster", "")
shared_task = raw.get("shared_task", "")
protocol = raw.get("protocol", "")
constraints = raw.get("constraints", [])
if not isinstance(constraints, list):
die("constraints must be an array of strings")
legacy = raw.get("prompt", "")
if not role and not legacy:
die("role or prompt required")
# Build identity text.
if role:
parts = ["## Role", role]
if roster:
parts += ["## Roster", roster]
if shared_task:
parts += ["## Shared Task", shared_task]
if protocol:
parts += ["## Coordination Protocol", protocol]
if constraints:
parts += ["## Constraints", "\n".join(f"- {c}" for c in constraints)]
identity = "\n\n".join(parts)
else:
identity = legacy
# Load base config.
try:
with open(BASE_CONFIG) as f:
cfg = json.load(f)
except (OSError, json.JSONDecodeError) as e:
die(f"failed to read base config: {e}")
cfg["prompt"] = ["cat ~/.config/ollie/prompts/SYSTEM_PROMPT.md", f"echo {json.dumps(identity)}"]
# Write JIT config.
out_path = os.path.join(AGENTS_DIR, f"{name}.json")
try:
with open(out_path, "w") as f:
json.dump(cfg, f, indent=2)
except OSError as e:
die(f"failed to write config: {e}")
print(name)
if __name__ == "__main__":
main()