agents: Add skill for reading LE audio profiles specifications Change-Id: I0eb7ee7b3b04dea6ebfd38844790bde31e64ec5e Reviewed-on: https://bluetooth-review.googlesource.com/c/bluetooth/+/2901
diff --git a/.agents/skills/le_profiles_specifications/SKILL.md b/.agents/skills/le_profiles_specifications/SKILL.md new file mode 100644 index 0000000..03ac327 --- /dev/null +++ b/.agents/skills/le_profiles_specifications/SKILL.md
@@ -0,0 +1,18 @@ +--- +name: LE Audio Profiles Specifications +description: Caches and provides access to LE Audio profile specifications. +--- + +# LE Audio Profiles Specifications + +This resource maintains a local cache of specifications related to LE Audio profiles and services. + +## Structure + +The specifications are stored in the `specifications/` directory in this skill folder. +You can search them directly using `grep_search` or read them with `view_file`. + +## Management + +To refresh or download the specifications, run: +`python3 .agents/skills/le_profiles_specifications/scripts/downloader.py`
diff --git a/.agents/skills/le_profiles_specifications/scripts/downloader.py b/.agents/skills/le_profiles_specifications/scripts/downloader.py new file mode 100644 index 0000000..a50acec --- /dev/null +++ b/.agents/skills/le_profiles_specifications/scripts/downloader.py
@@ -0,0 +1,111 @@ +import os +from urllib.request import urlopen, Request +from urllib.error import URLError +from bs4 import BeautifulSoup + +SPEC_DIR = os.path.join( + os.path.dirname(os.path.dirname(os.path.abspath(__file__))), + "specifications", +) + +# List of specifications to download +SPECS = [ + { + "name": "BAP_v1.0.2", + "url": "https://www.bluetooth.com/wp-content/uploads/Files/Specification/HTML/BAP_v1.0.2/out/en/index-en.html", + }, + { + "name": "CAP_v1.0.1", + "url": "https://www.bluetooth.com/wp-content/uploads/Files/Specification/HTML/CAP_v1.0.1/out/en/index-en.html", + }, + { + "name": "TMAP_v1.0.1", + "url": "https://www.bluetooth.com/wp-content/uploads/Files/Specification/HTML/TMAP_v1.0.1/out/en/index-en.html", + }, + { + "name": "HAP_v1.0.1", + "url": "https://www.bluetooth.com/wp-content/uploads/Files/Specification/HTML/HAP_v1.0.1/out/en/index-en.html", + }, + { + "name": "PBP_v1.0.1", + "url": "https://www.bluetooth.com/wp-content/uploads/Files/Specification/HTML/PBP_v1.0.1/out/en/index-en.html", + }, + { + "name": "MCP_v1.0", + "url": "https://www.bluetooth.com/wp-content/uploads/Files/Specification/HTML/28982-MCP-html5/out/en/index-en.html", + }, + { + "name": "CCP_v1.0", + "url": "https://www.bluetooth.com/wp-content/uploads/Files/Specification/HTML/26587-CCP-html5/out/en/index-en.html", + }, + { + "name": "MICP_v1.0", + "url": "https://www.bluetooth.com/wp-content/uploads/Files/Specification/HTML/21264-MICP-html5/out/en/index-en.html", + }, + { + "name": "VCP_v1.0", + "url": "https://www.bluetooth.com/wp-content/uploads/Files/Specification/HTML/76878-VCP-html5/out/en/index-en.html", + }, + { + "name": "ASCS_v1.0.1", + "url": "https://www.bluetooth.com/wp-content/uploads/Files/Specification/HTML/ASCS_v1.0.1/out/en/index-en.html", + }, + { + "name": "PACS_v1.0.2", + "url": "https://www.bluetooth.com/wp-content/uploads/Files/Specification/HTML/PACS_v1.0.2/out/en/index-en.html", + }, + { + "name": "CSIS_v1.0", + "url": "https://www.bluetooth.com/wp-content/uploads/Files/Specification/HTML/28085-CSIS-html5/out/en/index-en.html", + }, + { + "name": "CSIP_v1.0", + "url": "https://www.bluetooth.com/wp-content/uploads/Files/Specification/HTML/27407-CSIP-html5/out/en/index-en.html", + }, + { + "name": "BASS_v1.0.1", + "url": "https://www.bluetooth.com/wp-content/uploads/Files/Specification/HTML/BASS_v1.0.1/out/en/index-en.html", + }, + { + "name": "AICS_v1.0.1", + "url": "https://www.bluetooth.com/wp-content/uploads/Files/Specification/HTML/AICS_v1.0.1/out/en/index-en.html", + }, +] + +def download_spec(name, url): + print(f"Downloading {name} from {url}...") + headers = {'User-Agent': 'Mozilla/5.0'} + try: + req = Request(url, headers=headers) + with urlopen(req, timeout=30) as response: + html_content = response.read() + + # Create spec dir if not exists + os.makedirs(SPEC_DIR, exist_ok=True) + + # Save HTML + html_path = os.path.join(SPEC_DIR, f"{name}.html") + with open(html_path, 'wb') as f: + f.write(html_content) + print(f"Saved HTML to {html_path}") + + # Save Text/Markdown for searching + soup = BeautifulSoup(html_content, 'html.parser') + text_content = soup.get_text(separator='\n', strip=True) + + md_path = os.path.join(SPEC_DIR, f"{name}.md") + with open(md_path, 'w', encoding='utf-8') as f: + f.write(text_content) + print(f"Saved Markdown to {md_path}") + + except URLError as e: + print(f"Error downloading {name}: {e}") + except Exception as e: + print(f"An error occurred: {e}") + +def main(): + for spec in SPECS: + download_spec(spec["name"], spec["url"]) + +if __name__ == "__main__": + main()
diff --git a/.gitignore b/.gitignore index b45d8bf..b4147a0 100644 --- a/.gitignore +++ b/.gitignore
@@ -5,4 +5,4 @@ infra/packages # Specification files. -.agents/skills/core_specification/specifications +.agents/skills/*/specifications