strands-code-agent 0.1.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,4 @@
1
+ from strands_code_agent.code_agent import CodeAgent
2
+ from strands_code_agent.toolkits import Toolkit
3
+
4
+ __all__ = ["CodeAgent", "Toolkit"]
@@ -0,0 +1,142 @@
1
+ import tempfile
2
+
3
+ from strands import Agent
4
+ from jinja2 import Template
5
+
6
+ from strands_code_agent.document_code import get_documentation
7
+ from strands_code_agent.python_environments.local_sandboxed import SandboxedPythonInterpreter
8
+ from strands_code_agent.imports import get_import_string, extract_imports
9
+
10
+
11
+ CODE_AGENT_INSTRUCTIONS = """
12
+ You are a code agent. You solve tasks by writing and executing Python code using the python_repl tool.
13
+
14
+ The Python interpreter state resets completely with each new user message, but it persists across multiple tool invocations within a single response.
15
+ You can perform multi-step computation within a single turn, but do not assume that results from a previous turn are still in memory.
16
+ """
17
+
18
+ CODE_PREAMBLE_TEMPLATE = Template("""
19
+ The python environment of the python_repl tool is initialised with the following code (you do not need to rewrite this code):
20
+ ```python
21
+ {{CODE_PREAMBLE}}
22
+ ```
23
+ """)
24
+
25
+ TEMP_DIR_TEMPLATE = Template("""
26
+ If you need to generate a file use this temporary directory: {{TEMP_DIR}}
27
+ The user has no access to this temporary directory.
28
+ """)
29
+
30
+ DOMAIN_SPECIFIC_DOC_TEMPLATE = Template("""
31
+ You can use the following Domain Specific Code:
32
+ {{SYMBOLS_DOCUMENTATION}}
33
+ """)
34
+
35
+
36
+ class CodeAgent(Agent):
37
+ """A coding agent that extends Strands Agent with a sandboxed Python REPL and domain-specific symbol documentation.
38
+
39
+ CodeAgent wraps a :class:`PythonInterpreter` as a built-in ``python_repl`` tool and
40
+ assembles a system prompt from the provided toolkits. Each :class:`Toolkit` can contribute:
41
+
42
+ - **libraries** – module names authorized for import in the sandboxed interpreter.
43
+ - **initialization_code** – Python code executed at interpreter startup (e.g. imports, config).
44
+ Any modules imported in this code are automatically authorized.
45
+ - **usage_instructions** – free-text guidance appended to the system prompt.
46
+ - **domain_specific_code** – callable symbols whose source and docstrings are documented in
47
+ the system prompt and made available in the interpreter.
48
+
49
+ The interpreter state persists across tool invocations within a single agent turn but
50
+ resets completely between user messages.
51
+
52
+ Args:
53
+ system_prompt: Optional base system prompt prepended before the coding instructions.
54
+
55
+ tools: Additional tools to include alongside the built-in Python REPL.
56
+
57
+ toolkits: :class:`Toolkit` instances that supply libraries, initialization code,
58
+ usage instructions, and domain-specific symbols to the REPL environment.
59
+
60
+ tmp_dir: If ``True`` (default), creates a temporary directory under ``/tmp`` and
61
+ documents its path in the system prompt so the agent can write files there.
62
+
63
+ timeout_seconds: Maximum execution time in seconds for each ``python_repl``
64
+ invocation. Defaults to ``60``.
65
+
66
+ python_interpreter_class: The :class:`PythonInterpreter` subclass to use for
67
+ code execution. Defaults to :class:`ExecPythonInterpreter` (lightweight,
68
+ unrestricted ``exec()``-based). Use :class:`SandboxedPythonInterpreter`
69
+ for import restrictions and sandboxed execution.
70
+
71
+ **kwargs: Additional arguments forwarded to the Strands :class:`Agent` base class
72
+ (e.g. ``model``, ``callback_handler``).
73
+ """
74
+ def __init__(self,
75
+ system_prompt:str|None=None,
76
+ tools:list|None=None,
77
+ toolkits:list|None=None,
78
+ tmp_dir=True,
79
+ timeout_seconds=60,
80
+ python_interpreter_class=SandboxedPythonInterpreter,
81
+ **kwargs):
82
+ authorized_imports = set()
83
+ initialization_code = []
84
+ usage_instructions = []
85
+ domain_specific_code = []
86
+ if toolkits is not None:
87
+ for toolkit in toolkits:
88
+ if toolkit.libraries is not None:
89
+ authorized_imports.update(toolkit.libraries)
90
+ if toolkit.initialization_code is not None:
91
+ initialization_code.append(toolkit.initialization_code.strip())
92
+ if toolkit.usage_instructions is not None:
93
+ usage_instructions.append(toolkit.usage_instructions.strip())
94
+ if toolkit.domain_specific_code is not None:
95
+ domain_specific_code.extend(toolkit.domain_specific_code)
96
+
97
+ additional_functions = {}
98
+ domain_specific_doc = ""
99
+ if domain_specific_code:
100
+ authorized_imports.update(sym.__module__ for sym in domain_specific_code if sym.__module__ != "__main__")
101
+ initialization_code.append(get_import_string(domain_specific_code))
102
+ sym_doc = "\n".join([get_documentation(sym) for sym in domain_specific_code])
103
+ domain_specific_doc = DOMAIN_SPECIFIC_DOC_TEMPLATE.render(SYMBOLS_DOCUMENTATION=sym_doc)
104
+ additional_functions = {sym.__qualname__.split(".")[0]: sym for sym in domain_specific_code}
105
+
106
+ code_preamble = "\n".join(initialization_code)
107
+ # Auto-authorize any modules imported in initialization code so users
108
+ # don't have to duplicate them in both `libraries` and `initialization_code`.
109
+ authorized_imports.update(extract_imports(code_preamble))
110
+ code_preamble_doc = CODE_PREAMBLE_TEMPLATE.render(CODE_PREAMBLE=code_preamble) if code_preamble else ""
111
+
112
+ tmp_dir_doc = ""
113
+ if tmp_dir:
114
+ self.tmp_dir = tempfile.mkdtemp(dir='/tmp')
115
+ tmp_dir_doc = TEMP_DIR_TEMPLATE.render(TEMP_DIR=self.tmp_dir)
116
+
117
+ system_prompt = '\n'.join([
118
+ system_prompt if system_prompt is not None else "",
119
+ CODE_AGENT_INSTRUCTIONS,
120
+ code_preamble_doc,
121
+ "\n".join(usage_instructions),
122
+ tmp_dir_doc,
123
+ domain_specific_doc
124
+ ])
125
+
126
+ self.python_repl = python_interpreter_class(
127
+ code_preamble,
128
+ authorized_imports=authorized_imports,
129
+ additional_functions=additional_functions,
130
+ timeout_seconds=timeout_seconds,
131
+ )
132
+ python_repl_tool = self.python_repl.get_tool()
133
+ if tools is not None:
134
+ tools.append(python_repl_tool)
135
+ else:
136
+ tools = [python_repl_tool]
137
+
138
+ kwargs.update({
139
+ "system_prompt": system_prompt,
140
+ "tools": tools
141
+ })
142
+ super().__init__(**kwargs)
@@ -0,0 +1,63 @@
1
+ import inspect
2
+ from typing import Callable, Type, Union
3
+
4
+
5
+ def format_function(func, indent: str = "") -> str:
6
+ try:
7
+ sig = inspect.signature(func)
8
+ result = f"{indent}def {func.__name__}{sig}:\n"
9
+ except (ValueError, TypeError):
10
+ result = f"{indent}def {func.__name__}(...):\n"
11
+
12
+ doc = inspect.getdoc(func)
13
+ if doc:
14
+ doc_lines = doc.split('\n')
15
+ result += f'{indent} """\n'
16
+ for line in doc_lines:
17
+ result += f"{indent} {line}\n"
18
+ result += f'{indent} """\n'
19
+
20
+ result += f"{indent} ...\n"
21
+ return result
22
+
23
+
24
+ def get_documentation(obj: Union[Callable, Type]) -> str:
25
+ """
26
+ Extract documentation from a Python function or class.
27
+ Returns formatted text suitable for a coding agent.
28
+ """
29
+ if inspect.isclass(obj):
30
+ # Class header with constructor signature
31
+ try:
32
+ sig = inspect.signature(obj)
33
+ output = f"class {obj.__name__}{sig}:\n"
34
+ except (ValueError, TypeError):
35
+ output = f"class {obj.__name__}:\n"
36
+
37
+ # Class docstring
38
+ class_doc = inspect.getdoc(obj)
39
+ if class_doc:
40
+ output += ' """\n'
41
+ for line in class_doc.split('\n'):
42
+ output += f" {line}\n"
43
+ output += ' """\n\n'
44
+
45
+ # Methods (public + key dunder methods)
46
+ important_dunders = {
47
+ '__init__', '__call__', '__enter__', '__exit__',
48
+ '__iter__', '__next__', '__getitem__', '__setitem__',
49
+ '__len__', '__contains__', '__repr__', '__str__'
50
+ }
51
+
52
+ for name, method in inspect.getmembers(obj, predicate=inspect.isfunction):
53
+ if name.startswith('_') and name not in important_dunders:
54
+ continue
55
+ output += format_function(method, indent=" ") + "\n"
56
+
57
+ return output.rstrip() + "\n"
58
+
59
+ elif callable(obj):
60
+ return format_function(obj)
61
+
62
+ else:
63
+ raise TypeError(f"Expected a function or class, got {type(obj)}")
@@ -0,0 +1,36 @@
1
+ import ast
2
+ from typing import Callable, Type, Union
3
+ from collections import defaultdict
4
+
5
+
6
+ def extract_imports(code: str) -> set[str]:
7
+ """Extract top-level module names from import statements in a code snippet."""
8
+ try:
9
+ tree = ast.parse(code)
10
+ except SyntaxError:
11
+ return set()
12
+ modules = set()
13
+ for node in ast.walk(tree):
14
+ if isinstance(node, ast.Import):
15
+ for alias in node.names:
16
+ modules.add(alias.name)
17
+ elif isinstance(node, ast.ImportFrom):
18
+ if node.module:
19
+ modules.add(node.module)
20
+ for alias in node.names:
21
+ modules.add(f"{node.module}.{alias.name}")
22
+ return modules
23
+
24
+
25
+ def get_import_string(symbols: list[Union[Callable, Type]]) -> str:
26
+ """Generate minimal import statements for a list of symbols."""
27
+ by_module: dict[str, list[str]] = defaultdict(list)
28
+ for sym in symbols:
29
+ if sym.__module__ == "__main__":
30
+ continue
31
+ by_module[sym.__module__].append(sym.__qualname__.split(".")[0])
32
+
33
+ lines = []
34
+ for module, names in sorted(by_module.items()):
35
+ lines.append(f"from {module} import {', '.join(sorted(set(names)))}")
36
+ return "\n".join(lines)
File without changes
@@ -0,0 +1,44 @@
1
+ from abc import ABC, abstractmethod
2
+
3
+ from strands import tool
4
+
5
+
6
+ STDOUT_LABEL = "STDOUT:\n"
7
+ STDERR_LABEL = "STDERR:"
8
+
9
+
10
+ class PythonInterpreter(ABC):
11
+ def __init__(self, state_initialization=None, stdout_label=STDOUT_LABEL, stderr_label=STDERR_LABEL, authorized_imports=None, additional_functions=None, timeout_seconds=60):
12
+ self.state_initialization = state_initialization
13
+ self.stdout_label = stdout_label
14
+ self.stderr_label = stderr_label
15
+
16
+ @abstractmethod
17
+ def clear_state(self):
18
+ ...
19
+
20
+ @abstractmethod
21
+ def execute_code(self, code) -> tuple[str, str]:
22
+ ...
23
+
24
+ def get_tool(self):
25
+ @tool
26
+ def python_repl(code: str) -> str:
27
+ """
28
+ Executes Python code in a REPL environment with state persistence.
29
+
30
+ Args:
31
+ code: The Python code to execute
32
+ """
33
+ stdout_output, stderr_output = self.execute_code(code)
34
+
35
+ observation = []
36
+ if stdout_output:
37
+ observation.append(f"{self.stdout_label}{stdout_output}")
38
+ if stderr_output:
39
+ observation.append(f"{self.stderr_label}{stderr_output}")
40
+ if not observation:
41
+ observation.append("Code executed successfully.")
42
+ return '\n'.join(observation)
43
+
44
+ return python_repl
@@ -0,0 +1,28 @@
1
+ import io
2
+ from contextlib import redirect_stdout, redirect_stderr
3
+
4
+ from strands_code_agent.python_environments.base import PythonInterpreter, STDOUT_LABEL, STDERR_LABEL
5
+
6
+
7
+ class ExecPythonInterpreter(PythonInterpreter):
8
+ def __init__(self, state_initialization=None, stdout_label=STDOUT_LABEL, stderr_label=STDERR_LABEL, **kwargs):
9
+ super().__init__(state_initialization, stdout_label, stderr_label)
10
+
11
+ self.state = {}
12
+ if self.state_initialization:
13
+ self.execute_code(self.state_initialization)
14
+
15
+ def clear_state(self):
16
+ self.state.clear()
17
+ if self.state_initialization:
18
+ self.execute_code(self.state_initialization)
19
+
20
+ def execute_code(self, code):
21
+ stdout_buffer = io.StringIO()
22
+ stderr_buffer = io.StringIO()
23
+ try:
24
+ with redirect_stdout(stdout_buffer), redirect_stderr(stderr_buffer):
25
+ exec(code, self.state)
26
+ except Exception as e:
27
+ stderr_buffer.write(str(e))
28
+ return stdout_buffer.getvalue().strip(), stderr_buffer.getvalue().strip()
@@ -0,0 +1,63 @@
1
+ import warnings
2
+
3
+ from smolagents.local_python_executor import LocalPythonExecutor
4
+
5
+ from strands_code_agent.python_environments.base import PythonInterpreter, STDOUT_LABEL, STDERR_LABEL
6
+
7
+
8
+ # Python builtins that smolagents' executor doesn't allow-list by default
9
+ EXTRA_BUILTINS = {"repr": repr, "ascii": ascii, "ord": ord, "chr": chr, "hex": hex, "oct": oct, "bin": bin}
10
+
11
+
12
+ class SandboxedPythonInterpreter(PythonInterpreter):
13
+ def __init__(self, state_initialization=None, stdout_label=STDOUT_LABEL, stderr_label=STDERR_LABEL, authorized_imports=None, additional_functions=None, timeout_seconds=60):
14
+ super().__init__(state_initialization, stdout_label, stderr_label)
15
+
16
+ self.authorized_imports = authorized_imports or []
17
+ self.additional_functions = {**EXTRA_BUILTINS, **(additional_functions or {})}
18
+ self.timeout_seconds = timeout_seconds
19
+
20
+ self._init_executor()
21
+
22
+ def _init_executor(self):
23
+ # smolagents' LocalPythonExecutor introspects all attributes of authorized modules
24
+ # via getattr(), which triggers DeprecationWarnings on access, not use.
25
+ with warnings.catch_warnings():
26
+ warnings.simplefilter("ignore")
27
+ self.executor = LocalPythonExecutor(
28
+ additional_authorized_imports=self.authorized_imports,
29
+ additional_functions=self.additional_functions,
30
+ timeout_seconds=self.timeout_seconds,
31
+ )
32
+ self.executor.send_tools({})
33
+ if self.state_initialization:
34
+ self.executor(self.state_initialization)
35
+
36
+ def clear_state(self):
37
+ self._init_executor()
38
+
39
+ def execute_code(self, code):
40
+ stdout, stderr = "", ""
41
+ try:
42
+ result = self.executor(code)
43
+ stdout = result.logs.strip() if result.logs else ""
44
+ except Exception as e:
45
+ # Salvage any print output captured before the error
46
+ if hasattr(self.executor, "state") and "_print_outputs" in self.executor.state:
47
+ stdout = str(self.executor.state["_print_outputs"]).strip()
48
+ stderr = str(e)
49
+ return stdout, stderr
50
+
51
+ def __str__(self) -> str:
52
+ buffer = []
53
+ if self.authorized_imports:
54
+ buffer.append(f"# Authorized Imports: {', '.join(self.authorized_imports)}")
55
+ if self.additional_functions:
56
+ buffer.append(f"# Additional Functions: {', '.join(self.additional_functions.keys())}")
57
+ if self.state_initialization:
58
+ buffer.append(f"""# Init Code:
59
+ ```python
60
+ {self.state_initialization}
61
+ ```
62
+ """)
63
+ return '\n'.join(buffer) if buffer else "Standard PythonInterpreter"
@@ -0,0 +1,42 @@
1
+ from dataclasses import dataclass
2
+
3
+
4
+ @dataclass
5
+ class Toolkit:
6
+ """A toolkit that bundles libraries, initialization code, usage instructions, and domain-specific
7
+ symbols for use by a CodeAgent's Python REPL environment.
8
+
9
+ Args:
10
+ libraries: Library names to authorize as imports in the Python executor.
11
+ initialization_code: Python code snippet to run when initializing the environment.
12
+ usage_instructions: Extra instructions included in the system prompt about how to use the provided libraries.
13
+ domain_specific_code: Callable symbols to be fully imported and documented in the agent's context.
14
+ """
15
+ libraries: list[str] | None = None
16
+ initialization_code: str | None = None
17
+ usage_instructions: str | None = None
18
+ domain_specific_code: list | None = None
19
+
20
+
21
+ VISUALIZATION_TOOLKIT = Toolkit(
22
+ libraries = ['matplotlib.*', 'seaborn.*'],
23
+ initialization_code = """
24
+ # Visualization Libraries
25
+ import matplotlib
26
+ matplotlib.use('Agg') # Use non-interactive backend
27
+ import matplotlib.pyplot as plt
28
+ import seaborn as sns
29
+ """,
30
+ usage_instructions="""
31
+ Do not try to show any matplotlib image: the python_repl tool executes the code in a sub-process without a GUI.
32
+ """)
33
+
34
+
35
+ DATA_ANALYSIS_TOOLKIT = Toolkit(
36
+ libraries = ['numpy.*', 'pandas.*', 'scipy.*', 'datetime'],
37
+ initialization_code = """
38
+ from datetime import date, datetime, timedelta
39
+
40
+ import numpy as np
41
+ import pandas as pd
42
+ """)
@@ -0,0 +1,7 @@
1
+ import base64
2
+
3
+
4
+ def image_to_base64(image_path):
5
+ """Read an image file and return its contents as a base64-encoded string."""
6
+ with open(image_path, 'rb') as f:
7
+ return base64.b64encode(f.read()).decode('utf-8')
@@ -0,0 +1,163 @@
1
+ Metadata-Version: 2.4
2
+ Name: strands-code-agent
3
+ Version: 0.1.0
4
+ Summary: A coding agent built on Strands Agents SDK that uses code generation as the primary action interface
5
+ Project-URL: Homepage, https://github.com/aws-samples/sample-strands-code-agent
6
+ Project-URL: Repository, https://github.com/aws-samples/sample-strands-code-agent
7
+ Project-URL: Issues, https://github.com/aws-samples/sample-strands-code-agent/issues
8
+ Author: Emilio Monti
9
+ License-Expression: MIT-0
10
+ License-File: LICENSE
11
+ Keywords: agents,code-generation,llm,repl,strands
12
+ Classifier: Development Status :: 4 - Beta
13
+ Classifier: Intended Audience :: Developers
14
+ Classifier: License :: OSI Approved :: MIT License
15
+ Classifier: Programming Language :: Python :: 3
16
+ Classifier: Programming Language :: Python :: 3.10
17
+ Classifier: Programming Language :: Python :: 3.11
18
+ Classifier: Programming Language :: Python :: 3.12
19
+ Classifier: Programming Language :: Python :: 3.13
20
+ Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
21
+ Requires-Python: >=3.10
22
+ Requires-Dist: jinja2>=3.0
23
+ Requires-Dist: smolagents>=1.0.0
24
+ Requires-Dist: strands-agents>=0.1.0
25
+ Description-Content-Type: text/markdown
26
+
27
+ # strands-code-agent
28
+
29
+ A coding agent built on [Strands Agents SDK](https://github.com/strands-agents/sdk-python) that replaces the tool-calling paradigm with code generation as the agent's primary action interface. Rather than invoking structured tools by name and passing results through the conversation context, the agent writes Python code in a persistent REPL where domain capabilities (database queries, APIs, etc.) are exposed as importable library functions. This keeps intermediate data as native Python objects in memory and lets the agent compose multi-step logic in a single code block instead of orchestrating sequential tool calls. In empirical evaluations on the Data Agent Benchmark, this code-generation paradigm achieves higher accuracy (+7%) while consuming 78% fewer input tokens, completing tasks 56% faster, and requiring 35% fewer reasoning cycles compared to an equivalent tool-calling agent. The library makes it easy to configure the Python environment with the libraries and domain-specific code your agent needs.
30
+
31
+ ## Installation
32
+
33
+ ```bash
34
+ pip install strands-code-agent
35
+ ```
36
+
37
+ ## Quick Start
38
+
39
+ ```python
40
+ from strands_code_agent import CodeAgent
41
+
42
+ agent = CodeAgent(system_prompt="You are a helpful data analyst.")
43
+
44
+ response = agent("What is 2 ** 10?")
45
+ ```
46
+
47
+ The agent receives a `python_repl` tool automatically and solves tasks by writing and executing Python code.
48
+
49
+ ## CodeAgent
50
+
51
+ `CodeAgent` extends the Strands `Agent` with a built-in Python REPL and automatic system-prompt enrichment.
52
+
53
+ | Parameter | Type | Description |
54
+ |---|---|---|
55
+ | `system_prompt` | `str \| None` | Base system prompt, extended with coding instructions. |
56
+ | `tools` | `list \| None` | Additional tools alongside the built-in Python REPL. |
57
+ | `toolkits` | `list[Toolkit] \| None` | Toolkits that configure the REPL environment (see below). |
58
+ | `tmp_dir` | `bool` | If `True` (default), creates a temp directory and documents its path in the prompt. |
59
+ | `python_interpreter_class` | `type[PythonInterpreter]` | The interpreter backend. Defaults to `SandboxedPythonInterpreter` (import restrictions via allowlist). Use `ExecPythonInterpreter` for lightweight unrestricted `exec()`-based execution. |
60
+ | `**kwargs` | | Forwarded to the Strands `Agent` base class (e.g. `model`, `callback_handler`). |
61
+
62
+ ## Toolkit
63
+
64
+ A `Toolkit` bundles everything the REPL needs for a specific domain. Each field influences the `CodeAgent` in a specific way:
65
+
66
+ | Parameter | Type | Effect on `PythonInterpreter` | Effect on System Prompt |
67
+ |---|---|---|---|
68
+ | `libraries` | `list[str] \| None` | Added to `authorized_imports` — the REPL will only allow imports from this allowlist. | — |
69
+ | `initialization_code` | `str \| None` | Prepended to `state_initialization` — runs before every Agent snippet. | Documented so the agent knows which symbols are pre-loaded. |
70
+ | `usage_instructions` | `str \| None` | — | Appended as-is, giving the agent guidance on how to use the libraries. |
71
+ | `domain_specific_code` | `list \| None` | Auto-imported in `state_initialization` (modules added to `authorized_imports`). | Full signature + docstring of each symbol is documented so the agent can use them. |
72
+
73
+ ### Example
74
+
75
+ ```python
76
+ from strands_code_agent.toolkits import Toolkit
77
+
78
+ VISUALIZATION_TOOLKIT = Toolkit(
79
+ # 1. libraries → PythonInterpreter.authorized_imports
80
+ # Allows the REPL to import these modules.
81
+ # Use "module.*" to allow a module and all its submodules.
82
+ libraries=["matplotlib.*", "seaborn.*"],
83
+
84
+ # 2. initialization_code → PythonInterpreter.state_initialization + System Prompt
85
+ # Runs before user code; also shown in the prompt so the agent
86
+ # knows plt and sns are already available.
87
+ initialization_code="""
88
+ import matplotlib
89
+ matplotlib.use('Agg') # Use non-interactive backend
90
+ import matplotlib.pyplot as plt
91
+ import seaborn as sns
92
+ """,
93
+
94
+ # 3. usage_instructions → System Prompt only
95
+ # Tells the agent how to behave with these libraries.
96
+ usage_instructions="Do not try to show any matplotlib image: the python_repl tool executes the code in a sub-process without a GUI.",
97
+ )
98
+ ```
99
+
100
+ ### Built-in Toolkits
101
+
102
+ The library ships with ready-to-use toolkits:
103
+
104
+ ```python
105
+ from strands_code_agent.toolkits import (
106
+ VISUALIZATION_TOOLKIT, # matplotlib + seaborn (non-interactive backend)
107
+ DATA_ANALYSIS_TOOLKIT, # numpy + pandas + scipy + datetime
108
+ )
109
+ ```
110
+
111
+ ### Domain-Specific Code
112
+
113
+ Pass your own functions or classes via `domain_specific_code`. The `CodeAgent` will:
114
+
115
+ 1. **Auto-import** them in `PythonInterpreter.state_initialization` (their modules are added to `authorized_imports`).
116
+ 2. **Document** each symbol's full signature and docstring in the **System Prompt**, so the agent knows how to call them.
117
+
118
+ ```python
119
+ from strands_code_agent import CodeAgent, Toolkit
120
+
121
+ def calculate_roi(investment: float, returns: float) -> float:
122
+ """Calculate return on investment as a percentage."""
123
+ return (returns - investment) / investment * 100
124
+
125
+
126
+ agent = CodeAgent(
127
+ system_prompt="You are a finance assistant.",
128
+ toolkits=[
129
+ Toolkit(domain_specific_code=[calculate_roi])
130
+ ],
131
+ )
132
+
133
+ response = agent("What is the ROI if I invest 1000 and get back 1250?")
134
+ ```
135
+
136
+ ### Combining Toolkits
137
+
138
+ ```python
139
+ from strands_code_agent import CodeAgent
140
+ from strands_code_agent.toolkits import DATA_ANALYSIS_TOOLKIT, VISUALIZATION_TOOLKIT
141
+
142
+ agent = CodeAgent(
143
+ system_prompt="You are a data analyst.",
144
+ toolkits=[DATA_ANALYSIS_TOOLKIT, VISUALIZATION_TOOLKIT],
145
+ )
146
+ ```
147
+
148
+ ## Running Tests
149
+
150
+ The test suite uses [pytest](https://docs.pytest.org/). Install it and run from the project root:
151
+
152
+ ```bash
153
+ pip install pytest
154
+ python -m pytest tests/ -v
155
+ ```
156
+
157
+ ## Security
158
+
159
+ See [CONTRIBUTING](CONTRIBUTING.md#security-issue-notifications) for more information.
160
+
161
+ ## License
162
+
163
+ This library is licensed under the MIT-0 License. See the LICENSE file.
@@ -0,0 +1,14 @@
1
+ strands_code_agent/__init__.py,sha256=roto57kfvRbs3o_mug5acxv5o-6I15EV3OePxd6YLcI,136
2
+ strands_code_agent/code_agent.py,sha256=9fVA3PG3KuAczciulhpGxZL2GH7FpqL7t5h8jZqGZtw,6414
3
+ strands_code_agent/document_code.py,sha256=s8VAI7rLk8T-fZ5RGYwJSAE8NhnY0kNdQe6jnRVMCfY,2065
4
+ strands_code_agent/imports.py,sha256=KYVgl7VTq9OQhzMDFEe2OgdKy144tS3NshK5QAOgW7Y,1238
5
+ strands_code_agent/toolkits.py,sha256=eo2apEyQ3NWCWYmisiN45uTLeDacnw61h_sDnfXhSl8,1444
6
+ strands_code_agent/utils.py,sha256=YfRND-jJoNl3jX3hv_O7t5V8RAsDgy8GUtfixq2e2qs,230
7
+ strands_code_agent/python_environments/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
8
+ strands_code_agent/python_environments/base.py,sha256=S5FAhCKmN4wpxAveRjsb1VQ75vfgCG0_tP_Me_5T1cI,1344
9
+ strands_code_agent/python_environments/local_exec.py,sha256=fK9Xh830NvMDy7gMkSDc617WSzQ3BzsWvsmeOPbBLMA,1092
10
+ strands_code_agent/python_environments/local_sandboxed.py,sha256=wvVY-I5Y0zgMqja7uSi4M6WfQiCW4NAiInimW3ABJP8,2667
11
+ strands_code_agent-0.1.0.dist-info/METADATA,sha256=x5-ea4zYve9xrbuZL2WXlhli34HiZ_549ELr5nICgtc,7033
12
+ strands_code_agent-0.1.0.dist-info/WHEEL,sha256=QccIxa26bgl1E6uMy58deGWi-0aeIkkangHcxk2kWfw,87
13
+ strands_code_agent-0.1.0.dist-info/licenses/LICENSE,sha256=fLdQcTJS79HVeIN7qHhbYTGRCZBvDBC4etq3z0ut_EI,947
14
+ strands_code_agent-0.1.0.dist-info/RECORD,,
@@ -0,0 +1,4 @@
1
+ Wheel-Version: 1.0
2
+ Generator: hatchling 1.29.0
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
@@ -0,0 +1,17 @@
1
+ MIT No Attribution
2
+
3
+ Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy of
6
+ this software and associated documentation files (the "Software"), to deal in
7
+ the Software without restriction, including without limitation the rights to
8
+ use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
9
+ the Software, and to permit persons to whom the Software is furnished to do so.
10
+
11
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
12
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
13
+ FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
14
+ COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
15
+ IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
16
+ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
17
+