Skip to content

Commit f98ca8a

Browse files
authored
Add agent script to update a DocGen instance with json output. (#162)
1 parent 77c493a commit f98ca8a

File tree

4 files changed

+129
-20
lines changed

4 files changed

+129
-20
lines changed

aws_doc_sdk_examples_tools/agent/README.md

Lines changed: 32 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
11
# Ailly Prompt Workflow
22

3-
This project provides two scripts to **generate**, **run**, and **parse** [Ailly](https://www.npmjs.com/package/@ailly/cli) prompts based on your AWS DocGen snippets.
3+
This project provides three scripts to **generate** Ailly prompts, **run** them, **parse** the results, and **update** a DocGen instance.
44

55
## Overview
66

77
1. **Generate** Ailly prompts from DocGen snippets (`make_prompts.py`).
88
2. **Run** the Ailly CLI on the generated prompts (`npx @ailly/cli`).
9-
3. **Parse** the Ailly outputs back into structured JSON (`parse_json_files.py`).
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`).
1011

1112
---
1213

@@ -33,15 +34,11 @@ python make_prompts.py \
3334
- `--system-prompts`: One or more system prompts, either as strings or file paths.
3435
- `--out`: (Optional) Output directory. Defaults to `.ailly_prompts`.
3536

36-
This will:
37-
- Create Markdown files for each snippet.
38-
- Create a `.aillyrc` file with the provided system prompts.
39-
4037
---
4138

4239
## Step 2: Run Ailly CLI
4340

44-
Run Ailly on the generated prompts. From inside the .ailly_prompts directory:
41+
Run Ailly on the generated prompts:
4542

4643
```bash
4744
npx @ailly/cli --root .ailly_prompts
@@ -53,15 +50,33 @@ This will create `{file}.ailly.md` output files in the `.ailly_prompts` director
5350

5451
## Step 3: Parse Ailly output
5552

56-
After Ailly has generated response files (`*.ailly.md`), parse them into JSON objects using `parse_json_files.py`:
53+
Parse the `{name}.ailly.md` files into JSON using `parse_json_files.py`:
54+
55+
```bash
56+
python parse_json_files.py .ailly_prompts/*.ailly.md --out example_updates.json
57+
```
58+
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`.
62+
63+
---
64+
65+
## Step 4: Update DocGen with Ailly results
66+
67+
Use `update_doc_gen.py` to load the parsed data back into your `DocGen` project:
5768

5869
```bash
59-
python parse_json_files.py .ailly_prompts/*.ailly.md --out output.json
70+
python update_doc_gen.py \
71+
--doc-gen-root /path/to/your/docgen/project \
72+
--updates-path example_updates.json
6073
```
6174

6275
**Arguments:**
63-
- Positional: List of files to parse (you can use a glob like `*.ailly.md`).
64-
- `--out`: (Optional) Output file path for the resulting JSON array. Defaults to `out.json`.
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`).
78+
79+
This will update the `title`, `title_abbrev`, and `synopsis` fields in the corresponding DocGen examples.
6580

6681
---
6782

@@ -78,5 +93,10 @@ python make_prompts.py \
7893
npx @ailly/cli --root .ailly_prompts
7994

8095
# Step 3: Parse results
81-
python parse_json_files.py .ailly_prompts/*.ailly.md --out results.json
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
82102
```

aws_doc_sdk_examples_tools/agent/make_prompts.py

Lines changed: 23 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -20,12 +20,23 @@ def make_doc_gen(root: Path) -> DocGen:
2020
return doc_gen
2121

2222

23-
def write_prompts(snippets: Dict[str, Snippet], out: Path) -> None:
24-
"""Write each snippet's code into a separate Markdown file."""
23+
def write_prompts(doc_gen: DocGen, out: Path) -> None:
2524
out.mkdir(parents=True, exist_ok=True)
26-
for snippet_id, snippet in snippets.items():
27-
snippet_path = out / f"{snippet_id}.md"
28-
snippet_path.write_text(snippet.code, encoding="utf-8")
25+
examples = doc_gen.examples
26+
snippets = doc_gen.snippets
27+
for example_id, example in examples.items():
28+
# Postfix with `.md` so Ailly will pick it up.
29+
prompt_path = out / f"{example_id}.md"
30+
# This assumes we're running DocGen specifically on AWSIAMPolicyExampleReservoir.
31+
snippet_key = (
32+
example.languages["IAMPolicyGrammar"]
33+
.versions[0]
34+
.excerpts[0]
35+
.snippet_files[0]
36+
.replace("/", ".")
37+
)
38+
snippet = snippets[snippet_key]
39+
prompt_path.write_text(snippet.code, encoding="utf-8")
2940

3041

3142
def setup_ailly(system_prompts: List[str], out: Path) -> None:
@@ -54,15 +65,20 @@ def parse_prompts_arg(values: List[str]) -> List[str]:
5465
return prompts
5566

5667

68+
def validate_root_path(doc_gen_root: Path):
69+
assert "AWSIAMPolicyExampleReservoir" in str(doc_gen_root)
70+
assert doc_gen_root.is_dir()
71+
72+
5773
def main(
5874
doc_gen_root: Path, system_prompts: List[str], out: str = ".ailly_prompts"
5975
) -> None:
6076
"""Generate prompts and configuration files for Ailly."""
6177
out_path = Path(out)
6278
setup_ailly(system_prompts, out_path)
63-
79+
validate_root_path(doc_gen_root)
6480
doc_gen = make_doc_gen(doc_gen_root)
65-
write_prompts(doc_gen.snippets, out_path)
81+
write_prompts(doc_gen, out_path)
6682

6783

6884
if __name__ == "__main__":

aws_doc_sdk_examples_tools/agent/parse_json_files.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ def process_files(file_paths: List[str]) -> Dict[str, Dict]:
4141
content = f.read()
4242
json_data = extract_json_from_text(content)
4343
if json_data is not None:
44-
results[basename(path)] = json_data
44+
results[basename(path).replace(".md.ailly.md", "")] = json_data
4545
else:
4646
logger.warning(f"No valid JSON object found in file: {f.name}")
4747
except Exception as e:
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
import argparse
2+
import json
3+
import logging
4+
from pathlib import Path
5+
from typing import Iterable
6+
7+
from aws_doc_sdk_examples_tools.doc_gen import DocGen, Example
8+
9+
# Setup logging
10+
logging.basicConfig(level=logging.INFO)
11+
logger = logging.getLogger(__name__)
12+
13+
14+
def examples_from_updates(updates_path: Path) -> Iterable[Example]:
15+
updates = json.loads(updates_path.read_text())
16+
examples = [
17+
Example(
18+
id=id,
19+
file=None,
20+
languages={},
21+
title=update.get("title"),
22+
title_abbrev=update.get("title_abbrev"),
23+
synopsis=update.get("synopsis"),
24+
)
25+
for id, update in updates.items()
26+
]
27+
return examples
28+
29+
30+
def update_examples(doc_gen: DocGen, examples: Iterable[Example]) -> None:
31+
for example in examples:
32+
if doc_gen_example := doc_gen.examples.get(example.id):
33+
doc_gen_example.title = example.title
34+
doc_gen_example.title_abbrev = example.title_abbrev
35+
doc_gen_example.synopsis = example.synopsis
36+
else:
37+
logger.warning(f"Could not find example with id: {example.id}")
38+
39+
40+
def main(doc_gen_root: Path, updates_path: Path) -> None:
41+
doc_gen = DocGen.from_root(doc_gen_root)
42+
examples = examples_from_updates(updates_path)
43+
update_examples(doc_gen, examples)
44+
print(
45+
[
46+
{
47+
"title": ex.title,
48+
"title_abbrev": ex.title_abbrev,
49+
"synopsis": ex.synopsis,
50+
}
51+
for id, ex in doc_gen.examples.items()
52+
]
53+
)
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)

0 commit comments

Comments
 (0)