agentflowkit 0.1.0__tar.gz → 0.5.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.
- agentflowkit-0.5.0/.coverage +0 -0
- agentflowkit-0.5.0/.github/ISSUE_TEMPLATE/bug_report.md +43 -0
- agentflowkit-0.5.0/.github/ISSUE_TEMPLATE/feature_request.md +29 -0
- agentflowkit-0.5.0/.github/workflows/ci.yml +81 -0
- agentflowkit-0.5.0/.github/workflows/docs.yml +32 -0
- agentflowkit-0.5.0/.github/workflows/publish.yml +33 -0
- agentflowkit-0.5.0/.gitignore +21 -0
- agentflowkit-0.5.0/AUDIT_REPORT.md +137 -0
- agentflowkit-0.5.0/CHANGELOG.md +111 -0
- agentflowkit-0.5.0/CMakeLists.txt +30 -0
- agentflowkit-0.5.0/CONTRIBUTING.md +99 -0
- agentflowkit-0.5.0/PASS2_RESOLUTION_REPORT.md +261 -0
- agentflowkit-0.5.0/PKG-INFO +430 -0
- agentflowkit-0.5.0/README.md +388 -0
- agentflowkit-0.5.0/benchmarks/parallel_speedup.py +71 -0
- agentflowkit-0.5.0/docs/getting-started.md +83 -0
- agentflowkit-0.5.0/docs/guides/cost-streaming.md +48 -0
- agentflowkit-0.5.0/docs/guides/memory.md +195 -0
- agentflowkit-0.5.0/docs/guides/observability.md +52 -0
- agentflowkit-0.5.0/docs/guides/tools.md +58 -0
- agentflowkit-0.5.0/docs/index.md +42 -0
- agentflowkit-0.5.0/docs/reference.md +49 -0
- {agentflowkit-0.1.0 → agentflowkit-0.5.0}/examples/code_reviewer.py +1 -2
- agentflowkit-0.5.0/examples/cpp_build_pipeline.py +293 -0
- agentflowkit-0.5.0/examples/drone_telemetry_agent.py +168 -0
- agentflowkit-0.5.0/examples/market_analysis_crew.py +258 -0
- agentflowkit-0.5.0/examples/memory_chat_agents.py +172 -0
- agentflowkit-0.5.0/examples/notebooks/parallel_execution_demo.ipynb +292 -0
- agentflowkit-0.5.0/examples/notebooks/quickstart.ipynb +269 -0
- {agentflowkit-0.1.0 → agentflowkit-0.5.0}/examples/research_crew.py +2 -3
- agentflowkit-0.5.0/examples/research_react_agent.py +146 -0
- agentflowkit-0.5.0/examples/robotics_mqtt_agent.py +114 -0
- agentflowkit-0.5.0/examples/streaming_and_cost.py +52 -0
- agentflowkit-0.5.0/examples/tool_agent.py +66 -0
- agentflowkit-0.5.0/mkdocs.yml +66 -0
- agentflowkit-0.5.0/pyproject.toml +85 -0
- agentflowkit-0.5.0/src/agentflow/__init__.py +95 -0
- agentflowkit-0.5.0/src/agentflow/agent.py +536 -0
- agentflowkit-0.5.0/src/agentflow/cache.py +143 -0
- agentflowkit-0.5.0/src/agentflow/cpp_core/bindings.cpp +36 -0
- agentflowkit-0.5.0/src/agentflow/cpp_core/dag_engine.cpp +105 -0
- agentflowkit-0.5.0/src/agentflow/cpp_core/dag_engine.h +22 -0
- agentflowkit-0.5.0/src/agentflow/distillation.py +160 -0
- agentflowkit-0.5.0/src/agentflow/events.py +254 -0
- agentflowkit-0.5.0/src/agentflow/exceptions.py +45 -0
- agentflowkit-0.5.0/src/agentflow/hitl.py +155 -0
- agentflowkit-0.5.0/src/agentflow/llm.py +248 -0
- agentflowkit-0.5.0/src/agentflow/logging.py +131 -0
- agentflowkit-0.5.0/src/agentflow/memory.py +478 -0
- agentflowkit-0.5.0/src/agentflow/observability.py +91 -0
- agentflowkit-0.5.0/src/agentflow/pipeline.py +729 -0
- agentflowkit-0.5.0/src/agentflow/pricing.py +57 -0
- agentflowkit-0.5.0/src/agentflow/py.typed +0 -0
- agentflowkit-0.5.0/src/agentflow/rate_limiter.py +86 -0
- agentflowkit-0.5.0/src/agentflow/sandbox.py +557 -0
- agentflowkit-0.5.0/src/agentflow/swarm.py +262 -0
- agentflowkit-0.5.0/src/agentflow/swarm_routing.py +321 -0
- agentflowkit-0.5.0/src/agentflow/tools.py +154 -0
- agentflowkit-0.5.0/src/agentflow/triggers.py +127 -0
- agentflowkit-0.5.0/src/agentflow/types.py +68 -0
- {agentflowkit-0.1.0 → agentflowkit-0.5.0}/tests/test_agent.py +1 -1
- agentflowkit-0.5.0/tests/test_cache.py +140 -0
- agentflowkit-0.5.0/tests/test_conditional.py +124 -0
- agentflowkit-0.5.0/tests/test_hitl.py +679 -0
- {agentflowkit-0.1.0 → agentflowkit-0.5.0}/tests/test_llm.py +0 -2
- agentflowkit-0.5.0/tests/test_logging.py +72 -0
- agentflowkit-0.5.0/tests/test_long_term_memory.py +440 -0
- agentflowkit-0.5.0/tests/test_memory.py +264 -0
- agentflowkit-0.5.0/tests/test_observability.py +99 -0
- agentflowkit-0.5.0/tests/test_parallel.py +242 -0
- {agentflowkit-0.1.0 → agentflowkit-0.5.0}/tests/test_pipeline.py +3 -5
- agentflowkit-0.5.0/tests/test_pricing.py +36 -0
- agentflowkit-0.5.0/tests/test_rate_limiter.py +57 -0
- agentflowkit-0.5.0/tests/test_retry.py +46 -0
- agentflowkit-0.5.0/tests/test_sandbox.py +466 -0
- agentflowkit-0.5.0/tests/test_streaming.py +54 -0
- agentflowkit-0.5.0/tests/test_swarm.py +419 -0
- agentflowkit-0.5.0/tests/test_swarm_routing.py +525 -0
- agentflowkit-0.5.0/tests/test_tools.py +231 -0
- agentflowkit-0.5.0/tests/test_triggers.py +386 -0
- agentflowkit-0.5.0/uv.lock +4179 -0
- agentflowkit-0.1.0/.gitignore +0 -11
- agentflowkit-0.1.0/PKG-INFO +0 -177
- agentflowkit-0.1.0/README.md +0 -149
- agentflowkit-0.1.0/pyproject.toml +0 -46
- agentflowkit-0.1.0/src/agentflow/__init__.py +0 -25
- agentflowkit-0.1.0/src/agentflow/agent.py +0 -97
- agentflowkit-0.1.0/src/agentflow/events.py +0 -32
- agentflowkit-0.1.0/src/agentflow/exceptions.py +0 -21
- agentflowkit-0.1.0/src/agentflow/llm.py +0 -96
- agentflowkit-0.1.0/src/agentflow/pipeline.py +0 -170
- agentflowkit-0.1.0/src/agentflow/types.py +0 -40
- agentflowkit-0.1.0/tmpclaude-0006-cwd +0 -1
- agentflowkit-0.1.0/tmpclaude-07af-cwd +0 -1
- agentflowkit-0.1.0/tmpclaude-153f-cwd +0 -1
- agentflowkit-0.1.0/tmpclaude-186c-cwd +0 -1
- agentflowkit-0.1.0/tmpclaude-1ebb-cwd +0 -1
- agentflowkit-0.1.0/tmpclaude-2838-cwd +0 -1
- agentflowkit-0.1.0/tmpclaude-2ebe-cwd +0 -1
- agentflowkit-0.1.0/tmpclaude-6962-cwd +0 -1
- agentflowkit-0.1.0/tmpclaude-6b68-cwd +0 -1
- agentflowkit-0.1.0/tmpclaude-8083-cwd +0 -1
- agentflowkit-0.1.0/tmpclaude-80d4-cwd +0 -1
- agentflowkit-0.1.0/tmpclaude-8eb0-cwd +0 -1
- agentflowkit-0.1.0/tmpclaude-94d9-cwd +0 -1
- agentflowkit-0.1.0/tmpclaude-a787-cwd +0 -1
- agentflowkit-0.1.0/tmpclaude-aea4-cwd +0 -1
- agentflowkit-0.1.0/tmpclaude-ba42-cwd +0 -1
- agentflowkit-0.1.0/tmpclaude-c025-cwd +0 -1
- agentflowkit-0.1.0/tmpclaude-c7b8-cwd +0 -1
- agentflowkit-0.1.0/tmpclaude-de78-cwd +0 -1
- agentflowkit-0.1.0/tmpclaude-de86-cwd +0 -1
- agentflowkit-0.1.0/tmpclaude-e628-cwd +0 -1
- agentflowkit-0.1.0/tmpclaude-e792-cwd +0 -1
- agentflowkit-0.1.0/tmpclaude-f142-cwd +0 -1
- agentflowkit-0.1.0/tmpclaude-f2e4-cwd +0 -1
- agentflowkit-0.1.0/tmpclaude-f501-cwd +0 -1
- agentflowkit-0.1.0/tmpclaude-fd1d-cwd +0 -1
- {agentflowkit-0.1.0 → agentflowkit-0.5.0}/.gitattributes +0 -0
- {agentflowkit-0.1.0 → agentflowkit-0.5.0}/LICENSE +0 -0
|
Binary file
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: Bug Report
|
|
3
|
+
about: Report a reproducible bug in agentflowkit
|
|
4
|
+
title: "[Bug] "
|
|
5
|
+
labels: bug
|
|
6
|
+
assignees: ""
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Description
|
|
10
|
+
|
|
11
|
+
A clear, concise description of the bug.
|
|
12
|
+
|
|
13
|
+
## Reproduction Steps
|
|
14
|
+
|
|
15
|
+
```python
|
|
16
|
+
# Minimal reproducible example
|
|
17
|
+
from agentflow import Agent, LLM, Pipeline
|
|
18
|
+
|
|
19
|
+
@Agent(name="example", role="Example")
|
|
20
|
+
async def example(task: str, context: dict) -> str:
|
|
21
|
+
return task
|
|
22
|
+
|
|
23
|
+
# Code that triggers the bug
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
## Expected Behavior
|
|
27
|
+
|
|
28
|
+
What you expected to happen.
|
|
29
|
+
|
|
30
|
+
## Actual Behavior
|
|
31
|
+
|
|
32
|
+
What actually happened (include full traceback if applicable).
|
|
33
|
+
|
|
34
|
+
## Environment
|
|
35
|
+
|
|
36
|
+
- `agentflowkit` version: <!-- e.g. 0.2.0 -->
|
|
37
|
+
- Python version: <!-- e.g. 3.11.5 -->
|
|
38
|
+
- OS: <!-- e.g. Ubuntu 22.04 / macOS 14 / Windows 11 -->
|
|
39
|
+
- LLM provider: <!-- e.g. OpenAI, Groq, Ollama -->
|
|
40
|
+
|
|
41
|
+
## Additional Context
|
|
42
|
+
|
|
43
|
+
Any other context, screenshots, or logs that may help diagnose the issue.
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: Feature Request
|
|
3
|
+
about: Suggest a new feature or improvement
|
|
4
|
+
title: "[Feature] "
|
|
5
|
+
labels: enhancement
|
|
6
|
+
assignees: ""
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Problem Statement
|
|
10
|
+
|
|
11
|
+
What problem does this feature solve? Who is affected?
|
|
12
|
+
|
|
13
|
+
## Proposed Solution
|
|
14
|
+
|
|
15
|
+
A clear description of what you want to happen.
|
|
16
|
+
|
|
17
|
+
```python
|
|
18
|
+
# Ideally, show what the API would look like
|
|
19
|
+
pipe = Pipeline(llm=llm)
|
|
20
|
+
pipe.add(agent, new_feature_param=...)
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
## Alternatives Considered
|
|
24
|
+
|
|
25
|
+
Other approaches you considered and why you prefer this one.
|
|
26
|
+
|
|
27
|
+
## Additional Context
|
|
28
|
+
|
|
29
|
+
Links to related issues, prior art in other frameworks (LangChain, CrewAI, etc.), or references.
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
pull_request:
|
|
7
|
+
branches: [main]
|
|
8
|
+
|
|
9
|
+
jobs:
|
|
10
|
+
lint:
|
|
11
|
+
name: Lint & Type Check
|
|
12
|
+
runs-on: ubuntu-latest
|
|
13
|
+
steps:
|
|
14
|
+
- uses: actions/checkout@v4
|
|
15
|
+
|
|
16
|
+
- name: Set up Python
|
|
17
|
+
uses: actions/setup-python@v5
|
|
18
|
+
with:
|
|
19
|
+
python-version: "3.11"
|
|
20
|
+
|
|
21
|
+
- name: Install dev dependencies
|
|
22
|
+
run: pip install -e ".[dev]"
|
|
23
|
+
|
|
24
|
+
- name: Run ruff
|
|
25
|
+
run: ruff check src/ tests/ examples/ benchmarks/
|
|
26
|
+
|
|
27
|
+
- name: Run mypy
|
|
28
|
+
run: mypy src/agentflow/
|
|
29
|
+
|
|
30
|
+
test:
|
|
31
|
+
name: Tests (Python ${{ matrix.python-version }})
|
|
32
|
+
runs-on: ubuntu-latest
|
|
33
|
+
strategy:
|
|
34
|
+
fail-fast: false
|
|
35
|
+
matrix:
|
|
36
|
+
python-version: ["3.10", "3.11", "3.12"]
|
|
37
|
+
|
|
38
|
+
steps:
|
|
39
|
+
- uses: actions/checkout@v4
|
|
40
|
+
|
|
41
|
+
- name: Set up Python ${{ matrix.python-version }}
|
|
42
|
+
uses: actions/setup-python@v5
|
|
43
|
+
with:
|
|
44
|
+
python-version: ${{ matrix.python-version }}
|
|
45
|
+
|
|
46
|
+
- name: Install dependencies
|
|
47
|
+
run: pip install -e ".[dev]"
|
|
48
|
+
|
|
49
|
+
- name: Run tests with coverage
|
|
50
|
+
run: pytest tests/ -v --cov=agentflow --cov-report=xml --cov-report=term-missing
|
|
51
|
+
|
|
52
|
+
- name: Upload coverage to Codecov
|
|
53
|
+
uses: codecov/codecov-action@v4
|
|
54
|
+
with:
|
|
55
|
+
file: ./coverage.xml
|
|
56
|
+
fail_ci_if_error: false
|
|
57
|
+
env:
|
|
58
|
+
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
|
|
59
|
+
|
|
60
|
+
build:
|
|
61
|
+
name: Build Distribution
|
|
62
|
+
runs-on: ubuntu-latest
|
|
63
|
+
needs: [lint, test]
|
|
64
|
+
steps:
|
|
65
|
+
- uses: actions/checkout@v4
|
|
66
|
+
|
|
67
|
+
- name: Set up Python
|
|
68
|
+
uses: actions/setup-python@v5
|
|
69
|
+
with:
|
|
70
|
+
python-version: "3.11"
|
|
71
|
+
|
|
72
|
+
- name: Install build tools
|
|
73
|
+
run: pip install build
|
|
74
|
+
|
|
75
|
+
- name: Build wheel and sdist
|
|
76
|
+
run: python -m build
|
|
77
|
+
|
|
78
|
+
- name: Check distributions
|
|
79
|
+
run: |
|
|
80
|
+
pip install twine
|
|
81
|
+
twine check dist/*
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
name: Docs
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
paths:
|
|
7
|
+
- "docs/**"
|
|
8
|
+
- "mkdocs.yml"
|
|
9
|
+
- "src/**"
|
|
10
|
+
- ".github/workflows/docs.yml"
|
|
11
|
+
workflow_dispatch:
|
|
12
|
+
|
|
13
|
+
permissions:
|
|
14
|
+
contents: write
|
|
15
|
+
|
|
16
|
+
jobs:
|
|
17
|
+
deploy:
|
|
18
|
+
name: Build & Deploy MkDocs
|
|
19
|
+
runs-on: ubuntu-latest
|
|
20
|
+
steps:
|
|
21
|
+
- uses: actions/checkout@v4
|
|
22
|
+
|
|
23
|
+
- name: Set up Python
|
|
24
|
+
uses: actions/setup-python@v5
|
|
25
|
+
with:
|
|
26
|
+
python-version: "3.11"
|
|
27
|
+
|
|
28
|
+
- name: Install docs dependencies
|
|
29
|
+
run: pip install -e ".[docs]"
|
|
30
|
+
|
|
31
|
+
- name: Build and deploy to GitHub Pages
|
|
32
|
+
run: mkdocs gh-deploy --force
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
name: Publish to PyPI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
tags:
|
|
6
|
+
- "v*"
|
|
7
|
+
|
|
8
|
+
jobs:
|
|
9
|
+
publish:
|
|
10
|
+
name: Publish to PyPI
|
|
11
|
+
runs-on: ubuntu-latest
|
|
12
|
+
environment: release
|
|
13
|
+
permissions:
|
|
14
|
+
id-token: write # Required for OIDC trusted publishing
|
|
15
|
+
|
|
16
|
+
steps:
|
|
17
|
+
- uses: actions/checkout@v4
|
|
18
|
+
|
|
19
|
+
- name: Set up Python
|
|
20
|
+
uses: actions/setup-python@v5
|
|
21
|
+
with:
|
|
22
|
+
python-version: "3.11"
|
|
23
|
+
|
|
24
|
+
- name: Install build tools
|
|
25
|
+
run: pip install build
|
|
26
|
+
|
|
27
|
+
- name: Build distribution
|
|
28
|
+
run: python -m build
|
|
29
|
+
|
|
30
|
+
- name: Publish to PyPI
|
|
31
|
+
uses: pypa/gh-action-pypi-publish@release/v1
|
|
32
|
+
# No API key needed — uses OIDC trusted publishing
|
|
33
|
+
# Configure at: https://pypi.org/manage/project/agentflowkit/settings/publishing/
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
__pycache__/
|
|
2
|
+
*.pyc
|
|
3
|
+
*.pyo
|
|
4
|
+
*.egg-info/
|
|
5
|
+
dist/
|
|
6
|
+
build/
|
|
7
|
+
.venv/
|
|
8
|
+
venv/
|
|
9
|
+
.env
|
|
10
|
+
.pytest_cache/
|
|
11
|
+
*.egg
|
|
12
|
+
# AI assistants / agents
|
|
13
|
+
.claude/
|
|
14
|
+
CLAUDE.md
|
|
15
|
+
.cursor/
|
|
16
|
+
.cursorrules
|
|
17
|
+
.aider*
|
|
18
|
+
.github/copilot-instructions.md
|
|
19
|
+
AGENTS.md
|
|
20
|
+
chat.md
|
|
21
|
+
tmpclaude-*
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
# 🔍 Audit Report — `agentflowkit` v0.4.0
|
|
2
|
+
|
|
3
|
+
> **الوضع:** Pass 1 (تقرير فقط — ما تم تعديل أي سطر).
|
|
4
|
+
> **التاريخ:** 2026-07-03
|
|
5
|
+
> **الفرع:** `main` @ `03a370d`
|
|
6
|
+
> **المدقّق:** Claude (Opus 4.8) — Two-Pass Security & Health Audit
|
|
7
|
+
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
## 0. الملخّص التنفيذي
|
|
11
|
+
|
|
12
|
+
| البند | النتيجة |
|
|
13
|
+
|-------|---------|
|
|
14
|
+
| **Stack** | Python ≥3.10 · packaging: `hatchling` · quality: `ruff` + `mypy --strict` |
|
|
15
|
+
| **Core deps** | `openai>=1.0.0`, `pydantic>=2.0.0` (باقي backends: docker/redis/chromadb/aiomqtt = optional extras) |
|
|
16
|
+
| **Test baseline** | ✅ `202 passed, 11 skipped` بـ ~22s — كلها خضراء (التقرير الأصلي حكى 99؛ الواقع أكبر وأصحّ) |
|
|
17
|
+
| **Ruff (src)** | ❌ 2 errors بـ `swarm.py` |
|
|
18
|
+
| **Mypy (src)** | ❌ 1 error بـ `swarm.py` |
|
|
19
|
+
| **pip-audit** | ✅ ولا CVE بأي dependency حقيقي لـ agentflow |
|
|
20
|
+
| **Secrets / eval / exec** | ✅ نظيف |
|
|
21
|
+
|
|
22
|
+
**أهم 5 أولويات:**
|
|
23
|
+
1. **D1** — تصليح lint/type بـ `swarm.py` (بوابة الجودة حمرا حالياً، إصلاح آمن 100%).
|
|
24
|
+
2. **A1** — لفّ استدعاءات ChromaDB المتزامنة بـ `asyncio.to_thread` (blocking داخل الـ event loop).
|
|
25
|
+
3. **S1** — قرار حول الـ sandbox fallback الصامت (يغيّر سلوك خارجي).
|
|
26
|
+
4. **H1** — سقف عدد الجلسات بـ `InMemoryContext` (نمو ذاكرة غير محدود).
|
|
27
|
+
5. **H2/A2/A3/H3/H4/H5** — تحصينات صغيرة آمنة.
|
|
28
|
+
|
|
29
|
+
**تنبيه على البيئة:** الـ `venv` المفحوص بيئة مشتركة (torch+cuda، transformers، streamlit، rembg، langchain…) مش معزولة لـ agentflow — بيأثّر على قراءة الـ CVEs (شوف القسم 3).
|
|
30
|
+
|
|
31
|
+
---
|
|
32
|
+
|
|
33
|
+
## 1. 🔒 Security & AI Risks (أولوية قصوى)
|
|
34
|
+
|
|
35
|
+
| # | Sev | Issue | File+Line | Impact | Suggested Fix |
|
|
36
|
+
|---|-----|-------|-----------|--------|---------------|
|
|
37
|
+
| S1 | 🟠 Med-High | **Fallback صامت لـ `SubprocessSandbox`** — لما Docker مش متوفر، `create_sandbox(prefer_docker=True)` بيرجع `SubprocessSandbox` اللي بشغّل كود الـ LLM مباشرة على الهوست (`sys.executable -c code`) بدون عزل. الاسم `sandboxed_tool` بيوحي بالأمان، والـ fallback بصير بصمت وقت الإعداد (في warning بس وقت التنفيذ). | `sandbox.py:389-415` | كود مولّد من LLM (يحتمل injection) ينفّذ على جهاز المستخدم بكامل صلاحياته. | opt-in صريح `allow_insecure_fallback=False`؛ إذا Docker مفقود وما في سماح → `raise`. **⚠️ يغيّر السلوك الخارجي — بدّه قرار.** |
|
|
38
|
+
| S2 | 🟡 Low | **Heredoc breakout بالـ C++** — الكود بينحطّ داخل `sh -c` heredoc بفاصل ثابت `AGENTFLOW_EOF`؛ كود فيه هاض السطر بيكسر الـ heredoc. | `sandbox.py:64-79` | منخفض: الكسر بيضل جوّا نفس الـ container المعزول (network none, cap_drop ALL, read_only). مش هروب من الحدود. | تمرير الكود عبر stdin أو file mount بدل heredoc. |
|
|
39
|
+
| S3 | 🟡 Low-Med | **Trust elevation بالـ prompt** — مخرجات الوكلاء/الأدوات السابقة بتنحقن بالـ **system** prompt (مقصوصة 300 حرف)؛ محتوى غير موثوق (نتيجة أداة web/MQTT) بيترفّع لمستوى system. | `agent.py:106-115` | منخفض-متوسط: بيضخّم prompt-injection؛ متأصّل بأطر الوكلاء. | نقل ذاكرة الجلسة لرسالة `user`/`assistant` مش `system`. informational. |
|
|
40
|
+
| S4 | 🟢 OK | **No hardcoded secrets / no eval / no exec** — بس placeholders بالـ tests/docs (`"test-key"`, `"sk-or-..."`). `subprocess` محصور بـ `sandbox.py` بالتصميم. | — | نظيف. | لا شيء. |
|
|
41
|
+
| S5 | 🟢 OK | **No path traversal بالـ loggers** — كتابة على stdout بس (`StreamHandler`)، ما في file paths. | `logging.py` | نظيف. | لا شيء. |
|
|
42
|
+
|
|
43
|
+
---
|
|
44
|
+
|
|
45
|
+
## 2. ⚙️ Async & Concurrency Health
|
|
46
|
+
|
|
47
|
+
| # | Sev | Issue | File+Line | Impact | Suggested Fix |
|
|
48
|
+
|---|-----|-------|-----------|--------|---------------|
|
|
49
|
+
| A1 | 🟠 Med | **استدعاءات ChromaDB متزامنة (blocking) جوّا `async def`** — كل دوال `VectorContext` معرّفة `async` بس بتنادي `._collection.upsert/.query/.get/.delete` المتزامنة مباشرة. مع `PersistentClient` (disk IO) أو حساب embeddings بيتجمّد الـ event loop. باقي الكود بيلفّ الـ blocking بـ `asyncio.to_thread` (DockerSandbox / tools.py) — هون غير متسق. | `memory.py:258-323` | تجميد الـ loop تحت الحمل. | `await asyncio.to_thread(self._collection.method, …)`. |
|
|
50
|
+
| A2 | 🟡 Low-Med | **RateLimiter ماسك الـ lock عبر `await sleep`** — `_wait_for_window` ماسك `self._lock` وهو نايم بالـ `asyncio.sleep`، فكل الكوروتينات الباقية بتتسكّر (تسلسل الإنتاجية)، والـ semaphore slot محجوز طول الانتظار. | `rate_limiter.py:47-59` | خنق الـ throughput، مش deadlock. | احسب مدة النوم تحت الـ lock، حرّر الـ lock، بعدها نام. |
|
|
51
|
+
| A3 | 🟡 Low | **تسرّب Semaphore عند الإلغاء** — `acquire()` بياخد الـ semaphore بعدها `_wait_for_window`؛ إلغاء أثناء النوم ما بيحرّر الـ slot. وبـ `llm.py` الـ `acquire()` برّا الـ try/finally (121 مقابل try 123). | `rate_limiter.py:36-39`, `llm.py:120-121` | حالة حافة ضيّقة (cancellation). | خلّي `acquire` يحرّر الـ semaphore إذا `_wait_for_window` رمى؛ أو انقل `acquire` جوّا try. |
|
|
52
|
+
| A4 | 🟢 OK | **`asyncio.gather`** — كلها `return_exceptions=True` مع معالجة، أو await متسلسل للـ tasks. ما في gather exceptions مهملة. | `pipeline.py:248,440,558`; `agent.py:283-286`; `swarm.py:162-163` | نظيف. | لا شيء. |
|
|
53
|
+
| A5 | 🟢 OK | **`InMemoryContext` locking** — قفل واحد متّسق، ما في await بين check/act يسبّب race، ولا nesting. | `memory.py:48-104` | نظيف. | لا شيء. |
|
|
54
|
+
|
|
55
|
+
---
|
|
56
|
+
|
|
57
|
+
## 3. 📦 Dependencies
|
|
58
|
+
|
|
59
|
+
### النُّسخ (Installed vs Latest)
|
|
60
|
+
|
|
61
|
+
| Package | Installed | Latest | نوع | ملاحظة |
|
|
62
|
+
|---------|-----------|--------|-----|--------|
|
|
63
|
+
| `openai` | 1.99.9 | **2.44.0** | **MAJOR** | الكود بستورد `APIError, RateLimitError, AsyncOpenAI` + `openai.types.chat` — 2.x محتمل يكسر. **توصية بس.** |
|
|
64
|
+
| `pydantic-core` | 2.46.4 | 2.47.0 | minor | آمن (patch/minor). |
|
|
65
|
+
| `anyio` | 4.14.0 | 4.14.1 | patch | آمن. |
|
|
66
|
+
| `ruff` (dev) | 0.1.14 | 0.15.20 | — | ⚠️ مثبّت **أقل** من floor المعلن `>=0.4` بالـ pyproject. |
|
|
67
|
+
| `pytest-asyncio` (dev) | 0.23.3 | 1.4.0 | major | dev بس. |
|
|
68
|
+
| `pytest-cov` (dev) | 7.0.0 | 7.1.0 | minor | dev بس. |
|
|
69
|
+
|
|
70
|
+
### CVEs (pip-audit)
|
|
71
|
+
|
|
72
|
+
✅ **ولا CVE بأي من dependencies الحقيقية لـ agentflow** (`openai`, `pydantic`).
|
|
73
|
+
|
|
74
|
+
كل الثغرات المكتشفة بحزم **مش تابعة** لـ agentflow، موجودة بالـ venv المشترك:
|
|
75
|
+
|
|
76
|
+
```
|
|
77
|
+
setuptools 65.5.0 CVE-2024-6345 (RCE), PYSEC-2025-49 (path traversal), PYSEC-2022-43012
|
|
78
|
+
starlette 0.37.2 عدة CVEs (2024-2026)
|
|
79
|
+
tornado 6.5.2 عدة CVEs (2026)
|
|
80
|
+
werkzeug 3.1.3 CVE-2025-66221, CVE-2026-21860, CVE-2026-27199
|
|
81
|
+
transformers 4.57.6 PYSEC-2025-217, CVE-2026-1839, CVE-2026-4372
|
|
82
|
+
streamlit 1.53.1 CVE-2026-33682
|
|
83
|
+
pyarrow / rembg / wheel ثغرات إضافية
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
- كل هدول **مش** dependencies لـ agentflow.
|
|
87
|
+
- تنبيه: الـ extra الاختياري `chromadb` بيجرّ transitively `fastapi/starlette/uvicorn`.
|
|
88
|
+
- **توصية:** شغّل الـ audit بـ venv معزول فيه agentflow + extras بس عشان قراءة دقيقة.
|
|
89
|
+
|
|
90
|
+
---
|
|
91
|
+
|
|
92
|
+
## 4. 🔁 Duplicated Logic & Refactors
|
|
93
|
+
|
|
94
|
+
| # | Sev | Issue | File+Line | Impact | Suggested Fix |
|
|
95
|
+
|---|-----|-------|-----------|--------|---------------|
|
|
96
|
+
| D1 | 🟠 Med | **Lint/type فاشلة بـ `swarm.py`** — `ruff`: B007 (`iteration` unused @104)، F841 (`arguments` unused @148). `mypy`: no-untyped-def @184 (`_make_delegate_fn`). بوابة الجودة **حالياً حمرا**. | `swarm.py:104,148,184` | إصلاحات تافهة وآمنة. | `for _ in range(...)`، احذف `arguments` المكرّر، ضيف return type annotation. **✅ أسهل مكسب.** |
|
|
97
|
+
| D2 | 🟠 Med | **بلوك HITL pause/persist مكرّر 3×** حرفياً. | `pipeline.py:250-296, 442-485, 560-595` | صيانة مؤلمة. | استخرج helper `_persist_pause_state(...)`. **⚠️ يلمس تدفق pipeline — بدّه قرار.** |
|
|
98
|
+
| D3 | 🟡 Low | **حلقة ReAct مكرّرة** بين الوكيل والـ supervisor. | `agent.py:195-307` vs `swarm.py:104-182` | تكرار كبير بس **core logic**. | **توصية بس — ممنوع لمسها حسب القيود.** |
|
|
99
|
+
| D4 | 🟡 Low | **guard استيراد redis مكرّر** بنمطين مختلفين. | `cache.py:80-84` vs `memory.py:108-135` | بسيط. | توحيد النمط. |
|
|
100
|
+
|
|
101
|
+
---
|
|
102
|
+
|
|
103
|
+
## 5. 🩺 General Health
|
|
104
|
+
|
|
105
|
+
| # | Sev | Issue | File+Line | Impact | Suggested Fix |
|
|
106
|
+
|---|-----|-------|-----------|--------|---------------|
|
|
107
|
+
| H1 | 🟠 Med | **نمو `InMemoryContext` غير محدود بالجلسات** — `max_entries` بحدّ الإدخالات **لكل جلسة**، بس عدد الجلسات (`self._store` keys) غير محدود. الجلسات المنتهية بتتنظّف بس لما تتقرا هي بالذات عبر `load_context`. workload بيولّد session_id فريد لكل طلب وما بيرجع يقراه = تسرّب ذاكرة. | `memory.py:60, 78-91` | نمو ذاكرة غير محدود. | سقف max-sessions/sweep دوري، أو توثيق إن الـ caller لازم `clear()`. |
|
|
108
|
+
| H2 | 🟡 Low | **`getattr` برّا الـ try بـ tools** — `kwargs = {k: getattr(validated, k) for k in arguments}` قبل الـ try؛ إذا الـ LLM بعت مفتاح زيادة (pydantic بتجاهله)، `getattr` بترمي `AttributeError` غير ملفوفة بـ `ToolError`. | `tools.py:94` | منخفض. | كرّر على حقول الموديل مش مفاتيح `arguments`، أو انقل جوّا try. |
|
|
109
|
+
| H3 | 🟡 Low | **ما في لفّ لأخطاء Redis** — استثناءات redis الخام بتنتشر بدل framework error (غير متّسق مع لفّ `LLMError`/`ToolError`). | `memory.py:186-201`, `cache.py:119-131` | منخفض. | لفّ استدعاءات redis. |
|
|
110
|
+
| H4 | 🟡 Low | **`InMemoryCache` موصوف "Thread-safe" بدون قفل** — dict عادي بلا lock (بعكس `InMemoryContext`). آمن ضمن الـ event loop بس، مش thread-safe فعلياً؛ وكمان FIFO مش LRU رغم التسمية. | `cache.py:36-70` | docstring مضلّل. | صحّح الـ docstring أو ضيف قفل. |
|
|
111
|
+
| H5 | 🟡 Low | **DockerSandbox `read_only=True` مع كتابة `/tmp`** — مسار الـ C++ بيكتب `/tmp/code.cpp` بس الـ container read-only بلا tmpfs → تنفيذ C++ بالـ Docker بيفشل runtime. | `sandbox.py:201, 73-76` | خلل وظيفي (مش أمني). | ضيف `tmpfs={"/tmp": ""}` أو `read_only=False`. |
|
|
112
|
+
|
|
113
|
+
---
|
|
114
|
+
|
|
115
|
+
## 6. القرارات المعلّقة (بدّها موافقتك)
|
|
116
|
+
|
|
117
|
+
| القرار | الوصف | الخيار |
|
|
118
|
+
|--------|-------|--------|
|
|
119
|
+
| **S1** | الـ sandbox fallback الصامت | نضيف `allow_insecure_fallback` ونمنع الـ fallback الصامت؟ (يغيّر سلوك) |
|
|
120
|
+
| **D2** | HITL persist helper | نستخرج helper (يلمس pipeline flow)؟ |
|
|
121
|
+
| **D3** | ReAct dedup | توصية فقط — ممنوع اللمس حسب القيود |
|
|
122
|
+
| **openai 2.x** | ترقية major | نتركها توصية أم نجرّبها بفرع منفصل؟ |
|
|
123
|
+
|
|
124
|
+
---
|
|
125
|
+
|
|
126
|
+
## 7. خطة Pass 2 المقترحة (بعد الموافقة)
|
|
127
|
+
|
|
128
|
+
**المجموعة الآمنة (ما بتغيّر سلوك — بتنفّذ مباشرة بعد الموافقة):**
|
|
129
|
+
`D1` (lint/type) → `A1` (to_thread) → `H1` (session cap) → `H2` (try scope) → `A2`+`A3` (rate limiter) → `H3` (redis wrap) → `H4` (docstring) → `H5` (tmpfs) → dependency patches (anyio, pydantic-core).
|
|
130
|
+
|
|
131
|
+
**بعد كل مجموعة:** `pytest` + `ruff` + `mypy` — والـ 202 لازم تضل خضرا.
|
|
132
|
+
|
|
133
|
+
**تُترك كتوصيات فقط:** `S1`, `D2`, `D3`, `openai 2.x`.
|
|
134
|
+
|
|
135
|
+
---
|
|
136
|
+
|
|
137
|
+
*انتهى Pass 1 — ما تم تعديل أي سطر بالكود.*
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project will be documented here.
|
|
4
|
+
|
|
5
|
+
Format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
|
|
6
|
+
This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
|
+
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
## [0.3.0]
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
- **Tool / function calling** (`tools.py`): the `@tool` decorator turns any sync
|
|
14
|
+
or async Python function into an LLM-callable tool. Argument JSON schemas are
|
|
15
|
+
generated automatically from type hints via Pydantic. Agents given `tools=[...]`
|
|
16
|
+
run a bounded **ReAct loop** (call → execute tools → observe → repeat) up to
|
|
17
|
+
`max_tool_iterations` (default 6). Tool errors are fed back to the model for
|
|
18
|
+
recovery. New `ToolError` exception; tool-call traces recorded in
|
|
19
|
+
`AgentResult.metadata["tool_calls"]`.
|
|
20
|
+
- **Cost tracking** (`pricing.py`): built-in USD price tables for common OpenAI
|
|
21
|
+
and Anthropic models with longest-prefix matching. `LLM.generate()` returns a
|
|
22
|
+
`cost` (and `prompt_tokens`/`completion_tokens`); `AgentResult.cost` and
|
|
23
|
+
`PipelineResult.total_cost` aggregate spend. Cache hits bill `0.0`.
|
|
24
|
+
`register_price()` / `estimate_cost()` are public.
|
|
25
|
+
- **Token streaming**: `LLM.astream()` yields content deltas token-by-token for
|
|
26
|
+
interactive UIs (honours the rate limiter; no cache/retry mid-stream).
|
|
27
|
+
- **Observability hooks** (`observability.py`): `Hooks` base class + `LoggingHooks`
|
|
28
|
+
wire the previously-unused `PipelineLogger` into `Pipeline.run()` (which was
|
|
29
|
+
silent before). A raising hook is caught and warned, never crashing the run.
|
|
30
|
+
- **Production-grade retry**: unified exponential backoff with jitter and
|
|
31
|
+
`Retry-After` header support. New `LLM(retry_base_delay=, retry_jitter=)` args.
|
|
32
|
+
- **Documentation site**: MkDocs Material + mkdocstrings under `docs/`, deployed
|
|
33
|
+
via a new `docs.yml` workflow. New `docs` optional-dependency group.
|
|
34
|
+
- New examples: `tool_agent.py`, `streaming_and_cost.py`; and
|
|
35
|
+
`benchmarks/parallel_speedup.py`.
|
|
36
|
+
|
|
37
|
+
### Fixed
|
|
38
|
+
- **`py.typed` marker** added — the package advertised `Typing :: Typed` but
|
|
39
|
+
shipped no marker, so downstream type-checkers saw no types.
|
|
40
|
+
- **Red CI made green**: resolved 1 `ruff` error (B904) and 7 `mypy --strict`
|
|
41
|
+
errors across `llm.py`, `cache.py`, `logging.py`, `events.py`, `pipeline.py`.
|
|
42
|
+
|
|
43
|
+
### Changed
|
|
44
|
+
- `__version__` bumped to `0.3.0`.
|
|
45
|
+
- Test coverage raised to ~91%; `fail_under` tightened from 80 → 90.
|
|
46
|
+
- `Pipeline.__init__` gains a `hooks` parameter; `run()` now emits lifecycle
|
|
47
|
+
events and generates `run_id` up front.
|
|
48
|
+
|
|
49
|
+
---
|
|
50
|
+
|
|
51
|
+
## [0.2.0]
|
|
52
|
+
|
|
53
|
+
### Added
|
|
54
|
+
- **Parallel execution**: Agents at the same DAG level now run concurrently via
|
|
55
|
+
`asyncio.gather()`. `_resolve_levels()` replaces `_resolve_order()` and uses
|
|
56
|
+
Kahn's algorithm to group independent agents.
|
|
57
|
+
- **Per-agent timeout**: `Pipeline.add(timeout=N)` wraps each agent coroutine with
|
|
58
|
+
`asyncio.wait_for`; raises `AgentTimeoutError` on expiry.
|
|
59
|
+
- **Conditional branching**: `Pipeline.add(condition=lambda ctx: ...)` allows
|
|
60
|
+
dynamic skipping of agents based on upstream outputs. Skipped agents emit
|
|
61
|
+
`agent_skipped` events in streaming mode.
|
|
62
|
+
- **Pipeline-level retry**: `Pipeline(retry_failed_agents=N)` retries failed
|
|
63
|
+
agents up to N times with exponential backoff (1s, 2s, 4s). Timeouts are
|
|
64
|
+
non-retriable.
|
|
65
|
+
- **LLM response caching** (`cache.py`): `ResponseCache` ABC with `InMemoryCache`
|
|
66
|
+
(SHA-256 key, lazy TTL eviction, max-size LRU) and `RedisCache` (optional dep).
|
|
67
|
+
Cache is wired into `LLM(cache=...)`.
|
|
68
|
+
- **Rate limiting** (`rate_limiter.py`): `RateLimiter(requests_per_minute, max_concurrent)`
|
|
69
|
+
using `asyncio.Semaphore` + sliding-window counter. Async context manager interface.
|
|
70
|
+
Wired into `LLM(rate_limiter=...)`.
|
|
71
|
+
- **Structured logging** (`logging.py`): `PipelineLogger` (LoggerAdapter with JSON
|
|
72
|
+
formatter) carrying `run_id` and `pipeline` through all log records.
|
|
73
|
+
- **Agent output validation**: `@Agent(output_schema=MyPydanticModel)` validates
|
|
74
|
+
LLM response JSON against a Pydantic v2 model; raises `AgentOutputValidationError`
|
|
75
|
+
on failure.
|
|
76
|
+
- New exception classes: `AgentTimeoutError`, `AgentOutputValidationError`.
|
|
77
|
+
- `AgentResult` gains: `cached`, `level`, `timestamp` fields.
|
|
78
|
+
- `PipelineResult` gains: `run_id`, `levels_executed`, `agents_with_cache_hits` fields.
|
|
79
|
+
- `Event.type` now documents all valid values including `"agent_skipped"`.
|
|
80
|
+
- GitHub Actions CI workflow (lint, test matrix py3.10-3.12, codecov, build check).
|
|
81
|
+
- GitHub Actions publish workflow (OIDC trusted publishing on version tags).
|
|
82
|
+
- Issue templates for bug reports and feature requests.
|
|
83
|
+
- `CONTRIBUTING.md` with development setup and PR checklist.
|
|
84
|
+
- `pythonpath = ["src"]` in pytest config to fix editable install on non-ASCII paths.
|
|
85
|
+
|
|
86
|
+
### Changed
|
|
87
|
+
- `__version__` bumped to `0.2.0`.
|
|
88
|
+
- `pipeline.py`: `Pipeline.__init__` gains `retry_failed_agents` parameter.
|
|
89
|
+
- `pipeline.py`: `Pipeline.add` gains `timeout` and `condition` parameters.
|
|
90
|
+
- `llm.py`: `LLM.__init__` gains `cache` and `rate_limiter` parameters.
|
|
91
|
+
Return dict from `generate()` now includes `"cached"` key.
|
|
92
|
+
- `pyproject.toml`: classifier updated to Beta; dev extras expanded;
|
|
93
|
+
`ruff`, `mypy`, `coverage` tool config sections added.
|
|
94
|
+
|
|
95
|
+
### Performance
|
|
96
|
+
- Two independent agents that each take 0.1s now complete in ~0.1s (parallel),
|
|
97
|
+
not ~0.2s (sequential).
|
|
98
|
+
|
|
99
|
+
---
|
|
100
|
+
|
|
101
|
+
## [0.1.0] — 2026-02-27
|
|
102
|
+
|
|
103
|
+
### Added
|
|
104
|
+
- Initial release.
|
|
105
|
+
- `@Agent` decorator and `BaseAgent` ABC for defining agents.
|
|
106
|
+
- `Pipeline` with topological sort (`_resolve_order`) for dependency resolution.
|
|
107
|
+
- `LLM` provider abstraction with OpenAI-compatible API, retry logic.
|
|
108
|
+
- `EventEmitter` + `pipeline.stream()` for async event streaming.
|
|
109
|
+
- Pydantic v2 data models: `AgentResult`, `PipelineResult`, `Event`.
|
|
110
|
+
- Custom exception hierarchy: `AgentFlowError`, `AgentError`, `LLMError`, `PipelineError`.
|
|
111
|
+
- Published to PyPI as `agentflowkit`.
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
cmake_minimum_required(VERSION 3.15)
|
|
2
|
+
project(agentflow_cpp LANGUAGES NONE)
|
|
3
|
+
|
|
4
|
+
set(SKIP_CPP_EXTENSION OFF CACHE BOOL "Skip building the C++ pybind11 extension")
|
|
5
|
+
|
|
6
|
+
if(NOT SKIP_CPP_EXTENSION)
|
|
7
|
+
include(CheckLanguage)
|
|
8
|
+
check_language(CXX)
|
|
9
|
+
if(CMAKE_CXX_COMPILER)
|
|
10
|
+
enable_language(CXX)
|
|
11
|
+
set(CMAKE_CXX_STANDARD 17)
|
|
12
|
+
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
|
13
|
+
endif()
|
|
14
|
+
endif()
|
|
15
|
+
|
|
16
|
+
if(CMAKE_CXX_COMPILER AND NOT SKIP_CPP_EXTENSION)
|
|
17
|
+
find_package(pybind11 CONFIG QUIET)
|
|
18
|
+
if(pybind11_FOUND)
|
|
19
|
+
message(STATUS "pybind11 found — building _agentflow_cpp extension")
|
|
20
|
+
pybind11_add_module(_agentflow_cpp
|
|
21
|
+
src/agentflow/cpp_core/bindings.cpp
|
|
22
|
+
src/agentflow/cpp_core/dag_engine.cpp
|
|
23
|
+
)
|
|
24
|
+
target_include_directories(_agentflow_cpp PRIVATE src/agentflow/cpp_core)
|
|
25
|
+
else()
|
|
26
|
+
message(STATUS "pybind11 not found — skipping _agentflow_cpp extension (Python fallback will be used)")
|
|
27
|
+
endif()
|
|
28
|
+
else()
|
|
29
|
+
message(STATUS "C++ compiler not available — skipping _agentflow_cpp extension (Python fallback will be used)")
|
|
30
|
+
endif()
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
# Contributing to agentflowkit
|
|
2
|
+
|
|
3
|
+
Thank you for your interest in contributing! This guide explains how to work on the project.
|
|
4
|
+
|
|
5
|
+
## Development Setup
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
git clone https://github.com/KaramQ6/agentflow.git
|
|
9
|
+
cd agentflow
|
|
10
|
+
pip install -e ".[dev]"
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
Verify your setup:
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
pytest tests/ -v
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
All tests should pass before you start making changes.
|
|
20
|
+
|
|
21
|
+
## Project Structure
|
|
22
|
+
|
|
23
|
+
```
|
|
24
|
+
src/agentflow/
|
|
25
|
+
├── agent.py # @Agent decorator + BaseAgent ABC
|
|
26
|
+
├── cache.py # ResponseCache, InMemoryCache, RedisCache
|
|
27
|
+
├── events.py # EventEmitter for streaming
|
|
28
|
+
├── exceptions.py # Exception hierarchy
|
|
29
|
+
├── llm.py # LLM provider abstraction
|
|
30
|
+
├── logging.py # PipelineLogger (structured JSON)
|
|
31
|
+
├── pipeline.py # Pipeline DAG orchestration (core)
|
|
32
|
+
├── rate_limiter.py # RateLimiter (RPM + concurrency)
|
|
33
|
+
└── types.py # Pydantic data models
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
## Code Style
|
|
37
|
+
|
|
38
|
+
We use **ruff** for linting + formatting and **mypy** for type checking.
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
ruff check src/ tests/ # Lint
|
|
42
|
+
ruff format src/ tests/ # Format
|
|
43
|
+
mypy src/agentflow/ # Type check
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
All code must:
|
|
47
|
+
- Have full type hints
|
|
48
|
+
- Pass `ruff check` with no errors
|
|
49
|
+
- Pass `mypy` in strict mode
|
|
50
|
+
|
|
51
|
+
## Adding a Feature
|
|
52
|
+
|
|
53
|
+
### New cache backend
|
|
54
|
+
|
|
55
|
+
1. Subclass `ResponseCache` in `cache.py`
|
|
56
|
+
2. Implement `async get(key)` and `async set(key, value, ttl)`
|
|
57
|
+
3. Add to `__all__` in `__init__.py`
|
|
58
|
+
4. Write tests in `tests/test_cache.py`
|
|
59
|
+
|
|
60
|
+
### New exception type
|
|
61
|
+
|
|
62
|
+
1. Add to `exceptions.py` (subclass the appropriate parent)
|
|
63
|
+
2. Add to `__all__` in `__init__.py`
|
|
64
|
+
3. Import and use in the relevant module
|
|
65
|
+
|
|
66
|
+
### New pipeline feature
|
|
67
|
+
|
|
68
|
+
1. Add to `pipeline.py` — keep changes localized to `_PipelineNode`, `Pipeline.add()`, or the execution loop
|
|
69
|
+
2. Emit appropriate events for streaming consumers
|
|
70
|
+
3. Write tests in `tests/test_parallel.py` or a new test file
|
|
71
|
+
|
|
72
|
+
## Pull Request Checklist
|
|
73
|
+
|
|
74
|
+
- [ ] Tests added for new functionality
|
|
75
|
+
- [ ] All existing tests still pass (`pytest tests/ -v`)
|
|
76
|
+
- [ ] Type hints on all new functions and classes
|
|
77
|
+
- [ ] Docstrings on public API additions
|
|
78
|
+
- [ ] Entry added to `[Unreleased]` section in `CHANGELOG.md`
|
|
79
|
+
- [ ] No new dependencies added without discussion in an issue first
|
|
80
|
+
|
|
81
|
+
## Commit Message Convention
|
|
82
|
+
|
|
83
|
+
We use [Conventional Commits](https://www.conventionalcommits.org/):
|
|
84
|
+
|
|
85
|
+
```
|
|
86
|
+
feat: add Redis cache backend
|
|
87
|
+
fix: handle asyncio.TimeoutError in _execute_node
|
|
88
|
+
docs: add caching section to README
|
|
89
|
+
test: add parallel execution timing test
|
|
90
|
+
refactor: extract _resolve_levels from _resolve_order
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
## Running the Full Suite
|
|
94
|
+
|
|
95
|
+
```bash
|
|
96
|
+
pytest tests/ -v --cov=agentflow --cov-report=term-missing
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
Coverage should remain ≥ 80%.
|