Skip to content

Commit 963a784

Browse files
authored
feat: Get CLI running on windows (#27)
Per strands-agents/tools#17 some tools do not work on windows and they fail on importing the tools. To workaround that, conditionally include tools when running on windows. Also included an update to the strand tool to make all tools available since we now have centralized logic for that. Also add workflows to run tests on windows + MacOS --------- Co-authored-by: Mackenzie Zastrow <[email protected]>
1 parent 7494711 commit 963a784

File tree

5 files changed

+158
-84
lines changed

5 files changed

+158
-84
lines changed

.github/workflows/test-lint.yml

Lines changed: 39 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,15 +9,49 @@ on:
99

1010
jobs:
1111
unit-test:
12-
name: Unit Tests
12+
name: Unit Tests - Python ${{ matrix.python-version }} - ${{ matrix.os-name }}
1313
permissions:
1414
contents: read
15-
runs-on: ubuntu-latest
1615
strategy:
1716
matrix:
18-
python-version: ['3.10', '3.11', '3.12', '3.13']
19-
fail-fast: false
20-
17+
include:
18+
# Linux
19+
- os: ubuntu-latest
20+
os-name: 'linux'
21+
python-version: "3.10"
22+
- os: ubuntu-latest
23+
os-name: 'linux'
24+
python-version: "3.11"
25+
- os: ubuntu-latest
26+
os-name: 'linux'
27+
python-version: "3.12"
28+
- os: ubuntu-latest
29+
os-name: 'linux'
30+
python-version: "3.13"
31+
# Windows
32+
- os: windows-latest
33+
os-name: 'windows'
34+
python-version: "3.10"
35+
- os: windows-latest
36+
os-name: 'windows'
37+
python-version: "3.11"
38+
- os: windows-latest
39+
os-name: 'windows'
40+
python-version: "3.12"
41+
- os: windows-latest
42+
os-name: 'windows'
43+
python-version: "3.13"
44+
# MacOS - earliest & latest only; not enough runners for macOS
45+
- os: macos-latest
46+
os-name: 'macOS'
47+
python-version: "3.10"
48+
- os: macos-latest
49+
os-name: 'macOS'
50+
python-version: "3.13"
51+
fail-fast: true
52+
runs-on: ${{ matrix.os }}
53+
env:
54+
LOG_LEVEL: DEBUG
2155
steps:
2256
- name: Checkout code
2357
uses: actions/checkout@v4

src/strands_agents_builder/strands.py

Lines changed: 2 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -8,50 +8,14 @@
88

99
# Strands
1010
from strands import Agent
11-
12-
# Strands tools
13-
from strands_tools import (
14-
agent_graph,
15-
calculator,
16-
cron,
17-
current_time,
18-
editor,
19-
environment,
20-
file_read,
21-
file_write,
22-
generate_image,
23-
http_request,
24-
image_reader,
25-
journal,
26-
load_tool,
27-
memory,
28-
nova_reels,
29-
python_repl,
30-
retrieve,
31-
shell,
32-
slack,
33-
speak,
34-
stop,
35-
swarm,
36-
think,
37-
use_aws,
38-
use_llm,
39-
workflow,
40-
)
4111
from strands_tools.utils.user_input import get_user_input
4212

4313
from strands_agents_builder.handlers.callback_handler import callback_handler
14+
from strands_agents_builder.tools import get_tools
4415
from strands_agents_builder.utils import model_utils
4516
from strands_agents_builder.utils.kb_utils import load_system_prompt, store_conversation_in_kb
4617
from strands_agents_builder.utils.welcome_utils import render_goodbye_message, render_welcome_message
4718

48-
# Custom tools
49-
from tools import (
50-
store_in_kb,
51-
strand,
52-
welcome,
53-
)
54-
5519
os.environ["STRANDS_TOOL_CONSOLE_MODE"] = "enabled"
5620

5721

@@ -87,38 +51,7 @@ def main():
8751
# Load system prompt
8852
system_prompt = load_system_prompt()
8953

90-
tools = [
91-
agent_graph,
92-
calculator,
93-
cron,
94-
current_time,
95-
editor,
96-
environment,
97-
file_read,
98-
file_write,
99-
generate_image,
100-
http_request,
101-
image_reader,
102-
journal,
103-
load_tool,
104-
memory,
105-
nova_reels,
106-
python_repl,
107-
retrieve,
108-
shell,
109-
slack,
110-
speak,
111-
stop,
112-
swarm,
113-
think,
114-
use_aws,
115-
use_llm,
116-
workflow,
117-
# Strands tools
118-
store_in_kb,
119-
strand,
120-
welcome,
121-
]
54+
tools = get_tools().values()
12255

12356
agent = Agent(
12457
model=model,
Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
import platform
2+
from typing import Any
3+
4+
# Strands tools
5+
from strands_tools import (
6+
agent_graph,
7+
calculator,
8+
cron,
9+
current_time,
10+
editor,
11+
environment,
12+
file_read,
13+
file_write,
14+
generate_image,
15+
http_request,
16+
image_reader,
17+
journal,
18+
load_tool,
19+
memory,
20+
nova_reels,
21+
retrieve,
22+
slack,
23+
speak,
24+
stop,
25+
swarm,
26+
think,
27+
use_aws,
28+
use_llm,
29+
workflow,
30+
)
31+
32+
# Custom tools
33+
from tools import (
34+
store_in_kb,
35+
strand,
36+
welcome,
37+
)
38+
39+
40+
def get_tools() -> dict[str, Any]:
41+
"""
42+
Returns the platform-specific collection of available agent tools for strands.
43+
44+
Note:
45+
Tool availability varies by platform and system configuration.
46+
Each tool is initialized as a singleton instance.
47+
"""
48+
49+
tools = {
50+
"agent_graph": agent_graph,
51+
"calculator": calculator,
52+
"cron": cron,
53+
"current_time": current_time,
54+
"editor": editor,
55+
"environment": environment,
56+
"file_read": file_read,
57+
"file_write": file_write,
58+
"generate_image": generate_image,
59+
"http_request": http_request,
60+
"image_reader": image_reader,
61+
"journal": journal,
62+
"load_tool": load_tool,
63+
"memory": memory,
64+
"nova_reels": nova_reels,
65+
"retrieve": retrieve,
66+
"slack": slack,
67+
"speak": speak,
68+
"stop": stop,
69+
"swarm": swarm,
70+
"think": think,
71+
"use_aws": use_aws,
72+
"use_llm": use_llm,
73+
"workflow": workflow,
74+
# Strands tools
75+
"store_in_kb": store_in_kb,
76+
"strand": strand,
77+
"welcome": welcome,
78+
}
79+
80+
# Some tools don't currently work on windows and even fail to import, so we need to dynamically add these
81+
# (https://github.com/strands-agents/tools/issues/17
82+
if platform.system() != "Windows":
83+
from strands_tools import (
84+
python_repl,
85+
shell,
86+
)
87+
88+
tools |= {
89+
"python_repl": python_repl,
90+
"shell": shell,
91+
}
92+
93+
return tools

tests/test_tools.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import platform
2+
3+
import pytest
4+
5+
from strands_agents_builder.tools import get_tools
6+
7+
8+
@pytest.mark.skipif(platform.system() == "Windows", reason="Windows cannot import certain tools")
9+
def test_tools_includes_more_tools_on_non_windows():
10+
tools = get_tools()
11+
12+
assert "python_repl" in tools
13+
assert "shell" in tools
14+
15+
16+
@pytest.mark.skipif(platform.system() != "Windows", reason="Windows-specific test")
17+
def test_tools_includes_more_tools_on_windows():
18+
tools = get_tools()
19+
20+
assert "python_repl" not in tools
21+
assert "shell" not in tools

tools/strand.py

Lines changed: 3 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -46,16 +46,9 @@ def strand(
4646
sys.stdout = captured_output
4747

4848
try:
49-
# Resolve tools based on provided tool names
50-
# For simplicity, we'll import a common set, but we could make this more dynamic
51-
from strands_tools import editor, load_tool, python_repl, shell
52-
53-
all_tools = {
54-
"shell": shell,
55-
"editor": editor,
56-
"python_repl": python_repl,
57-
"load_tool": load_tool,
58-
}
49+
from strands_agents_builder.tools import get_tools
50+
51+
all_tools = get_tools()
5952

6053
# Select requested tools or use all if none specified
6154
selected_tools = [all_tools[name] for name in tool_names if name in all_tools]

0 commit comments

Comments
 (0)