From 442c3b0d668739f155a7303507c7552ffddc29d6 Mon Sep 17 00:00:00 2001 From: Nicholas Clegg Date: Sun, 23 Nov 2025 16:23:21 -0500 Subject: [PATCH 1/3] Autogenerate python api docs --- .github/workflows/build-test.yaml | 10 +- .gitignore | 1 + docs/api-reference/.gitkeep | 0 docs/api-reference/agent.md | 29 ------ docs/api-reference/event-loop.md | 10 -- docs/api-reference/experimental.md | 11 --- docs/api-reference/handlers.md | 7 -- docs/api-reference/hooks.md | 10 -- docs/api-reference/interrupt.md | 3 - docs/api-reference/models.md | 34 ------- docs/api-reference/multiagent.md | 23 ----- docs/api-reference/session.md | 20 ---- docs/api-reference/telemetry.md | 16 --- docs/api-reference/tools.md | 45 --------- docs/api-reference/types.md | 34 ------- docs/user-guide/concepts/agents/agent-loop.md | 2 +- generate_python_api_docs.py | 98 +++++++++++++++++++ mkdocs.yml | 5 +- 18 files changed, 106 insertions(+), 252 deletions(-) create mode 100644 docs/api-reference/.gitkeep delete mode 100644 docs/api-reference/agent.md delete mode 100644 docs/api-reference/event-loop.md delete mode 100644 docs/api-reference/experimental.md delete mode 100644 docs/api-reference/handlers.md delete mode 100644 docs/api-reference/hooks.md delete mode 100644 docs/api-reference/interrupt.md delete mode 100644 docs/api-reference/models.md delete mode 100644 docs/api-reference/multiagent.md delete mode 100644 docs/api-reference/session.md delete mode 100644 docs/api-reference/telemetry.md delete mode 100644 docs/api-reference/tools.md delete mode 100644 docs/api-reference/types.md create mode 100644 generate_python_api_docs.py diff --git a/.github/workflows/build-test.yaml b/.github/workflows/build-test.yaml index 009e6d0d..f0f6a5f4 100644 --- a/.github/workflows/build-test.yaml +++ b/.github/workflows/build-test.yaml @@ -12,7 +12,7 @@ permissions: read-all jobs: build: - name: Build Documentation + name: Build Documentation and Check Links runs-on: ubuntu-latest steps: - name: Checkout code @@ -24,12 +24,6 @@ jobs: run: | mkdocs build - check_links: - name: Check Links - runs-on: ubuntu-latest - - steps: - - uses: actions/checkout@v4 - name: Restore lychee cache uses: actions/cache@v4 with: @@ -41,4 +35,4 @@ jobs: id: lychee uses: lycheeverse/lychee-action@v2 with: - args: "--cache --max-cache-age 1d 'docs/**/*.md'" + args: "--cache --max-cache-age 1d 'docs/**/*.md'" \ No newline at end of file diff --git a/.gitignore b/.gitignore index dd5dfe9f..61c4e1c1 100644 --- a/.gitignore +++ b/.gitignore @@ -9,3 +9,4 @@ __pycache__ .idea .kiro *.egg-info +docs/api-reference \ No newline at end of file diff --git a/docs/api-reference/.gitkeep b/docs/api-reference/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/docs/api-reference/agent.md b/docs/api-reference/agent.md deleted file mode 100644 index 5eccd889..00000000 --- a/docs/api-reference/agent.md +++ /dev/null @@ -1,29 +0,0 @@ -::: strands.agent - options: - heading_level: 1 - members: false -::: strands.agent.agent - options: - heading_level: 2 -::: strands.agent.agent_result - options: - heading_level: 2 -::: strands.agent.conversation_manager - options: - heading_level: 2 - members: false -::: strands.agent.conversation_manager.conversation_manager - options: - heading_level: 3 -::: strands.agent.conversation_manager.null_conversation_manager - options: - heading_level: 3 -::: strands.agent.conversation_manager.sliding_window_conversation_manager - options: - heading_level: 3 -::: strands.agent.conversation_manager.summarizing_conversation_manager - options: - heading_level: 3 -::: strands.agent.state - options: - heading_level: 2 diff --git a/docs/api-reference/event-loop.md b/docs/api-reference/event-loop.md deleted file mode 100644 index 712d9b6f..00000000 --- a/docs/api-reference/event-loop.md +++ /dev/null @@ -1,10 +0,0 @@ -::: strands.event_loop - options: - heading_level: 1 - members: false -::: strands.event_loop.event_loop - options: - heading_level: 2 -::: strands.event_loop.streaming - options: - heading_level: 2 diff --git a/docs/api-reference/experimental.md b/docs/api-reference/experimental.md deleted file mode 100644 index 803dafc7..00000000 --- a/docs/api-reference/experimental.md +++ /dev/null @@ -1,11 +0,0 @@ -::: strands.experimental - options: - heading_level: 1 - members: false -::: strands.experimental.hooks - options: - heading_level: 2 - members: false -::: strands.experimental.hooks.events - options: - heading_level: 3 diff --git a/docs/api-reference/handlers.md b/docs/api-reference/handlers.md deleted file mode 100644 index 1b9694f2..00000000 --- a/docs/api-reference/handlers.md +++ /dev/null @@ -1,7 +0,0 @@ -::: strands.handlers - options: - heading_level: 1 - members: false -::: strands.handlers.callback_handler - options: - heading_level: 2 diff --git a/docs/api-reference/hooks.md b/docs/api-reference/hooks.md deleted file mode 100644 index cf09deef..00000000 --- a/docs/api-reference/hooks.md +++ /dev/null @@ -1,10 +0,0 @@ -::: strands.hooks - options: - heading_level: 1 - members: false -::: strands.hooks.events - options: - heading_level: 2 -::: strands.hooks.registry - options: - heading_level: 2 diff --git a/docs/api-reference/interrupt.md b/docs/api-reference/interrupt.md deleted file mode 100644 index 31e001aa..00000000 --- a/docs/api-reference/interrupt.md +++ /dev/null @@ -1,3 +0,0 @@ -::: strands.interrupt - options: - heading_level: 1 diff --git a/docs/api-reference/models.md b/docs/api-reference/models.md deleted file mode 100644 index a1ac435d..00000000 --- a/docs/api-reference/models.md +++ /dev/null @@ -1,34 +0,0 @@ -::: strands.models - options: - heading_level: 1 - members: false -::: strands.models.model - options: - heading_level: 2 -::: strands.models.bedrock - options: - heading_level: 2 -::: strands.models.anthropic - options: - heading_level: 2 -::: strands.models.gemini - options: - heading_level: 2 -::: strands.models.litellm - options: - heading_level: 2 -::: strands.models.llamaapi - options: - heading_level: 2 -::: strands.models.mistral - options: - heading_level: 2 -::: strands.models.ollama - options: - heading_level: 2 -::: strands.models.openai - options: - heading_level: 2 -::: strands.models.writer - options: - heading_level: 2 diff --git a/docs/api-reference/multiagent.md b/docs/api-reference/multiagent.md deleted file mode 100644 index 72c9491a..00000000 --- a/docs/api-reference/multiagent.md +++ /dev/null @@ -1,23 +0,0 @@ -::: strands.multiagent - options: - heading_level: 1 - members: false -::: strands.multiagent.base - options: - heading_level: 2 -::: strands.multiagent.graph - options: - heading_level: 2 -::: strands.multiagent.swarm - options: - heading_level: 2 -::: strands.multiagent.a2a - options: - heading_level: 2 - members: false -::: strands.multiagent.a2a.executor - options: - heading_level: 3 -::: strands.multiagent.a2a.server - options: - heading_level: 3 diff --git a/docs/api-reference/session.md b/docs/api-reference/session.md deleted file mode 100644 index 2b20a869..00000000 --- a/docs/api-reference/session.md +++ /dev/null @@ -1,20 +0,0 @@ -::: strands.session - options: - heading_level: 1 - members: false -::: strands.session.file_session_manager - options: - heading_level: 2 -::: strands.session.repository_session_manager - options: - heading_level: 2 -::: strands.session.s3_session_manager - options: - heading_level: 2 -::: strands.session.session_manager - options: - heading_level: 2 - members: false -::: strands.session.session_repository - options: - heading_level: 2 diff --git a/docs/api-reference/telemetry.md b/docs/api-reference/telemetry.md deleted file mode 100644 index 4827a0c0..00000000 --- a/docs/api-reference/telemetry.md +++ /dev/null @@ -1,16 +0,0 @@ -::: strands.telemetry - options: - heading_level: 1 - members: false -::: strands.telemetry.config - options: - heading_level: 2 -::: strands.telemetry.metrics - options: - heading_level: 2 -::: strands.telemetry.metrics_constants - options: - heading_level: 2 -::: strands.telemetry.tracer - options: - heading_level: 2 diff --git a/docs/api-reference/tools.md b/docs/api-reference/tools.md deleted file mode 100644 index 2744782f..00000000 --- a/docs/api-reference/tools.md +++ /dev/null @@ -1,45 +0,0 @@ -::: strands.tools - options: - heading_level: 1 - members: false -::: strands.tools.tools - options: - heading_level: 2 -::: strands.tools.decorator - options: - heading_level: 2 -::: strands.tools.loader - options: - heading_level: 2 -::: strands.tools.registry - options: - heading_level: 2 -::: strands.tools.structured_output - options: - heading_level: 2 -::: strands.tools.watcher - options: - heading_level: 2 -::: strands.tools.executors - options: - heading_level: 2 - members: false -::: strands.tools.executors.concurrent - options: - heading_level: 3 -::: strands.tools.executors.sequential - options: - heading_level: 3 -::: strands.tools.mcp - options: - heading_level: 2 - members: false -::: strands.tools.mcp.mcp_agent_tool - options: - heading_level: 3 -::: strands.tools.mcp.mcp_client - options: - heading_level: 3 -::: strands.tools.mcp.mcp_types - options: - heading_level: 3 diff --git a/docs/api-reference/types.md b/docs/api-reference/types.md deleted file mode 100644 index 193fc113..00000000 --- a/docs/api-reference/types.md +++ /dev/null @@ -1,34 +0,0 @@ -::: strands.types - options: - heading_level: 1 - members: false -::: strands.types.content - options: - heading_level: 2 -::: strands.types.event_loop - options: - heading_level: 2 -::: strands.types.exceptions - options: - heading_level: 2 -::: strands.types.guardrails - options: - heading_level: 2 -::: strands.types.interrupt - options: - heading_level: 2 -::: strands.types.media - options: - heading_level: 2 -::: strands.types.session - options: - heading_level: 2 -::: strands.types.streaming - options: - heading_level: 2 -::: strands.types.tools - options: - heading_level: 2 -::: strands.types.traces - options: - heading_level: 2 diff --git a/docs/user-guide/concepts/agents/agent-loop.md b/docs/user-guide/concepts/agents/agent-loop.md index cced63f5..000c6e13 100644 --- a/docs/user-guide/concepts/agents/agent-loop.md +++ b/docs/user-guide/concepts/agents/agent-loop.md @@ -37,7 +37,7 @@ The agent loop consists of several key components working together to create a s ### Event Loop Cycle -The event loop cycle is the central mechanism that orchestrates the flow of information. It's implemented in the [`event_loop_cycle`](../../../api-reference/event-loop.md#strands.event_loop.event_loop.event_loop_cycle) function, which: +The event loop cycle is the central mechanism that orchestrates the flow of information. It's implemented in the [`event_loop_cycle`](../../../api-reference/event_loop.md#strands.event_loop.event_loop.event_loop_cycle) function, which: - Processes messages with the language model - Handles tool execution requests diff --git a/generate_python_api_docs.py b/generate_python_api_docs.py new file mode 100644 index 00000000..897855b8 --- /dev/null +++ b/generate_python_api_docs.py @@ -0,0 +1,98 @@ +import os +import subprocess +import shutil +import importlib +from pathlib import Path +from typing import Any + +def on_pre_build(config): + """Generate API docs before build""" + repo_url = "https://github.com/strands-agents/sdk-python.git" + temp_dir = Path('temp_python_sdk') + sdk_path = temp_dir / 'src/strands' + output_dir = Path('docs/api-reference') + + # Clone repository + try: + subprocess.run(['git', 'clone', repo_url, str(temp_dir)], check=True) + except subprocess.CalledProcessError: + if sdk_path.exists(): + shutil.rmtree(temp_dir, ignore_errors=True) + print("Failed to clone repository") + return + + print("Generating API docs...") + + # Find modules + modules: list[str] = [] + for item in sdk_path.rglob('*.py'): + if item.name.startswith('_'): + continue + rel_path = item.relative_to(sdk_path.parent) + module = str(rel_path.with_suffix('')).replace('/', '.') + + # Only include modules that can be imported + # Otherwise we get an error like: ERROR - mkdocstrings: strands.types.multiagent could not be found + try: + importlib.import_module(module) + modules.append(module) + except ImportError: + continue + + # Group by api reference category + # Each category will have a list of included python modules + categories: dict[str, list[str]] = {} + for module in modules: + parts = module.split('.') + if len(parts) >= 2: + category = parts[1] + if category not in categories: + categories[category] = [] + categories[category].append(module) + + # Generate files + for category, module_list in categories.items(): + content = [] + main_module = f"strands.{category}" + + # Find container modules (modules that have sub-modules but aren't in the list) + container_modules = set() + for module in module_list: + parts = module.split('.') + # Check for potential container modules (3+ parts) + if len(parts) > 2: + for i in range(2, len(parts)): + container = '.'.join(parts[:i+1]) + if container not in module_list and container != main_module: + # Check if this container has multiple sub-modules + sub_modules = [m for m in module_list if m.startswith(container + '.')] + if len(sub_modules) > 1: + container_modules.add(container) + + # Add container modules to the list + module_list.extend(container_modules) + + # Sort to maintain proper order + sorted_modules = sorted(module_list) + + # Always include main module as header, even if not importable + if main_module not in module_list: + sorted_modules.insert(0, main_module) + else: + sorted_modules.remove(main_module) + sorted_modules.insert(0, main_module) + + for module in sorted_modules: + parts = module.split('.') + level = min(len(parts) - 1, 3) + content.append(f"::: {module}") + content.append(" options:") + content.append(f" heading_level: {level}") + # Add members: false for main module and container modules + if module == main_module or module in container_modules: + content.append(" members: false") + with open(output_dir / f"{category}.md", 'w') as f: + f.write('\n'.join(content) + '\n') + + # Clean up cloned repository + shutil.rmtree(temp_dir, ignore_errors=True) \ No newline at end of file diff --git a/mkdocs.yml b/mkdocs.yml index bdc84fd2..5a2e3f7c 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -168,7 +168,7 @@ nav: - Contribute ❤️: https://github.com/strands-agents/sdk-python/blob/main/CONTRIBUTING.md - API Reference: - Agent: api-reference/agent.md - - Event Loop: api-reference/event-loop.md + - Event Loop: api-reference/event_loop.md - Experimental: api-reference/experimental.md - Handlers: api-reference/handlers.md - Hooks: api-reference/hooks.md @@ -212,6 +212,9 @@ plugins: API Reference: - api-reference/*.md +hooks: + - generate_python_api_docs.py + extra: social: - icon: fontawesome/brands/github From fdd7cda77d86e0ef246ff789d10dcac2aeb2aaaa Mon Sep 17 00:00:00 2001 From: Nicholas Clegg Date: Wed, 26 Nov 2025 10:00:14 -0500 Subject: [PATCH 2/3] Address pr comments --- generate_python_api_docs.py | 27 +++++++++++++++------------ 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/generate_python_api_docs.py b/generate_python_api_docs.py index 897855b8..4aca0949 100644 --- a/generate_python_api_docs.py +++ b/generate_python_api_docs.py @@ -5,6 +5,20 @@ from pathlib import Path from typing import Any +def _find_container_modules(module_list: list[str], main_module: str) -> list[str]: + container_modules = set() + for module in module_list: + parts = module.split('.') + # Check for potential container modules (3+ parts) + if len(parts) > 2: + for i in range(2, len(parts)): + container = '.'.join(parts[:i+1]) + if container not in module_list and container != main_module: + # Check if this container has multiple sub-modules + sub_modules = [m for m in module_list if m.startswith(container + '.')] + if len(sub_modules) > 1: + container_modules.add(container) + def on_pre_build(config): """Generate API docs before build""" repo_url = "https://github.com/strands-agents/sdk-python.git" @@ -56,18 +70,7 @@ def on_pre_build(config): main_module = f"strands.{category}" # Find container modules (modules that have sub-modules but aren't in the list) - container_modules = set() - for module in module_list: - parts = module.split('.') - # Check for potential container modules (3+ parts) - if len(parts) > 2: - for i in range(2, len(parts)): - container = '.'.join(parts[:i+1]) - if container not in module_list and container != main_module: - # Check if this container has multiple sub-modules - sub_modules = [m for m in module_list if m.startswith(container + '.')] - if len(sub_modules) > 1: - container_modules.add(container) + container_modules = _find_container_modules(module_list, main_module) # Add container modules to the list module_list.extend(container_modules) From 53e1682b5e965a76eb03e55eb2ec02a12f4b9ab6 Mon Sep 17 00:00:00 2001 From: Nicholas Clegg Date: Wed, 26 Nov 2025 11:42:13 -0500 Subject: [PATCH 3/3] Add missing return --- .gitignore | 3 ++- generate_python_api_docs.py | 3 +++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 61c4e1c1..026e257c 100644 --- a/.gitignore +++ b/.gitignore @@ -9,4 +9,5 @@ __pycache__ .idea .kiro *.egg-info -docs/api-reference \ No newline at end of file +docs/api-reference +temp_python_sdk \ No newline at end of file diff --git a/generate_python_api_docs.py b/generate_python_api_docs.py index 4aca0949..be5036f0 100644 --- a/generate_python_api_docs.py +++ b/generate_python_api_docs.py @@ -18,6 +18,7 @@ def _find_container_modules(module_list: list[str], main_module: str) -> list[st sub_modules = [m for m in module_list if m.startswith(container + '.')] if len(sub_modules) > 1: container_modules.add(container) + return container_modules def on_pre_build(config): """Generate API docs before build""" @@ -25,6 +26,8 @@ def on_pre_build(config): temp_dir = Path('temp_python_sdk') sdk_path = temp_dir / 'src/strands' output_dir = Path('docs/api-reference') + # Clean up cloned repository if it already exists + shutil.rmtree(temp_dir, ignore_errors=True) # Clone repository try: