diff --git a/.github/workflows/pages.yml b/.github/workflows/pages.yml index 44fe9c7f..ceebdbf2 100644 --- a/.github/workflows/pages.yml +++ b/.github/workflows/pages.yml @@ -3,6 +3,14 @@ name: Deploy GitHub Pages on: push: branches: ["main"] + paths: + - "docs/**" + - "mkdocs.yml" + - "src/microbots/MicroBot.py" + - "src/microbots/bot/**" + - "src/microbots/llm/**" + - "src/microbots/environment/**" + - "src/microbots/tools/**" workflow_dispatch: permissions: @@ -29,6 +37,11 @@ jobs: - name: Install Zensical run: pip install zensical + - name: Install mkdocstrings and project + run: | + pip install "mkdocstrings[python]" + pip install -e . + - name: Build site run: zensical build --clean diff --git a/docs/api-docs/bots/index.md b/docs/api-docs/bots/index.md new file mode 100644 index 00000000..67690b5c --- /dev/null +++ b/docs/api-docs/bots/index.md @@ -0,0 +1,17 @@ +# Bots + +This section covers the different types of bots that can be built with Microbots, along with detailed guides and examples for each type. + +All bots extend the core [`MicroBot`](../components/bot.md) class with specialized system prompts, permissions, and tools. + +| Bot | Purpose | Access Level | +|-----|---------|-------------| +| [LogAnalysisBot](log-analysis-bot.md) | Analyze log files and identify root causes | Read-only | +| ReadingBot | Code comprehension and analysis | Read-only | +| WritingBot | Controlled file edits | Read-write (restricted commands) | +| BrowsingBot | Web search and browsing | N/A | +| AgentBoss | Task decomposition and delegation | Read-write | +| CopilotBot | GitHub Copilot SDK wrapper | Configurable | + +!!! note "Auto-generated API references" + The API references on these pages are **auto-generated from source code docstrings**. When the source code changes, the documentation updates automatically on the next build. diff --git a/docs/api-docs/bots/log-analysis-bot.md b/docs/api-docs/bots/log-analysis-bot.md new file mode 100644 index 00000000..cc419c18 --- /dev/null +++ b/docs/api-docs/bots/log-analysis-bot.md @@ -0,0 +1,29 @@ +# LogAnalysisBot + +The `LogAnalysisBot` analyzes log files and identifies root causes of failures. It mounts a code directory as read-only context and copies the target log file into the container for analysis. + +## Quick Example + +```python +from microbots import LogAnalysisBot + +bot = LogAnalysisBot( + model="azure-openai/gpt-4.1", + folder_to_mount="/path/to/source/code", +) + +result = bot.run(file_name="/path/to/error.log") +print(result.status, result.result) +``` + +## How It Works + +1. The source code directory is mounted **read-only** at the sandbox path for context. +2. The log file is **copied** into `/var/log/` inside the container. +3. The bot analyzes the log, cross-references with the source code, and identifies the root cause. + +## API Reference + + + +::: microbots.bot.LogAnalysisBot.LogAnalysisBot diff --git a/docs/api-docs/components/bot.md b/docs/api-docs/components/bot.md new file mode 100644 index 00000000..c1e59cba --- /dev/null +++ b/docs/api-docs/components/bot.md @@ -0,0 +1,59 @@ +# Bot + +The `MicroBot` class is the core autonomous agent. All specialized bots (`ReadingBot`, `WritingBot`, etc.) extend this class. + +You can use `MicroBot` directly for custom bots or subclass it for specialized behavior. + +## Quick Example + +```python +from microbots import MicroBot +from microbots.extras.mount import Mount, MountType, PermissionLabels + +bot = MicroBot( + model="azure-openai/gpt-5-swe-agent", + system_prompt="You are a helpful coding assistant.", + folder_to_mount=Mount( + host_path="code", + sandbox_path="/home/user/code", + mount_type=MountType.MOUNT, + permission=PermissionLabels.READ_ONLY, + ), +) + +result = bot.run(task="Analyze the project structure") +print(result.status, result.result) +``` + +## API Reference + + + +!!! info "Parameters vs Attributes" + **Parameters** are the arguments you pass when creating an instance of a class (e.g., `MicroBot(model=..., system_prompt=...)`). + **Attributes** are the internal variables available on the instance after creation, used by the class during its operation. + +::: microbots.MicroBot.MicroBot + options: + show_source: false + + +::: microbots.MicroBot.BotRunResult + options: + show_source: false + +::: microbots.constants.ModelProvider + options: + show_source: false + +::: microbots.extras.mount.MountType + options: + show_source: false + +::: microbots.extras.mount.Mount + options: + show_source: false + +::: microbots.constants.PermissionLabels + options: + show_source: false diff --git a/docs/api-docs/components/index.md b/docs/api-docs/components/index.md new file mode 100644 index 00000000..ef6b4ac1 --- /dev/null +++ b/docs/api-docs/components/index.md @@ -0,0 +1,10 @@ +# Components + +This section covers the core components of Microbots, providing in-depth explanations and API references for each. + +Microbots is built around these below foundational components: + +- **[Bot](bot.md)** — The core `MicroBot` class that powers all autonomous agents. Every specialized bot extends this base class. + +!!! note "Auto-generated API references" + The API references on these pages are **auto-generated from source code docstrings** using [mkdocstrings](https://mkdocstrings.github.io/). When the source code changes, the documentation updates automatically on the next build. diff --git a/docs/api-docs/overview.md b/docs/api-docs/overview.md new file mode 100644 index 00000000..e29ab041 --- /dev/null +++ b/docs/api-docs/overview.md @@ -0,0 +1,15 @@ +# API Documentation + +This section provides comprehensive API references for Microbots, auto-generated from source code docstrings. When the source code changes, the documentation updates automatically on the next build. + +## Components + +The foundational building blocks of Microbots. + +- **[Bot](components/bot.md)** — The core `MicroBot` class that powers all autonomous agents. Covers the base class, `BotRunResult`, `BotType`, and the agent execution loop. + +## Bots + +Specialized bot implementations, each tailored for a specific use case. + +- **[LogAnalysisBot](bots/log-analysis-bot.md)** — Analyzes log files inside a sandboxed container and identifies root causes by cross-referencing with source code. diff --git a/mkdocs.yml b/mkdocs.yml index e4eca852..078dd53e 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -22,13 +22,38 @@ theme: icon: material/brightness-4 name: Switch to light mode features: - - navigation.instant - - navigation.sections + - navigation.indexes - navigation.top - navigation.tabs - content.code.copy +plugins: + - search + - mkdocstrings: + handlers: + python: + paths: [src] + options: + docstring_style: numpy + show_source: true + show_root_heading: true + show_symbol_type_heading: true + show_symbol_type_toc: true + heading_level: 2 + members_order: source + show_signature_annotations: true + separate_signature: true + merge_init_into_class: true + show_labels: true + show_if_no_docstring: true + group_by_category: false + filters: + - "!^_" + markdown_extensions: + - toc: + permalink: true + toc_depth: 4 - pymdownx.highlight: anchor_linenums: true - pymdownx.superfences @@ -42,6 +67,14 @@ markdown_extensions: nav: - Getting Started: - Home: index.md + - API Documentation: + - Overview: api-docs/overview.md + - Components: + - api-docs/components/index.md + - Bot: api-docs/components/bot.md + - Bots: + - api-docs/bots/index.md + - LogAnalysisBot: api-docs/bots/log-analysis-bot.md - Guides: - CopilotBot: copilot-bot.md - Authentication: authentication.md diff --git a/src/microbots/MicroBot.py b/src/microbots/MicroBot.py index a8c9b7a1..907c0ea2 100644 --- a/src/microbots/MicroBot.py +++ b/src/microbots/MicroBot.py @@ -61,38 +61,46 @@ class BotType(StrEnum): @dataclass class BotRunResult: + """Result of a bot run execution. + + Contains the status, result output, and any error information from a bot's run. + """ + status: bool + """Whether the bot run completed successfully.""" result: str | None + """The output produced by the bot run, or None if no output was generated.""" error: Optional[str] + """Error message if the run failed, or None if successful.""" class MicroBot: - """ - The core Microbot class. + """The core Microbot class. - MicroBot class is the core class representing the autonomous agent. Other bots are extensions of this class. + MicroBot is the core class representing the autonomous agent. Other bots are extensions of this class. If you want to create a custom bot, you can directly use this class or extend it into your own bot class. - Attributes + Parameters ---------- - model : str - The model to use for the bot, in the format /. - bot_type : BotType - The type of bot being created. It's unused. Will be removed soon. - system_prompt : Optional[str] - The system prompt to guide the bot's behavior. - environment : Optional[any] - The execution environment for the bot. If not provided, a default - LocalDockerEnvironment will be created. - additional_tools : Optional[list[ToolAbstract]] - A list of additional tools to install in the bot's environment. - folder_to_mount : Optional[Mount] - A folder to mount into the bot's environment. The bot will be given - access to this folder based on the specified permissions. This will - be the main code folder where the bot will work. Additional folders - can be mounted during the run() method. Refer to `Mount` class - regarding the directory structure and permission details. Defaults - to None. + model : str + The model to use, in the format ``/``. + See [ModelProvider][microbots.constants.ModelProvider] for supported providers. + bot_type : BotType, optional + The type of bot being created. Defaults to ``BotType.CUSTOM_BOT``. + system_prompt : str, optional + The system prompt to guide the bot's behavior. Defaults to None. + environment : any, optional + The execution environment for the bot. If not provided, a default + ``LocalDockerEnvironment`` will be created. + additional_tools : list[ToolAbstract], optional + A list of additional tools to install in the bot's environment. + Defaults to None. + folder_to_mount : Mount, optional + A folder to mount into the bot's environment. See + [Mount][microbots.extras.mount.Mount] for details. Defaults to None. + token_provider : any, optional + A token provider for authentication. Required for Azure OpenAI + with Azure AD auth. Defaults to None. """ def __init__( @@ -105,36 +113,9 @@ def __init__( folder_to_mount: Optional[Mount] = None, token_provider: Optional[any] = None, ): - """ - Init function for MicroBot class. - - Parameters - ---------- - model :str - The model to use for the bot, in the format /. - bot_type :BotType - The type of bot being created. It's unused. Will be removed soon. - system_prompt :Optional[str] - The system prompt to guide the bot's behavior. Defaults to None. - environment :Optional[any] - The execution environment for the bot. If not provided, a default - LocalDockerEnvironment will be created. - additional_tools :Optional[list[ToolAbstract]] - A list of additional tools to install in the bot's environment. - Defaults to None (treated as an empty list). - folder_to_mount :Optional[Mount] - A folder to mount into the bot's environment. The bot will be given - access to this folder based on the specified permissions. This will - be the main code folder where the bot will work. Additional folders - can be mounted using the run() method. Refer to `Mount` class - regarding the directory structure and permission details. Defaults - to None. - - Note: Supports only mount type MountType.MOUNT for now. - """ - - self.folder_to_mount = folder_to_mount + """Create a new MicroBot instance.""" + self.folder_to_mount: Optional[Mount] = folder_to_mount # TODO : Need to check on the purpose of variable `mounted` # 1. If we allow user to mount multiple directories, # we should able to get it as an argument and store them in self.mounted. @@ -142,28 +123,44 @@ def __init__( # # 2. We should let user to mount only one directory. In that case self.mounted may not be required. # Just one self.folder_to_mount and necessary extra mounts at the derived class similar to LogAnalyticsBot. + """A folder to mount into the bot's environment. The bot will be given access to this folder based on the specified permissions. This will be the main code folder where the bot will work. Additional folders can be mounted during the ``run()`` method. Refer to [Mount][microbots.extras.mount.Mount] for directory structure and permission details. Supports only ``MountType.MOUNT`` for now.""" - self.mounted = [] + self.mounted: list[Mount] = [] + """List of all mounted directories in the bot's environment.""" if folder_to_mount is not None: self._validate_folder_to_mount(folder_to_mount) self.mounted.append(folder_to_mount) - self.system_prompt = system_prompt - self.model = model - self.bot_type = bot_type - self.environment = environment - self.additional_tools = additional_tools or [] + self.system_prompt: Optional[str] = system_prompt + """The system prompt to guide the bot's behavior. Defaults to None.""" + self.model: str = model + """The model to use for the bot, in the format ``/``. See [ModelProvider][microbots.constants.ModelProvider] for supported providers.""" + self.bot_type: BotType = bot_type + """The type of bot being created. It's unused. Will be removed soon.""" + self.environment: Optional[any] = environment + """The execution environment for the bot. If not provided, a default ``LocalDockerEnvironment`` will be created.""" + self.additional_tools: list[ToolAbstract] = additional_tools or [] + """A list of additional tools to install in the bot's environment. Defaults to an empty list.""" # TODO: Replace iteration_count and max_iterations with cost management. # Iteration count represents overall LLM interactions including interactions + # done by sub agents. - self.iteration_count = 0 - self.max_iterations = 0 - self.step_count = 0 + self.iteration_count: int = 0 + """Number of LLM interactions so far, including sub-agent interactions.""" + self.max_iterations: int = 0 + """Maximum allowed iterations for the current run.""" + self.step_count: int = 0 + """Number of steps completed in the current run.""" self._validate_model_and_provider(model) - self.model_provider = model.split("/")[0] - self.deployment_name = model.split("/")[1] + self.model_provider: str = model.split("/")[0] + """The LLM provider extracted from the model string. See [ModelProvider][microbots.constants.ModelProvider] for supported values.""" + self.deployment_name: str = model.split("/")[1] + """The model deployment name extracted from the model string.""" + + self.token_provider: Optional[any] = None + """Token provider for Azure AD authentication. If not provided and ``AZURE_AUTH_METHOD`` is set to ``azure_ad``, a default provider using ``DefaultAzureCredential`` will be created automatically.""" # Only auto-create token provider from env for providers that support Azure AD tokens. if token_provider is not None: @@ -202,7 +199,30 @@ def run( max_iterations: int = 20, timeout_in_seconds: int = 200 ) -> BotRunResult: + """Execute a task with the bot. + Parameters + ---------- + task : str + The task to execute. + additional_mounts : Optional[list[Mount]] + Extra mounts to add to the environment. Only ``MountType.COPY`` is + supported. Defaults to None. + max_iterations : int + Maximum number of agent loop iterations. Defaults to 20. + timeout_in_seconds : int + Timeout for the task in seconds. Defaults to 200. + + Returns + ------- + BotRunResult + The result containing status, output, and any errors. + + Raises + ------ + ValueError + If ``max_iterations`` is less than or equal to 0. + """ if max_iterations <= 0: raise ValueError("max_iterations must be greater than 0") @@ -253,7 +273,6 @@ def run( return_value.error = f"Timeout of {timeout} seconds reached" return return_value - logger.info("%s Step-%d %s", "-" * 20, self.step_count, "-" * 20) if llm_response.thoughts: logger.info( diff --git a/src/microbots/bot/LogAnalysisBot.py b/src/microbots/bot/LogAnalysisBot.py index b2c682b1..e8b133cb 100644 --- a/src/microbots/bot/LogAnalysisBot.py +++ b/src/microbots/bot/LogAnalysisBot.py @@ -3,14 +3,39 @@ from typing import Optional from microbots.constants import DOCKER_WORKING_DIR, LOG_FILE_DIR, PermissionLabels +from microbots.extras.mount import Mount, MountType from microbots.MicroBot import BotType, MicroBot, system_prompt_common from microbots.tools.tool import ToolAbstract -from microbots.extras.mount import Mount, MountType logger = logging.getLogger(__name__) class LogAnalysisBot(MicroBot): + """A specialized bot for analyzing log files. + + LogAnalysisBot extends [MicroBot][microbots.MicroBot.MicroBot] to analyze log files + inside a sandboxed container and identify root causes by cross-referencing + with source code. The source code folder is mounted as read-only. + + Parameters + ---------- + model : str + The model to use, in the format ``/``. + See [ModelProvider][microbots.constants.ModelProvider] for supported providers. + folder_to_mount : str + The absolute path to the source code folder on the host machine. + This folder will be mounted as read-only inside the bot's sandbox + for cross-referencing with log entries. + environment : any, optional + The execution environment for the bot. If not provided, a default + ``LocalDockerEnvironment`` will be created. + additional_tools : list[ToolAbstract], optional + A list of additional tools to install in the bot's environment. + Defaults to None. + token_provider : any, optional + A token provider for authentication. Required for Azure OpenAI + with Azure AD auth. Defaults to None. + """ def __init__( self, @@ -26,7 +51,7 @@ def __init__( folder_mount_info = Mount( folder_to_mount, f"/{DOCKER_WORKING_DIR}/{os.path.basename(folder_to_mount)}", - PermissionLabels.READ_ONLY + PermissionLabels.READ_ONLY, ) system_prompt = f""" @@ -49,6 +74,22 @@ def __init__( ) def run(self, file_name: str, max_iterations: int = 20, timeout_in_seconds: int = 300) -> any: + """Run the log analysis bot on a log file. + + Parameters + ---------- + file_name : str + The absolute path to the log file on the host machine to analyze. + max_iterations : int, optional + Maximum number of LLM interactions allowed. Defaults to 20. + timeout_in_seconds : int, optional + Maximum time in seconds before the run times out. Defaults to 300. + + Returns + ------- + BotRunResult + The result of the log analysis. + """ # Add the logic to copy the file from the user path to /var/log path in container file_mount_info = Mount( diff --git a/src/microbots/constants.py b/src/microbots/constants.py index c4a7ff98..2bbb52df 100644 --- a/src/microbots/constants.py +++ b/src/microbots/constants.py @@ -3,9 +3,17 @@ class ModelProvider(StrEnum): + """Supported LLM providers for MicroBot. + + Use these values as the provider prefix in the model string: ``/``. + """ + OPENAI = "azure-openai" + """Azure OpenAI provider. Example: ``azure-openai/gpt-4o``""" OLLAMA_LOCAL = "ollama-local" + """Local Ollama provider. Example: ``ollama-local/llama3``""" ANTHROPIC = "anthropic" + """Anthropic Claude provider. Example: ``anthropic/claude-sonnet-4-20250514``""" class ModelEnum(StrEnum): @@ -13,8 +21,12 @@ class ModelEnum(StrEnum): class PermissionLabels(StrEnum): + """Permission levels for mounted folders in the bot's sandbox environment.""" + READ_ONLY = "READ_ONLY" + """Read-only access to the mounted folder.""" READ_WRITE = "READ_WRITE" + """Read and write access to the mounted folder.""" class PermissionMapping: diff --git a/src/microbots/extras/mount.py b/src/microbots/extras/mount.py index a36014b2..df0d445b 100644 --- a/src/microbots/extras/mount.py +++ b/src/microbots/extras/mount.py @@ -7,51 +7,53 @@ class MountType(StrEnum): - """ - Enum representing the type of mount operation. + """Type of mount operation for the bot's sandbox environment.""" - MOUNT : Mount the folder from host to sandbox environment. - COPY : Copy the folder from host to sandbox environment. - """ MOUNT = "mount" + """Mount the folder from host to sandbox environment.""" COPY = "copy" + """Copy the folder from host to sandbox environment.""" @dataclass class Mount: - """ - Folder mount configuration for a microbot environment. + """Folder mount configuration for a microbot environment. All the folders and files to be presented for the Bot should be either mounted or copied to the Bot's sandbox environment using this class. - Attributes + Parameters ---------- host_path : str The absolute path on the host machine to be mounted or copied. sandbox_path : str The absolute path inside the Bot's sandbox environment where the host_path will be mounted or copied. If the host_path is a file - and the sandbox_path ends with a path separator ("/"), then - the file will be placed inside the sandbox_path directory with - the same base name as the host file. + and the sandbox_path ends with a path separator, the file will be + placed inside the sandbox_path directory with the same base name. permission : PermissionLabels - The permission level for the mounted/copied folder. It should - be one of the values from PermissionLabels enum. + The permission level for the mounted/copied folder. See + [PermissionLabels][microbots.constants.PermissionLabels] for supported values. mount_type : MountType, optional - The type of mount operation. Mounting and copying have are the - options. Possible values are MountType enum values. - Default is MountType.MOUNT. + The type of mount operation. See [MountType][microbots.extras.mount.MountType] + for supported values. Defaults to ``MountType.MOUNT``. """ + host_path: str + """The absolute path on the host machine to be mounted or copied.""" sandbox_path: str + """The absolute path inside the Bot's sandbox environment where the host_path will be mounted or copied. If the host_path is a file and the sandbox_path ends with a path separator ("/"), then the file will be placed inside the sandbox_path directory with the same base name.""" permission: PermissionLabels + """The permission level for the mounted/copied folder. See [PermissionLabels][microbots.constants.PermissionLabels] for supported values.""" mount_type: MountType = MountType.MOUNT + """The type of mount operation. See [MountType][microbots.extras.mount.MountType] for supported values. Defaults to ``MountType.MOUNT``.""" # These will be set in __post_init__ permission_key: str = field(init=False) + """Resolved permission key string (e.g. ``ro``, ``rw``). Set automatically.""" host_path_info: PathInfo = field(init=False) + """Path metadata for the host path. Set automatically.""" def __post_init__(self): self.permission_key = PermissionMapping.MAPPING.get(self.permission) diff --git a/src/microbots/llm/openai_api.py b/src/microbots/llm/openai_api.py index 5713d5d6..6c57ea9b 100644 --- a/src/microbots/llm/openai_api.py +++ b/src/microbots/llm/openai_api.py @@ -83,5 +83,4 @@ def clear_history(self): "content": self.system_prompt, } ] - return True - + return True \ No newline at end of file