Add sssf skill, installable via the skills CLI
Port the sssf skill from ~/.agents/skills/sssf into this repo so it can be distributed and installed with the skills CLI (skills add INDigitalStudio/skills --skill sssf). - Copy the skill (SKILL.md, cookbooks, references, scripts, templates, and the visualizer app source) into sssf/. - Gitignore build/runtime artifacts: the visualizer's node_modules/ and dist/, Python bytecode, and the machine-specific repos.json. - Make the skill location-independent: install.py now stamps the skill's real path into the stamped justfile's skill_dir (replacing the hardcoded ~/.agents/skills/sssf), so 'just obs' finds the visualizer wherever the CLI installed the skill. - Update cookbooks to use <skill>/scripts/... instead of the hardcoded path, and document the skills CLI install command. - Update the repo README with install instructions.
This commit is contained in:
parent
a42608f602
commit
2cc766aabe
98 changed files with 12508 additions and 0 deletions
119
sssf/scripts/make_adw.py
Normal file
119
sssf/scripts/make_adw.py
Normal file
|
|
@ -0,0 +1,119 @@
|
|||
#!/usr/bin/env -S uv run
|
||||
# /// script
|
||||
# dependencies = []
|
||||
# ///
|
||||
"""make_adw — generate a new one-shot ADW script from agents in the config.
|
||||
|
||||
Usage:
|
||||
uv run <skill>/scripts/make_adw.py --name review_docs --agents scout,builder
|
||||
|
||||
Each named agent becomes one agent phase, chained by envelope. Starter agents
|
||||
map to their concrete output types; unknown agents get GenericOutput (define a
|
||||
concrete type in adw_modules/data_types.py and swap it in).
|
||||
"""
|
||||
|
||||
import argparse
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
OUTPUT_TYPES = {"planner": "PlanOutput", "builder": "BuildOutput",
|
||||
"scout": "ScoutOutput",
|
||||
"reviewer": "ReviewOutput", "documenter": "DocumentOutput"}
|
||||
|
||||
HEADER = '''#!/usr/bin/env -S uv run
|
||||
# /// script
|
||||
# dependencies = ["pydantic", "python-dotenv", "pyyaml"]
|
||||
# ///
|
||||
"""ADW {title} — generated by make_adw.
|
||||
|
||||
Usage:
|
||||
uv run adws/adw_{name}.py "<prompt or path/to/prompt.md>" [--config adws/adw_sssf_config/sssf.config.yaml] [--adw-id a1b2c3d4]
|
||||
|
||||
Phases: engineer(request) -> {chain}
|
||||
"""
|
||||
|
||||
import argparse
|
||||
import sys
|
||||
|
||||
from adw_modules import agents, gates, session, utils
|
||||
from adw_modules.data_types import AgentCall, PhaseParams, {imports}
|
||||
|
||||
REQUIRED_AGENTS = {agents_list}
|
||||
|
||||
|
||||
def main(prompt: str, config: str = "adws/adw_sssf_config/sssf.config.yaml", adw_id: str | None = None) -> int:
|
||||
cfg = agents.load_config(config)
|
||||
agents.validate(cfg, REQUIRED_AGENTS)
|
||||
run = session.ensure(cfg, adw_id)
|
||||
|
||||
with run.phase(PhaseParams(name="request", kind="engineer", owner=run.engineer,
|
||||
description="Capture the incoming ask")) as ph:
|
||||
ph.log(input=prompt)
|
||||
|
||||
previous = None
|
||||
{phases}
|
||||
return 0 if run.succeeded else 1
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
parser = argparse.ArgumentParser(description=__doc__)
|
||||
parser.add_argument("prompt", help="inline text or a path to a prompt file")
|
||||
parser.add_argument("--config", default="adws/adw_sssf_config/sssf.config.yaml")
|
||||
parser.add_argument("--adw-id", default=None, help="join or pin an existing session")
|
||||
args = parser.parse_args()
|
||||
sys.exit(main(utils.resolve_prompt(args.prompt), args.config, args.adw_id))
|
||||
'''
|
||||
|
||||
PHASE = ''' # TODO: replace this description — say what THIS phase does and why.
|
||||
with run.phase(PhaseParams(name="{name}", kind="agent", owner="{agent}",
|
||||
description="Run {agent} over the request and hand its envelope on")) as ph:
|
||||
previous = ph.call(AgentCall(output_type={output_type}, prompt=prompt,
|
||||
previous=previous,
|
||||
gates=[gates.artifacts_exist]))
|
||||
'''
|
||||
|
||||
|
||||
def main() -> int:
|
||||
parser = argparse.ArgumentParser(description=__doc__)
|
||||
parser.add_argument("--name", required=True, help="snake_case adw name")
|
||||
parser.add_argument("--agents", required=True, help="comma-separated agent names, in order")
|
||||
parser.add_argument("--force", action="store_true")
|
||||
args = parser.parse_args()
|
||||
|
||||
agent_names = [a.strip() for a in args.agents.split(",") if a.strip()]
|
||||
if not agent_names:
|
||||
print("no agents given")
|
||||
return 1
|
||||
|
||||
types = [OUTPUT_TYPES.get(a, "GenericOutput") for a in agent_names]
|
||||
seen: dict[str, int] = {}
|
||||
phases = []
|
||||
for agent, output_type in zip(agent_names, types):
|
||||
seen[agent] = seen.get(agent, 0) + 1
|
||||
phase_name = agent if seen[agent] == 1 else f"{agent}_{seen[agent]}"
|
||||
phases.append(PHASE.format(name=phase_name, agent=agent, output_type=output_type))
|
||||
|
||||
body = HEADER.format(
|
||||
title=args.name.replace("_", " ").title(),
|
||||
name=args.name,
|
||||
chain=" -> ".join(agent_names),
|
||||
imports=", ".join(sorted(set(types))),
|
||||
agents_list=repr(sorted(set(agent_names))),
|
||||
phases="\n".join(phases),
|
||||
)
|
||||
|
||||
dest = Path.cwd() / "adws" / f"adw_{args.name}.py"
|
||||
if dest.exists() and not args.force:
|
||||
print(f"{dest} already exists — use --force to overwrite")
|
||||
return 1
|
||||
dest.parent.mkdir(parents=True, exist_ok=True)
|
||||
dest.write_text(body)
|
||||
print(f"wrote {dest}")
|
||||
print("next: replace each phase description — a generated one says nothing, "
|
||||
"and the description is the only intent the trace ever shows")
|
||||
print(f"run: uv run adws/adw_{args.name}.py \"your request\"")
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(main())
|
||||
Loading…
Add table
Add a link
Reference in a new issue