Skip to content

Commit c3aac17

Browse files
authored
Add runner for iam update agent (#163)
1 parent f98ca8a commit c3aac17

File tree

6 files changed

+96
-155
lines changed

6 files changed

+96
-155
lines changed
Lines changed: 42 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -1,102 +1,74 @@
11
# Ailly Prompt Workflow
22

3-
This project provides three scripts to **generate** Ailly prompts, **run** them, **parse** the results, and **update** a DocGen instance.
4-
5-
## Overview
6-
7-
1. **Generate** Ailly prompts from DocGen snippets (`make_prompts.py`).
8-
2. **Run** the Ailly CLI on the generated prompts (`npx @ailly/cli`).
9-
3. **Parse** the Ailly outputs into structured JSON (`parse_json_files.py`).
10-
4. **Update** your DocGen project with the parsed results (`update_doc_gen.py`).
11-
12-
---
13-
14-
## Prerequisites
15-
16-
- Python 3.8+
17-
- Node.js & npm (for `npx`)
3+
This project automates the process of generating, running, parsing, and applying [Ailly](https://www.npmjs.com/package/@ailly/cli) prompt outputs to an AWS DocGen project. It combines all steps into one streamlined command using a single Python script.
184

195
---
206

21-
## Step 1: Generate Ailly prompts
22-
23-
Use `make_prompts.py` to create a directory of Markdown files and a `.aillyrc` configuration file.
7+
## 📦 Overview
248

25-
```bash
26-
python make_prompts.py \
27-
--doc-gen-root /path/to/your/docgen/project \
28-
--system-prompts "You are a helpful assistant..." \
29-
--out .ailly_prompts
30-
```
9+
This tool:
10+
1. **Generates** Ailly prompts from DocGen snippets.
11+
2. **Runs** Ailly CLI to get enhanced metadata.
12+
3. **Parses** Ailly responses into structured JSON.
13+
4. **Updates** your DocGen examples with the new metadata.
3114

32-
**Arguments:**
33-
- `--doc-gen-root`: Path to your DocGen project root.
34-
- `--system-prompts`: One or more system prompts, either as strings or file paths.
35-
- `--out`: (Optional) Output directory. Defaults to `.ailly_prompts`.
15+
All of this is done with one command.
3616

3717
---
3818

39-
## Step 2: Run Ailly CLI
19+
## ✅ Prerequisites
4020

41-
Run Ailly on the generated prompts:
42-
43-
```bash
44-
npx @ailly/cli --root .ailly_prompts
45-
```
46-
47-
This will create `{file}.ailly.md` output files in the `.ailly_prompts` directory (or whatever output directory you specified).
21+
- Python 3.8+
22+
- Node.js and npm (for `npx`)
23+
- A DocGen project directory
4824

4925
---
5026

51-
## Step 3: Parse Ailly output
27+
## 🚀 Usage
5228

53-
Parse the `{name}.ailly.md` files into JSON using `parse_json_files.py`:
29+
From your project root, run:
5430

5531
```bash
56-
python parse_json_files.py .ailly_prompts/*.ailly.md --out example_updates.json
32+
python -m aws_doc_sdk_examples_tools.agent.bin.main \
33+
/path/to/your/docgen/project \
34+
--system-prompts path/to/system_prompt.txt
5735
```
5836

59-
**Arguments:**
60-
- Positional: List of files to parse (e.g., `*.ailly.md`).
61-
- `--out`: (Optional) Path for the JSON output. Defaults to `out.json`.
37+
### 🔧 Arguments
38+
39+
Run `python -m aws_doc_sdk_examples_tools.agent.bin.main --help` for more info.
6240

6341
---
6442

65-
## Step 4: Update DocGen with Ailly results
43+
## 🗂 What This Does
6644

67-
Use `update_doc_gen.py` to load the parsed data back into your `DocGen` project:
45+
Under the hood, this script:
6846

69-
```bash
70-
python update_doc_gen.py \
71-
--doc-gen-root /path/to/your/docgen/project \
72-
--updates-path example_updates.json
73-
```
47+
1. Creates a directory `.ailly_iam_policy` containing:
48+
- One Markdown file per snippet.
49+
- A `.aillyrc` configuration file.
7450

75-
**Arguments:**
76-
- `--doc-gen-root`: Path to the root of your DocGen project.
77-
- `--updates-path`: JSON file generated in Step 3 (default: `example_updates.json`).
51+
2. Runs `npx @ailly/cli` to generate `.ailly.md` outputs.
7852

79-
This will update the `title`, `title_abbrev`, and `synopsis` fields in the corresponding DocGen examples.
53+
3. Parses the Ailly `.ailly.md` files into a single `iam_updates.json` file.
54+
55+
4. Updates each matching `Example` in the DocGen instance with:
56+
- `title`
57+
- `title_abbrev`
58+
- `synopsis`
8059

8160
---
8261

83-
## Example Full Workflow
62+
## 💡 Example
8463

8564
```bash
86-
# Step 1: Generate prompts
87-
python make_prompts.py \
88-
--doc-gen-root ~/projects/aws-docgen-root \
89-
--system-prompts system_prompt.txt \
90-
--out .ailly_prompts
91-
92-
# Step 2: Run Ailly
93-
npx @ailly/cli --root .ailly_prompts
94-
95-
# Step 3: Parse results
96-
python parse_json_files.py .ailly_prompts/*.ailly.md --out example_updates.json
97-
98-
# Step 4: Update DocGen
99-
python update_doc_gen.py \
100-
--doc-gen-root ~/projects/aws-docgen-root \
101-
--updates-path example_updates.json
65+
python -m aws_doc_sdk_examples_tools.agent.bin.main \
66+
~/projects/AWSIAMPolicyExampleReservoir \
67+
--system-prompts prompts/system_prompt.txt
10268
```
69+
70+
This will:
71+
- Write prompts and config to `.ailly_iam_policy/`
72+
- Run Ailly and capture results
73+
- Parse and save output as `.ailly_iam_policy/iam_updates.json`
74+
- Apply updates to your DocGen examples
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
from pathlib import Path
2+
from subprocess import run
3+
from typing import List
4+
5+
import typer
6+
7+
from aws_doc_sdk_examples_tools.agent.make_prompts import main as make_prompts
8+
from aws_doc_sdk_examples_tools.agent.parse_json_files import main as parse_json_files
9+
from aws_doc_sdk_examples_tools.agent.update_doc_gen import main as update_doc_gen
10+
11+
app = typer.Typer()
12+
13+
AILLY_DIR = ".ailly_iam_policy"
14+
AILLY_DIR_PATH = Path(AILLY_DIR)
15+
IAM_UPDATES_PATH = AILLY_DIR_PATH / "iam_updates.json"
16+
17+
18+
def get_ailly_files(dir: Path) -> List[Path]:
19+
return [
20+
file
21+
for file in dir.iterdir()
22+
if file.is_file() and file.name.endswith(".ailly.md")
23+
]
24+
25+
26+
@app.command()
27+
def update(iam_tributary_root: str, system_prompts: List[str] = []) -> None:
28+
doc_gen_root = Path(iam_tributary_root)
29+
make_prompts(
30+
doc_gen_root=doc_gen_root, system_prompts=system_prompts, out=AILLY_DIR_PATH
31+
)
32+
run(["npx", "@ailly/cli", "--root", AILLY_DIR])
33+
file_paths = get_ailly_files(AILLY_DIR_PATH)
34+
parse_json_files(file_paths=file_paths, out=IAM_UPDATES_PATH)
35+
update_doc_gen(doc_gen_root=doc_gen_root, iam_updates_path=IAM_UPDATES_PATH)
36+
37+
38+
if __name__ == "__main__":
39+
app()

aws_doc_sdk_examples_tools/agent/make_prompts.py

Lines changed: 6 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,9 @@
11
#!/usr/bin/env python
22

3-
import argparse
43
import logging
54
import os
65
from pathlib import Path
7-
from typing import Dict, List
6+
from typing import List
87

98
from aws_doc_sdk_examples_tools.doc_gen import DocGen, Snippet
109

@@ -53,7 +52,7 @@ def setup_ailly(system_prompts: List[str], out: Path) -> None:
5352
aillyrc_path.write_text(content, encoding="utf-8")
5453

5554

56-
def parse_prompts_arg(values: List[str]) -> List[str]:
55+
def read_system_prompts(values: List[str]) -> List[str]:
5756
"""Parse system prompts from a list of strings or file paths."""
5857
prompts = []
5958
for value in values:
@@ -70,38 +69,10 @@ def validate_root_path(doc_gen_root: Path):
7069
assert doc_gen_root.is_dir()
7170

7271

73-
def main(
74-
doc_gen_root: Path, system_prompts: List[str], out: str = ".ailly_prompts"
75-
) -> None:
72+
def main(doc_gen_root: Path, system_prompts: List[str], out: Path) -> None:
7673
"""Generate prompts and configuration files for Ailly."""
77-
out_path = Path(out)
78-
setup_ailly(system_prompts, out_path)
74+
system_prompts = read_system_prompts(system_prompts)
75+
setup_ailly(system_prompts, out)
7976
validate_root_path(doc_gen_root)
8077
doc_gen = make_doc_gen(doc_gen_root)
81-
write_prompts(doc_gen, out_path)
82-
83-
84-
if __name__ == "__main__":
85-
parser = argparse.ArgumentParser(
86-
description="Write Ailly prompts for DocGen snippets and parse the results."
87-
)
88-
parser.add_argument(
89-
"--doc-gen-root", required=True, help="Path to a DocGen ready project."
90-
)
91-
parser.add_argument(
92-
"--system-prompts",
93-
nargs="+",
94-
required=True,
95-
help="List of prompt strings or file paths to store in a .aillyrc file.",
96-
)
97-
parser.add_argument(
98-
"--out",
99-
default=".ailly_prompts",
100-
help="Directory where Ailly prompt files will be written. Defaults to '.ailly_prompts'.",
101-
)
102-
103-
args = parser.parse_args()
104-
105-
doc_gen_root = Path(args.doc_gen_root)
106-
system_prompts = parse_prompts_arg(args.system_prompts)
107-
main(doc_gen_root, system_prompts, out=args.out)
78+
write_prompts(doc_gen, out)

aws_doc_sdk_examples_tools/agent/parse_json_files.py

Lines changed: 5 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
import argparse
21
import json
32
import logging
43
from os.path import basename
@@ -33,17 +32,16 @@ def extract_json_from_text(text: str) -> Optional[Dict]:
3332
return None
3433

3534

36-
def process_files(file_paths: List[str]) -> Dict[str, Dict]:
35+
def process_files(file_paths: List[Path]) -> Dict[str, Dict]:
3736
results = {}
3837
for path in file_paths:
3938
try:
40-
with open(path, "r", encoding="utf-8") as f:
41-
content = f.read()
39+
content = path.read_text()
4240
json_data = extract_json_from_text(content)
4341
if json_data is not None:
4442
results[basename(path).replace(".md.ailly.md", "")] = json_data
4543
else:
46-
logger.warning(f"No valid JSON object found in file: {f.name}")
44+
logger.warning(f"No valid JSON object found in file: {path.name}")
4745
except Exception as e:
4846
logger.warning(f"Error processing file {path}: {e}")
4947
return results
@@ -53,25 +51,6 @@ def write_objects(object: Dict, out: Path):
5351
out.write_text(json.dumps(object, indent=2))
5452

5553

56-
def main():
57-
parser = argparse.ArgumentParser(
58-
description="Extract JSON objects from one or more text files."
59-
)
60-
61-
parser.add_argument("files", nargs="+", help="List of files to process")
62-
63-
parser.add_argument(
64-
"--out",
65-
default="out.json",
66-
help="File path where the resultant json will be written.",
67-
)
68-
69-
args = parser.parse_args()
70-
71-
json_objects = process_files(args.files)
72-
out = Path(args.out)
54+
def main(file_paths: List[Path], out: Path):
55+
json_objects = process_files(file_paths)
7356
write_objects(json_objects, out)
74-
75-
76-
if __name__ == "__main__":
77-
main()

aws_doc_sdk_examples_tools/agent/update_doc_gen.py

Lines changed: 3 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
import argparse
21
import json
32
import logging
43
from pathlib import Path
@@ -37,9 +36,9 @@ def update_examples(doc_gen: DocGen, examples: Iterable[Example]) -> None:
3736
logger.warning(f"Could not find example with id: {example.id}")
3837

3938

40-
def main(doc_gen_root: Path, updates_path: Path) -> None:
39+
def main(doc_gen_root: Path, iam_updates_path: Path) -> None:
4140
doc_gen = DocGen.from_root(doc_gen_root)
42-
examples = examples_from_updates(updates_path)
41+
examples = examples_from_updates(iam_updates_path)
4342
update_examples(doc_gen, examples)
4443
print(
4544
[
@@ -48,26 +47,6 @@ def main(doc_gen_root: Path, updates_path: Path) -> None:
4847
"title_abbrev": ex.title_abbrev,
4948
"synopsis": ex.synopsis,
5049
}
51-
for id, ex in doc_gen.examples.items()
50+
for _, ex in doc_gen.examples.items()
5251
]
5352
)
54-
55-
56-
if __name__ == "__main__":
57-
parser = argparse.ArgumentParser(
58-
description="Apply a list of example updates to a doc gen instance"
59-
)
60-
parser.add_argument(
61-
"--doc-gen-root", required=True, help="Path to a DocGen ready project."
62-
)
63-
parser.add_argument(
64-
"--updates-path",
65-
default="example_updates.json",
66-
help="JSON file containing a list of example updates.",
67-
)
68-
69-
args = parser.parse_args()
70-
71-
doc_gen_root = Path(args.doc_gen_root)
72-
updates_path = Path(args.updates_path)
73-
main(doc_gen_root, updates_path)

requirements.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,3 +8,4 @@ PyYAML==6.0.1
88
requests==2.32.0
99
types-PyYAML==6.0.12.12
1010
yamale==4.0.4
11+
typer==0.15.3

0 commit comments

Comments
 (0)