Skip to content

feat(tools): distro-aware tool commands - #205

Merged
Kavya Sree Kaitepalli (KavyaSree2610) merged 2 commits into
mainfrom
bala/distro-aware-tools
Oct 29, 2026
Merged

Kavya Sree Kaitepalli (KavyaSree2610) merged 2 commits into
mainfrom
bala/distro-aware-tools

Conversation

@0xba1a

Copy link
Copy Markdown
Member

Summary

Tool YAML command fields (install_commands, verify_commands, setup_commands, uninstall_commands) can now be distro-specific. Microbots picks the right commands from the sandbox's /etc/os-release, so the same tool definition can support several sandbox images. The sandbox's distribution is never configured separately.

This is the second PR in the stack, following #202 (stock MCR images prepared on the fly).

Format

Each *_commands field accepts either form:

  • A list: generic commands that run on every distro. This is the existing format, so existing YAMLs keep working unchanged.
  • A map: keys are distro IDs from /etc/os-release (for example debian or azurelinux) and/or generic.
install_commands:
  debian:
    - apt-get update
    - apt-get install -y tesseract-ocr
  azurelinux:
    - tdnf install -y tesseract
verify_commands:          # a list applies to every distro
  - tesseract --version

Resolution

For a map, Microbots reads the sandbox's /etc/os-release:

  • Known distro: its ID wins, then its ID_LIKE entries (so debian also covers Ubuntu), then generic.
  • Known distro, no match: the tool fails with UnsupportedDistroError before any command runs, and the error says which entry to add.
  • Distro can't be detected: Microbots logs a warning and runs generic, or the first entry if there's no generic. A failing command is the last resort.

Changes

  • Environment.get_distro_ids() reads and caches the sandbox's /etc/os-release (ID, then ID_LIKE).
  • ToolAbstract.resolve_commands() selects the commands. Map keys are validated (no empty or duplicate keys) and lower-cased.
  • Internal tools resolve against the sandbox; external tools resolve against the host's /etc/os-release (new microbots.utils.os_release).
  • cscope, browser-use and the tesseract docs example use apt-get, so their commands are now keyed to debian. Their behaviour on the default Debian image is unchanged.
  • Docs: the custom tool walkthrough describes the format and resolution rules.

Testing

  • New test/tools/test_distro_commands.py covers resolution order, the unknown-distro fallback, the UnsupportedDistroError message, key validation, os-release parsing and caching, and internal/external tool wiring. Unit tests: 705 passed. The 6 failures in test_microbot.py::TestMicrobotUnit and 4 errors in test_memory_tool_integration.py also occur on main and come from my local environment.
  • Live checks on the stock images:
    • mcr.microsoft.com/devcontainers/python:3.11: detected ['debian'], and cscope.yaml installed and verified.
    • With /etc/os-release removed: the tool fell back to its first entry with a warning.
    • mcr.microsoft.com/azurelinux/base/core:3.0: detected ['azurelinux'], and cscope.yaml was rejected with UnsupportedDistroError before running anything.

Upcoming PRs in this stack

  1. refactor(env): run stock MCR images, prepare the sandbox on the fly #202 (merged): stock MCR images prepared on the fly.
  2. This PR: distro-aware tool commands.
  3. Azure Linux 3 sandbox (AZURELINUX_IMAGE), with an image option on the bots.
  4. Optional root_access for the sandbox shell.
  5. rpm / mock / azldev tool definitions.
  6. CopilotBot session_options and skill tracking, so it can use a repository's agent skills.

@codecov-commenter

Codecov Comments Bot (codecov-commenter) commented Oct 28, 2026 •

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 98.91304% with 1 line in your changes missing coverage. Please review.
✅ Project coverage is 77.03%. Comparing base (0dc77c8) to head (049f40a).

Files with missing lines Patch % Lines
src/microbots/tools/tool.py 97.43% 1 Missing ⚠️
Additional details and impacted files

Impacted file tree graph

@@            Coverage Diff             @@
##             main     #205      +/-   ##
==========================================
+ Coverage   76.48%   77.03%   +0.55%     
==========================================
  Files          46       47       +1     
  Lines        3113     3192      +79     
==========================================
+ Hits         2381     2459      +78     
- Misses        732      733       +1     
Flag Coverage Δ
ghcp 31.76% <34.78%> (+0.06%) ⬆️
integration 42.16% <71.73%> (+0.79%) ⬆️
ollama_local 34.27% <71.73%> (+0.99%) ⬆️
slow-browser 18.42% <34.78%> (+0.39%) ⬆️
slow-other 39.12% <53.26%> (+0.48%) ⬆️
unit 74.06% <98.91%> (+0.62%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

Files with missing lines Coverage Δ
src/microbots/environment/Environment.py 100.00% <100.00%> (ø)
src/microbots/tools/external_tool.py 100.00% <100.00%> (ø)
src/microbots/tools/internal_tool.py 97.75% <100.00%> (+0.10%) ⬆️
src/microbots/utils/os_release.py 100.00% <100.00%> (ø)
src/microbots/tools/tool.py 98.71% <97.43%> (-1.29%) ⬇️
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Tool YAML *_commands fields (install/verify/setup/uninstall) now accept
either a list (generic: runs on every distro) or a map keyed by distro ID
from /etc/os-release and/or "generic". The distro is always read from the
running sandbox, never configured:

- Known distro: its ID wins, then its ID_LIKE entries (so "debian" covers
  Ubuntu), then "generic"; with no match the tool fails with
  UnsupportedDistroError before running anything.
- Unknown distro (no /etc/os-release): "generic", else the first entry, is
  run with a warning; a failing command is the last resort.

- Environment.get_distro_ids() reads and caches /etc/os-release.
- ToolAbstract.resolve_commands() selects commands; map keys are
  validated and normalised to lower case.
- Internal tools resolve against the sandbox, external tools against
  the host (microbots.utils.os_release).
- cscope, browser-use and the tesseract docs example use apt-get, so
  their commands are now keyed to "debian".
- Document the format in the custom tool walkthrough.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@0xba1a
Bala (0xba1a) force-pushed the bala/distro-aware-tools branch from a409f03 to 129e301 Compare October 28, 2026 08:54
…ribute

Review follow-ups:

- resolve_commands() takes the distro IDs as a list instead of a
  callable. Internal tools gather them with env.get_distro_ids() and
  external tools with host_distro_ids() before resolving.
- Environment declares the _distro_ids cache as a class attribute
  (None until /etc/os-release is read), replacing the getattr fallback.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@KavyaSree2610
Kavya Sree Kaitepalli (KavyaSree2610) merged commit e434933 into main Oct 29, 2026
10 checks passed
@0xba1a
Bala (0xba1a) deleted the bala/distro-aware-tools branch October 29, 2026 06:49
Bala (0xba1a) added a commit that referenced this pull request Nov 2, 2026
Review follow-up: CopilotBot had its own per-distro Node.js/copilot-cli
install table and matching logic, duplicating the distro-aware tool
command resolution (#205). Move it into the normal tool model:

- New tool_definitions/copilot-cli.yaml: Node.js 22 per distro
  (NodeSource on Debian; checksum-verified nodejs.org build on Azure
  Linux, which only packages Node 20) and the pinned
  @github/copilot@1.0.39 CLI, verified with `copilot --version`. It has no
  usage instructions, since it is infrastructure rather than a tool for
  the model.
- CopilotBot._install_copilot_cli() installs and verifies that tool;
  _NODE_INSTALL_COMMANDS, _COPILOT_CLI_PACKAGE and _node_install_commands
  are removed. Unsupported distros now raise UnsupportedDistroError, and
  an undetectable distro falls back to the first (Debian) entry.
- The headless server start, token injection and readiness check stay
  in CopilotBot; the host-side SDK stays the `ghcp` pip extra.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Bala (0xba1a) added a commit that referenced this pull request Nov 2, 2026
Review follow-up: CopilotBot had its own per-distro Node.js/copilot-cli
install table and matching logic, duplicating the distro-aware tool
command resolution (#205). Move it into the normal tool model:

- New tool_definitions/copilot-cli.yaml: Node.js 22 per distro
  (NodeSource on Debian; checksum-verified nodejs.org build on Azure
  Linux, which only packages Node 20) and the pinned
  @github/copilot@1.0.39 CLI, verified with `copilot --version`. It has no
  usage instructions, since it is infrastructure rather than a tool for
  the model.
- CopilotBot._install_copilot_cli() installs and verifies that tool;
  _NODE_INSTALL_COMMANDS, _COPILOT_CLI_PACKAGE and _node_install_commands
  are removed. Unsupported distros now raise UnsupportedDistroError, and
  an undetectable distro falls back to the first (Debian) entry.
- The headless server start, token injection and readiness check stay
  in CopilotBot; the host-side SDK stays the `ghcp` pip extra.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Kavya Sree Kaitepalli (KavyaSree2610) pushed a commit that referenced this pull request Nov 2, 2026
#210)

* feat(copilot): SDK session options, skill tracking and image selection

Let CopilotBot use a repository's agent skills and run on any sandbox
image:

- session_options: extra kwargs forwarded to CopilotClient.create_session
  (skill_directories, custom_agents, mcp_servers, working_directory, ...).
  Keys are validated against the installed SDK; model, provider,
  streaming, hooks and system_message stay managed by CopilotBot. run()
  accepts per-run overrides. Only option names are logged.
- invoked_skills: names of skills used in the last run (skill.invoked
  events); skill load/invoke events are logged.
- image: container image of the auto-created environment.
  copilot-cli's Node.js 22 is installed for the distro read from
  /etc/os-release (NodeSource on Debian, checksum-verified nodejs.org
  build on Azure Linux, which only packages Node 20; Debian's steps when
  the distro is unknown; unsupported distros fail before running).
- Integration test: the agent upgrades util-linux in an Azure Linux
  checkout using its AGENTS.md and azldev-* skills (READ_ONLY by default,
  AZURELINUX_KEEP_CHANGES=1 to keep the changes).
- Docs: session options and Azure Linux skills example.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

# Conflicts:
#	docs/advanced/bots/copilot-bot.md
#	src/microbots/bot/CopilotBot.py
#	test/bot/test_copilot_bot.py

* refactor(copilot): install copilot-cli from a tool definition

Review follow-up: CopilotBot had its own per-distro Node.js/copilot-cli
install table and matching logic, duplicating the distro-aware tool
command resolution (#205). Move it into the normal tool model:

- New tool_definitions/copilot-cli.yaml: Node.js 22 per distro
  (NodeSource on Debian; checksum-verified nodejs.org build on Azure
  Linux, which only packages Node 20) and the pinned
  @github/copilot@1.0.39 CLI, verified with `copilot --version`. It has no
  usage instructions, since it is infrastructure rather than a tool for
  the model.
- CopilotBot._install_copilot_cli() installs and verifies that tool;
  _NODE_INSTALL_COMMANDS, _COPILOT_CLI_PACKAGE and _node_install_commands
  are removed. Unsupported distros now raise UnsupportedDistroError, and
  an undetectable distro falls back to the first (Debian) entry.
- The headless server start, token injection and readiness check stay
  in CopilotBot; the host-side SDK stays the `ghcp` pip extra.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* build(copilot): upgrade github-copilot-sdk to 1.0.28 and copilot-cli to 1.0.105

github-copilot-sdk 1.x pins the copilot-cli release it targets
(CLI_VERSION in copilot/_cli_version.py); 1.0.28 targets 1.0.105. The
0.3.0 / 1.0.39 pair is incompatible with either newer half (0.3.0 cannot
parse 1.0.105 responses; 1.0.39 lacks the 1.x `connect` RPC).

- Connect with CopilotClient(connection=UriRuntimeConnection(...)), which
  replaces ExternalServerConfig.
- Import PermissionHandler from copilot.session only and SessionEventType
  from the public copilot.session_events module; a pre-1.x SDK now fails
  with an explicit upgrade message.
- Cross-reference the two pins in pyproject.toml and copilot-cli.yaml, let
  the ghcp CI job install the `ghcp` extra instead of repeating the pin, and
  add test_copilot_version_pins.py to check the pins (and, under `ghcp`,
  that the installed SDK targets the pinned CLI).
- Replace the pre-0.3.0 SDK-layout tests with 1.x import/connection tests.
- Make the session-options test independent of COPILOT_BYOK_MODEL.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* feat(copilot): add model_id for BYOK deployments with custom names

copilot-cli 1.0.105 picks request settings (temperature, reasoning_effort,
prompts, token limits) from the model name. For a BYOK deployment with a
custom name, such as CI's Azure `mini-swe-agent-gpt5`, it falls back to
generic defaults and sends temperature 0, which GPT-5 rejects.

- New `model_id` parameter and COPILOT_BYOK_MODEL_ID env var, mapped to the
  SDK's provider `model_id`; the deployment name is kept as `wire_model`.
- ghcp CI job: use the Responses wire API and COPILOT_BYOK_MODEL_ID=gpt-5.
- Docs and unit tests for the new option.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

---------

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants