agent-framework-ep 0.1.0__tar.gz

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.
Files changed (22) hide show
  1. agent_framework_ep-0.1.0/.gitignore +219 -0
  2. agent_framework_ep-0.1.0/AGENTS.md +272 -0
  3. agent_framework_ep-0.1.0/LICENSE +21 -0
  4. agent_framework_ep-0.1.0/PKG-INFO +160 -0
  5. agent_framework_ep-0.1.0/README.md +131 -0
  6. agent_framework_ep-0.1.0/pyproject.toml +91 -0
  7. agent_framework_ep-0.1.0/src/agent_framework_ep/__init__.py +44 -0
  8. agent_framework_ep-0.1.0/src/agent_framework_ep/code_executor/__init__.py +51 -0
  9. agent_framework_ep-0.1.0/src/agent_framework_ep/code_executor/base.py +168 -0
  10. agent_framework_ep-0.1.0/src/agent_framework_ep/code_executor/docker/__init__.py +3 -0
  11. agent_framework_ep-0.1.0/src/agent_framework_ep/code_executor/docker/executor.py +468 -0
  12. agent_framework_ep-0.1.0/src/agent_framework_ep/openai_like/__init__.py +83 -0
  13. agent_framework_ep-0.1.0/src/agent_framework_ep/openai_like/_exceptions.py +33 -0
  14. agent_framework_ep-0.1.0/src/agent_framework_ep/openai_like/_reasoning_content.py +122 -0
  15. agent_framework_ep-0.1.0/src/agent_framework_ep/openai_like/_response_format.py +129 -0
  16. agent_framework_ep-0.1.0/src/agent_framework_ep/skills_provider/__init__.py +3 -0
  17. agent_framework_ep-0.1.0/src/agent_framework_ep/skills_provider/updatable_skills_provider.py +119 -0
  18. agent_framework_ep-0.1.0/tests/__init__.py +0 -0
  19. agent_framework_ep-0.1.0/tests/code_executor/__init__.py +0 -0
  20. agent_framework_ep-0.1.0/tests/code_executor/test_base.py +241 -0
  21. agent_framework_ep-0.1.0/tests/code_executor/test_docker_executor.py +306 -0
  22. agent_framework_ep-0.1.0/tests/conftest.py +8 -0
@@ -0,0 +1,219 @@
1
+ # Byte-compiled / optimized / DLL files
2
+ __pycache__/
3
+ *.py[codz]
4
+ *$py.class
5
+
6
+ # C extensions
7
+ *.so
8
+
9
+ # Distribution / packaging
10
+ .Python
11
+ build/
12
+ develop-eggs/
13
+ dist/
14
+ downloads/
15
+ eggs/
16
+ .eggs/
17
+ lib/
18
+ lib64/
19
+ parts/
20
+ sdist/
21
+ var/
22
+ wheels/
23
+ share/python-wheels/
24
+ *.egg-info/
25
+ .installed.cfg
26
+ *.egg
27
+ MANIFEST
28
+
29
+ # PyInstaller
30
+ # Usually these files are written by a python script from a template
31
+ # before PyInstaller builds the exe, so as to inject date/other infos into it.
32
+ *.manifest
33
+ *.spec
34
+
35
+ # Installer logs
36
+ pip-log.txt
37
+ pip-delete-this-directory.txt
38
+
39
+ # Unit test / coverage reports
40
+ htmlcov/
41
+ .tox/
42
+ .nox/
43
+ .coverage
44
+ .coverage.*
45
+ .cache
46
+ nosetests.xml
47
+ coverage.xml
48
+ *.cover
49
+ *.py.cover
50
+ .hypothesis/
51
+ .pytest_cache/
52
+ cover/
53
+
54
+ # Translations
55
+ *.mo
56
+ *.pot
57
+
58
+ # Django stuff:
59
+ *.log
60
+ local_settings.py
61
+ db.sqlite3
62
+ db.sqlite3-journal
63
+
64
+ # Flask stuff:
65
+ instance/
66
+ .webassets-cache
67
+
68
+ # Scrapy stuff:
69
+ .scrapy
70
+
71
+ # Sphinx documentation
72
+ docs/_build/
73
+
74
+ # PyBuilder
75
+ .pybuilder/
76
+ target/
77
+
78
+ # Jupyter Notebook
79
+ .ipynb_checkpoints
80
+
81
+ # IPython
82
+ profile_default/
83
+ ipython_config.py
84
+
85
+ # pyenv
86
+ # For a library or package, you might want to ignore these files since the code is
87
+ # intended to run in multiple environments; otherwise, check them in:
88
+ # .python-version
89
+
90
+ # pipenv
91
+ # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
92
+ # However, in case of collaboration, if having platform-specific dependencies or dependencies
93
+ # having no cross-platform support, pipenv may install dependencies that don't work, or not
94
+ # install all needed dependencies.
95
+ #Pipfile.lock
96
+
97
+ # UV
98
+ # Similar to Pipfile.lock, it is generally recommended to include uv.lock in version control.
99
+ # This is especially recommended for binary packages to ensure reproducibility, and is more
100
+ # commonly ignored for libraries.
101
+ # Since this is a library package (agent-framework-ep), we ignore uv.lock
102
+ uv.lock
103
+
104
+ # poetry
105
+ # Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
106
+ # This is especially recommended for binary packages to ensure reproducibility, and is more
107
+ # commonly ignored for libraries.
108
+ # https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
109
+ #poetry.lock
110
+ #poetry.toml
111
+
112
+ # pdm
113
+ # Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
114
+ # pdm recommends including project-wide configuration in pdm.toml, but excluding .pdm-python.
115
+ # https://pdm-project.org/en/latest/usage/project/#working-with-version-control
116
+ #pdm.lock
117
+ #pdm.toml
118
+ .pdm-python
119
+ .pdm-build/
120
+
121
+ # pixi
122
+ # Similar to Pipfile.lock, it is generally recommended to include pixi.lock in version control.
123
+ #pixi.lock
124
+ # Pixi creates a virtual environment in the .pixi directory, just like venv module creates one
125
+ # in the .venv directory. It is recommended not to include this directory in version control.
126
+ .pixi
127
+
128
+ # PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
129
+ __pypackages__/
130
+
131
+ # Celery stuff
132
+ celerybeat-schedule
133
+ celerybeat.pid
134
+
135
+ # SageMath parsed files
136
+ *.sage.py
137
+
138
+ # Environments
139
+ .env
140
+ .envrc
141
+ .venv
142
+ env/
143
+ venv/
144
+ ENV/
145
+ env.bak/
146
+ venv.bak/
147
+
148
+ # Spyder project settings
149
+ .spyderproject
150
+ .spyproject
151
+
152
+ # Rope project settings
153
+ .ropeproject
154
+
155
+ # mkdocs documentation
156
+ /site
157
+
158
+ # mypy
159
+ .mypy_cache/
160
+ .dmypy.json
161
+ dmypy.json
162
+
163
+ # Pyre type checker
164
+ .pyre/
165
+
166
+ # pytype static type analyzer
167
+ .pytype/
168
+
169
+ # Cython debug symbols
170
+ cython_debug/
171
+
172
+ # PyCharm
173
+ # JetBrains specific template is maintained in a separate JetBrains.gitignore that can
174
+ # be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
175
+ # and can be added to the global gitignore or merged into this file. For a more nuclear
176
+ # option (not recommended) you can uncomment the following to ignore the entire idea folder.
177
+ .idea/
178
+
179
+ # Abstra
180
+ # Abstra is an AI-powered process automation framework.
181
+ # Ignore directories containing user credentials, local state, and settings.
182
+ # Learn more at https://abstra.io/docs
183
+ .abstra/
184
+
185
+ # Visual Studio Code
186
+ # Visual Studio Code specific template is maintained in a separate VisualStudioCode.gitignore
187
+ # that can be found at https://github.com/github/gitignore/blob/main/Global/VisualStudioCode.gitignore
188
+ # and can be added to the global gitignore or merged into this file. However, if you prefer,
189
+ # you could uncomment the following to ignore the entire vscode folder
190
+ # .vscode/
191
+
192
+ # Ruff stuff:
193
+ .ruff_cache/
194
+
195
+ # PyPI configuration file
196
+ .pypirc
197
+
198
+ # Cursor
199
+ # Cursor is an AI-powered code editor. `.cursorignore` specifies files/directories to
200
+ # exclude from AI features like autocomplete and code analysis. Recommended for sensitive data
201
+ # refer to https://docs.cursor.com/context/ignore-files
202
+ .cursorignore
203
+ .cursorindexingignore
204
+
205
+ # Marimo
206
+ marimo/_static/
207
+ marimo/_lsp/
208
+ __marimo__/
209
+
210
+ # Project specific: Code Executor
211
+ # Temporary execution directories and sandbox files
212
+ tmp_exec/
213
+ sandbox/
214
+ *.sandbox
215
+ .exec_cache/
216
+
217
+ # Docker/container artifacts for code execution
218
+ .dockerignore
219
+ container_tmp/
@@ -0,0 +1,272 @@
1
+ # AGENTS.md - Agentic Coding Guidelines
2
+
3
+ > This file guides AI coding agents working in the `agent-framework-ep` repository.
4
+
5
+ ## Project Overview
6
+
7
+ Microsoft Agent Framework extensions for mainstream open-source LLMs (GLM, Kimi, Qwen, DeepSeek) with structured output support, reasoning_content support, and local containerized code interpreter environment.
8
+
9
+ - **Package Name**: `agent-framework-ep`
10
+ - **Package Manager**: uv
11
+ - **Target Python**: 3.12+
12
+
13
+ ---
14
+
15
+ ## Important Note
16
+
17
+ **Always prioritize retrieval-guided reasoning over pre-training-guided reasoning in any coding task.**
18
+
19
+ When implementing features or fixing bugs, actively search the codebase for existing patterns, conventions, and implementations rather than relying solely on general knowledge. Use `grep`, `glob`, and `read` tools to discover:
20
+
21
+ - How similar features are already implemented
22
+ - Existing naming conventions and patterns
23
+ - Test patterns and fixtures
24
+ - Error handling approaches
25
+ - Import organization styles
26
+
27
+ This ensures consistency with the existing codebase and prevents introducing divergent patterns.
28
+
29
+ ---
30
+
31
+ ## Build / Lint / Test Commands
32
+
33
+ ```bash
34
+ # Install dependencies
35
+ uv sync
36
+
37
+ # Run all tests
38
+ uv run pytest
39
+
40
+ # Run a single test (examples)
41
+ uv run pytest tests/test_module.py
42
+ uv run pytest tests/test_module.py::test_function_name
43
+ uv run pytest tests/ -k "test_pattern"
44
+
45
+ # Run with coverage
46
+ uv run pytest --cov=agent_framework_ep --cov-report=term-missing
47
+
48
+ # Lint and auto-fix
49
+ uv run ruff check --fix .
50
+
51
+ # Format code
52
+ uv run ruff format .
53
+
54
+ # Type check
55
+ uv run mypy src/agent_framework_ep
56
+
57
+ # Build package for PyPI
58
+ uv build
59
+
60
+ # Publish to PyPI
61
+ uv publish
62
+ ```
63
+
64
+ ---
65
+
66
+ ## Code Style Guidelines
67
+
68
+ ### Type Hints (Python 3.12+)
69
+
70
+ - Use modern syntax: `list[str]`, `dict[str, int]`, `str | None` (not `Optional[str]`)
71
+ - Use type parameter syntax: `def func[T](args: list[T]) -> T` (not `TypeVar`)
72
+ - Use `@override` decorator when overriding methods
73
+ - Annotate all public functions and methods
74
+
75
+ ```python
76
+ # Good
77
+ async def get_model_response[T](models: list[T]) -> T | None:
78
+ ...
79
+
80
+ # Bad
81
+ from typing import List, Optional, TypeVar
82
+ T = TypeVar("T")
83
+ async def get_model_response(models: List[T]) -> Optional[T]:
84
+ ...
85
+ ```
86
+
87
+ ### Imports
88
+
89
+ ```python
90
+ # Standard library
91
+ import asyncio
92
+ from collections.abc import Callable, Iterator
93
+ from pathlib import Path
94
+
95
+ # Third-party (alphabetical)
96
+ import httpx
97
+ from pydantic import BaseModel, field_validator
98
+
99
+ # Local (absolute only)
100
+ from agent_framework_ep.models import LLMResponse
101
+ ```
102
+
103
+ - Use `from collections.abc import ...` (not `from typing import ...`)
104
+ - **Never use relative imports** (`from .module import X`)
105
+ - Group: stdlib → third-party → local, separated by blank lines
106
+
107
+ ### Naming Conventions
108
+
109
+ | Element | Convention | Example |
110
+ |---------|------------|---------|
111
+ | Modules/Files | `snake_case` | `model_provider.py` |
112
+ | Classes | `PascalCase` | `StructuredOutputParser` |
113
+ | Functions | `snake_case` | `parse_reasoning_content()` |
114
+ | Constants | `SCREAMING_SNAKE_CASE` | `DEFAULT_TIMEOUT_SECONDS` |
115
+ | Private | `_leading_underscore` | `_internal_helper()` |
116
+
117
+ ### Formatting
118
+
119
+ - Line length: 120 characters
120
+ - Use double quotes for strings
121
+ - Trailing commas in multi-line structures
122
+ - Use ruff for both linting and formatting
123
+
124
+ ### Pydantic (v2 only)
125
+
126
+ ```python
127
+ from pydantic import BaseModel, field_validator, model_validator, ConfigDict
128
+
129
+ class StructuredOutput(BaseModel):
130
+ model_config = ConfigDict(strict=True)
131
+
132
+ content: str
133
+ reasoning: str | None = None
134
+
135
+ @field_validator("content")
136
+ @classmethod
137
+ def validate_content(cls, v: str) -> str:
138
+ return v.strip()
139
+
140
+ @model_validator(mode="after")
141
+ def check_consistency(self) -> "StructuredOutput":
142
+ if self.reasoning and not self.content:
143
+ raise ValueError("Cannot have reasoning without content")
144
+ return self
145
+ ```
146
+
147
+ - Use `model_config = ConfigDict(...)` (not inner `class Config`)
148
+ - Use `@field_validator` (not `@validator`)
149
+ - Use `@model_validator` (not `@root_validator`)
150
+
151
+ ### Error Handling
152
+
153
+ ```python
154
+ # Prefer specific exceptions
155
+ from agent_framework_ep.exceptions import LLMProviderError, StructuredOutputError
156
+
157
+ # Use match/case for error classification (Python 3.10+)
158
+ match error:
159
+ case httpx.TimeoutException():
160
+ raise LLMProviderError("Request timed out") from error
161
+ case httpx.HTTPStatusError() if error.response.status_code == 429:
162
+ raise LLMProviderError("Rate limited") from error
163
+ case _:
164
+ raise LLMProviderError(f"Unexpected error: {error}") from error
165
+ ```
166
+
167
+ ### Async Patterns (Python 3.11+)
168
+
169
+ ```python
170
+ # Use TaskGroup (not asyncio.gather)
171
+ async with asyncio.TaskGroup() as tg:
172
+ t1 = tg.create_task(fetch_glm_response())
173
+ t2 = tg.create_task(fetch_kimi_response())
174
+ results = (t1.result(), t2.result())
175
+ ```
176
+
177
+ ### Docstrings
178
+
179
+ Use Google-style docstrings:
180
+
181
+ ```python
182
+ def parse_structured_output(
183
+ raw_response: str,
184
+ schema: type[T],
185
+ ) -> T:
186
+ """Parse LLM response into structured output.
187
+
188
+ Args:
189
+ raw_response: Raw text response from LLM.
190
+ schema: Pydantic model class defining the output structure.
191
+
192
+ Returns:
193
+ Instance of the schema class with parsed data.
194
+
195
+ Raises:
196
+ StructuredOutputError: If response cannot be parsed to schema.
197
+
198
+ Example:
199
+ >>> output = parse_structured_output('{"name": "test"}', UserSchema)
200
+ >>> output.name
201
+ 'test'
202
+ """
203
+ ...
204
+ ```
205
+
206
+ ### Project Structure
207
+
208
+ ```
209
+ src/agent_framework_ep/
210
+ ├── __init__.py # Public API exports
211
+ ├── code_executor/ # Containerized code execution
212
+ │ ├── base.py # CodeExecutor ABC, CodeBlock, CancellationToken
213
+ │ └── docker/
214
+ │ └── executor.py # DockerCommandLineCodeExecutor
215
+ ├── openai_like/ # OpenAI-compatible client with extensions
216
+ │ ├── _exceptions.py # StructuredOutputParseError
217
+ │ ├── _reasoning_content.py # ReasoningContentMixin (DeepSeek-R1 support)
218
+ │ └── _response_format.py # ResponseFormatMixin (structured output)
219
+ └── skills_provider/
220
+ └── updatable_skills_provider.py # Dynamic skills updater
221
+
222
+ tests/
223
+ ├── conftest.py # pytest fixtures and markers
224
+ └── code_executor/ # Tests for code execution
225
+ ├── test_base.py
226
+ └── test_docker_executor.py
227
+ ```
228
+
229
+ ### Module Descriptions
230
+
231
+ | Module | Purpose |
232
+ |--------|---------|
233
+ | `code_executor` | Execute code in isolated Docker containers. Supports Python, bash, and shell scripts with timeout and cancellation. |
234
+ | `openai_like` | Extended OpenAI client with structured output parsing (JSON fallback) and reasoning_content support for DeepSeek-R1 style models. |
235
+ | `skills_provider` | Dynamic skills provider that can update skills asynchronously before each agent run. |
236
+
237
+ ### File Conventions
238
+
239
+ - Define `__all__` in every module to export public API
240
+ - Keep files under 400 lines; split when growing larger
241
+ - One class per file unless tightly coupled
242
+ - Use `pathlib.Path` (not `os.path`)
243
+ - Use f-strings (not `.format()` or `%`)
244
+
245
+ ---
246
+
247
+ ## Testing
248
+
249
+ ```python
250
+ # Use pytest with fixtures
251
+ import pytest
252
+ from agent_framework_ep import DockerCommandLineCodeExecutor, CodeBlock, CancellationToken
253
+
254
+ @pytest.fixture
255
+ async def executor():
256
+ async with DockerCommandLineCodeExecutor(image="python-code-sandbox") as exec:
257
+ yield exec
258
+
259
+ async def test_code_execution(executor):
260
+ result = await executor.execute_code_blocks(
261
+ [CodeBlock(code="print('hello')", language="python")],
262
+ CancellationToken()
263
+ )
264
+ assert result.exit_code == 0
265
+ assert "hello" in result.output
266
+ ```
267
+
268
+ ---
269
+
270
+ ## No Cursor/Copilot Rules
271
+
272
+ There are no existing `.cursorrules` or `.github/copilot-instructions.md` files in this repository.
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Peng Qian
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,160 @@
1
+ Metadata-Version: 2.4
2
+ Name: agent-framework-ep
3
+ Version: 0.1.0
4
+ Summary: Microsoft Agent Framework extensions for mainstream open-source LLMs
5
+ Project-URL: Repository, https://github.com/qianpeng/agent-framework-ep
6
+ Author-email: Peng Qian <qianpeng@example.com>
7
+ License: MIT
8
+ License-File: LICENSE
9
+ Classifier: Development Status :: 4 - Beta
10
+ Classifier: Intended Audience :: Developers
11
+ Classifier: License :: OSI Approved :: MIT License
12
+ Classifier: Programming Language :: Python :: 3
13
+ Classifier: Programming Language :: Python :: 3.12
14
+ Classifier: Programming Language :: Python :: 3.13
15
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
16
+ Requires-Python: >=3.12
17
+ Requires-Dist: agent-framework>=1.0.0rc5
18
+ Requires-Dist: dirtyjson>=0.0.0
19
+ Requires-Dist: docker>=7.0
20
+ Requires-Dist: json-repair>=0.0.0
21
+ Provides-Extra: dev
22
+ Requires-Dist: httpx>=0.27; extra == 'dev'
23
+ Requires-Dist: mypy>=1.8; extra == 'dev'
24
+ Requires-Dist: pytest-asyncio>=0.23; extra == 'dev'
25
+ Requires-Dist: pytest-cov>=4.0; extra == 'dev'
26
+ Requires-Dist: pytest>=8.0; extra == 'dev'
27
+ Requires-Dist: ruff>=0.3; extra == 'dev'
28
+ Description-Content-Type: text/markdown
29
+
30
+ # agent-framework-ep
31
+
32
+ Microsoft Agent Framework extensions for mainstream open-source LLMs, including structured output support for GLM, Kimi, Qwen, and DeepSeek, along with reasoning_content support. Plus a local containerized code interpreter environment. 'ep' stands for enterprise-level applications.
33
+
34
+ ## Features
35
+
36
+ - **OpenAI-like Client Extensions** (`openai_like`)
37
+ - Structured output parsing with JSON fallback (dirtyjson, json-repair)
38
+ - Reasoning content support for DeepSeek-R1 style models
39
+ - Compatible with Microsoft Agent Framework's OpenAIChatClient
40
+
41
+ - **Code Executor** (`code_executor`)
42
+ - Docker-based code execution environment
43
+ - Supports Python, bash, and shell scripts
44
+ - Timeout and cancellation support
45
+ - Isolated execution for security
46
+
47
+ - **Dynamic Skills Provider** (`skills_provider`)
48
+ - Async skill updates before each agent run
49
+ - Extendable skills from external sources
50
+
51
+ ## Installation
52
+
53
+ ```bash
54
+ pip install agent-framework-ep
55
+ ```
56
+
57
+ Or with uv:
58
+
59
+ ```bash
60
+ uv add agent-framework-ep
61
+ ```
62
+
63
+ ### Prerequisites
64
+
65
+ - Python 3.12+
66
+ - Docker (for code execution features)
67
+
68
+ ## Quick Start
69
+
70
+ ### OpenAI-like Client with Structured Output
71
+
72
+ ```python
73
+ from pydantic import BaseModel
74
+ from agent_framework import Agent
75
+ from agent_framework_ep import OpenAILikeChatClient
76
+
77
+ class Response(BaseModel):
78
+ answer: str
79
+ confidence: float
80
+
81
+ # Create client with structured output support
82
+ client = OpenAILikeChatClient(
83
+ model="deepseek-chat",
84
+ api_key="your-api-key"
85
+ )
86
+
87
+ # Use with Agent framework
88
+ agent = Agent(client=client)
89
+ response = await agent.run(
90
+ "What is the capital of France?",
91
+ response_format=Response
92
+ )
93
+ print(response.result) # Parsed Response object
94
+ ```
95
+
96
+ ### Code Execution
97
+
98
+ ```python
99
+ import asyncio
100
+ from agent_framework_ep import DockerCommandLineCodeExecutor, CodeBlock, CancellationToken
101
+
102
+ async def main():
103
+ async with DockerCommandLineCodeExecutor(
104
+ image="python-code-sandbox"
105
+ ) as executor:
106
+ result = await executor.execute_code_blocks(
107
+ [CodeBlock(code="print('Hello, World!')", language="python")],
108
+ CancellationToken()
109
+ )
110
+ print(result.output) # Hello, World!
111
+ print(result.exit_code) # 0
112
+
113
+ asyncio.run(main())
114
+ ```
115
+
116
+ ### Dynamic Skills Provider
117
+
118
+ ```python
119
+ from agent_framework_ep import UpdatableSkillsProvider
120
+ from agent_framework import Skill
121
+
122
+ async def fetch_dynamic_skills():
123
+ # Fetch skills from external source
124
+ return [
125
+ Skill(name="web-search", description="Search the web", content="..."),
126
+ ]
127
+
128
+ provider = UpdatableSkillsProvider(
129
+ skill_paths="./skills",
130
+ skills_updater=fetch_dynamic_skills
131
+ )
132
+ ```
133
+
134
+ ## Development
135
+
136
+ ```bash
137
+ # Clone the repository
138
+ git clone https://github.com/qianpeng/agent-framework-ep.git
139
+ cd agent-framework-ep
140
+
141
+ # Install dependencies
142
+ uv sync
143
+
144
+ # Run tests
145
+ uv run pytest
146
+
147
+ # Run tests with Docker (requires Docker)
148
+ uv run pytest -m docker
149
+
150
+ # Lint and format
151
+ uv run ruff check --fix .
152
+ uv run ruff format .
153
+
154
+ # Type check
155
+ uv run mypy src/agent_framework_ep
156
+ ```
157
+
158
+ ## License
159
+
160
+ MIT License - see [LICENSE](LICENSE) for details.