grasp_agents_legacy 0.6.50__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.
- grasp_agents_legacy-0.6.50/.gitignore +177 -0
- grasp_agents_legacy-0.6.50/LICENSE.md +1 -0
- grasp_agents_legacy-0.6.50/PKG-INFO +189 -0
- grasp_agents_legacy-0.6.50/README.md +163 -0
- grasp_agents_legacy-0.6.50/pyproject.toml +59 -0
- grasp_agents_legacy-0.6.50/src/grasp_agents_legacy/__init__.py +44 -0
- grasp_agents_legacy-0.6.50/src/grasp_agents_legacy/cloud_llm.py +251 -0
- grasp_agents_legacy-0.6.50/src/grasp_agents_legacy/costs_dict.yaml +130 -0
- grasp_agents_legacy-0.6.50/src/grasp_agents_legacy/errors.py +156 -0
- grasp_agents_legacy-0.6.50/src/grasp_agents_legacy/event_bus.py +161 -0
- grasp_agents_legacy-0.6.50/src/grasp_agents_legacy/generics_utils.py +168 -0
- grasp_agents_legacy-0.6.50/src/grasp_agents_legacy/grasp_logging.py +36 -0
- grasp_agents_legacy-0.6.50/src/grasp_agents_legacy/litellm/__init__.py +106 -0
- grasp_agents_legacy-0.6.50/src/grasp_agents_legacy/litellm/completion_chunk_converters.py +67 -0
- grasp_agents_legacy-0.6.50/src/grasp_agents_legacy/litellm/completion_converters.py +67 -0
- grasp_agents_legacy-0.6.50/src/grasp_agents_legacy/litellm/converters.py +150 -0
- grasp_agents_legacy-0.6.50/src/grasp_agents_legacy/litellm/lite_llm.py +304 -0
- grasp_agents_legacy-0.6.50/src/grasp_agents_legacy/litellm/message_converters.py +66 -0
- grasp_agents_legacy-0.6.50/src/grasp_agents_legacy/llm.py +392 -0
- grasp_agents_legacy-0.6.50/src/grasp_agents_legacy/llm_agent.py +532 -0
- grasp_agents_legacy-0.6.50/src/grasp_agents_legacy/llm_agent_memory.py +41 -0
- grasp_agents_legacy-0.6.50/src/grasp_agents_legacy/llm_policy_executor.py +663 -0
- grasp_agents_legacy-0.6.50/src/grasp_agents_legacy/memory.py +51 -0
- grasp_agents_legacy-0.6.50/src/grasp_agents_legacy/openai/__init__.py +16 -0
- grasp_agents_legacy-0.6.50/src/grasp_agents_legacy/openai/completions/__init__.py +84 -0
- grasp_agents_legacy-0.6.50/src/grasp_agents_legacy/openai/completions/chunk_converters.py +78 -0
- grasp_agents_legacy-0.6.50/src/grasp_agents_legacy/openai/completions/completion_converters.py +76 -0
- grasp_agents_legacy-0.6.50/src/grasp_agents_legacy/openai/completions/content_converters.py +77 -0
- grasp_agents_legacy-0.6.50/src/grasp_agents_legacy/openai/completions/converters.py +147 -0
- grasp_agents_legacy-0.6.50/src/grasp_agents_legacy/openai/completions/message_converters.py +159 -0
- grasp_agents_legacy-0.6.50/src/grasp_agents_legacy/openai/completions/openai_llm_completions.py +284 -0
- grasp_agents_legacy-0.6.50/src/grasp_agents_legacy/openai/completions/tool_converters.py +42 -0
- grasp_agents_legacy-0.6.50/src/grasp_agents_legacy/openai/responses/__init__.py +3 -0
- grasp_agents_legacy-0.6.50/src/grasp_agents_legacy/openai/responses/chunk_converters.py +123 -0
- grasp_agents_legacy-0.6.50/src/grasp_agents_legacy/openai/responses/completion_converters.py +41 -0
- grasp_agents_legacy-0.6.50/src/grasp_agents_legacy/openai/responses/completion_item_converters.py +33 -0
- grasp_agents_legacy-0.6.50/src/grasp_agents_legacy/openai/responses/content_converters.py +73 -0
- grasp_agents_legacy-0.6.50/src/grasp_agents_legacy/openai/responses/converters.py +157 -0
- grasp_agents_legacy-0.6.50/src/grasp_agents_legacy/openai/responses/message_converters.py +205 -0
- grasp_agents_legacy-0.6.50/src/grasp_agents_legacy/openai/responses/openai_responses_api.py +209 -0
- grasp_agents_legacy-0.6.50/src/grasp_agents_legacy/openai/responses/tool_converters.py +32 -0
- grasp_agents_legacy-0.6.50/src/grasp_agents_legacy/packet.py +107 -0
- grasp_agents_legacy-0.6.50/src/grasp_agents_legacy/printer.py +359 -0
- grasp_agents_legacy-0.6.50/src/grasp_agents_legacy/processors/base_processor.py +210 -0
- grasp_agents_legacy-0.6.50/src/grasp_agents_legacy/processors/parallel_processor.py +148 -0
- grasp_agents_legacy-0.6.50/src/grasp_agents_legacy/processors/processor.py +281 -0
- grasp_agents_legacy-0.6.50/src/grasp_agents_legacy/prompt_builder.py +176 -0
- grasp_agents_legacy-0.6.50/src/grasp_agents_legacy/rate_limiting/__init__.py +3 -0
- grasp_agents_legacy-0.6.50/src/grasp_agents_legacy/rate_limiting/rate_limiter.py +89 -0
- grasp_agents_legacy-0.6.50/src/grasp_agents_legacy/rate_limiting/types.py +10 -0
- grasp_agents_legacy-0.6.50/src/grasp_agents_legacy/rate_limiting/utils.py +51 -0
- grasp_agents_legacy-0.6.50/src/grasp_agents_legacy/run_context.py +24 -0
- grasp_agents_legacy-0.6.50/src/grasp_agents_legacy/runner.py +182 -0
- grasp_agents_legacy-0.6.50/src/grasp_agents_legacy/telemetry/exporters.py +91 -0
- grasp_agents_legacy-0.6.50/src/grasp_agents_legacy/telemetry/phoenix.py +67 -0
- grasp_agents_legacy-0.6.50/src/grasp_agents_legacy/telemetry/traceloop.py +32 -0
- grasp_agents_legacy-0.6.50/src/grasp_agents_legacy/tracing_decorators/__init__.py +63 -0
- grasp_agents_legacy-0.6.50/src/grasp_agents_legacy/tracing_decorators/base.py +442 -0
- grasp_agents_legacy-0.6.50/src/grasp_agents_legacy/typing/__init__.py +0 -0
- grasp_agents_legacy-0.6.50/src/grasp_agents_legacy/typing/completion.py +77 -0
- grasp_agents_legacy-0.6.50/src/grasp_agents_legacy/typing/completion_chunk.py +431 -0
- grasp_agents_legacy-0.6.50/src/grasp_agents_legacy/typing/completion_item.py +22 -0
- grasp_agents_legacy-0.6.50/src/grasp_agents_legacy/typing/content.py +125 -0
- grasp_agents_legacy-0.6.50/src/grasp_agents_legacy/typing/converters.py +116 -0
- grasp_agents_legacy-0.6.50/src/grasp_agents_legacy/typing/events.py +387 -0
- grasp_agents_legacy-0.6.50/src/grasp_agents_legacy/typing/io.py +9 -0
- grasp_agents_legacy-0.6.50/src/grasp_agents_legacy/typing/message.py +139 -0
- grasp_agents_legacy-0.6.50/src/grasp_agents_legacy/typing/tool.py +107 -0
- grasp_agents_legacy-0.6.50/src/grasp_agents_legacy/usage_tracker.py +102 -0
- grasp_agents_legacy-0.6.50/src/grasp_agents_legacy/utils/__init__.py +0 -0
- grasp_agents_legacy-0.6.50/src/grasp_agents_legacy/utils/callbacks.py +26 -0
- grasp_agents_legacy-0.6.50/src/grasp_agents_legacy/utils/io.py +28 -0
- grasp_agents_legacy-0.6.50/src/grasp_agents_legacy/utils/streaming.py +104 -0
- grasp_agents_legacy-0.6.50/src/grasp_agents_legacy/utils/validation.py +139 -0
- grasp_agents_legacy-0.6.50/src/grasp_agents_legacy/workflow/__init__.py +0 -0
- grasp_agents_legacy-0.6.50/src/grasp_agents_legacy/workflow/looped_workflow.py +182 -0
- grasp_agents_legacy-0.6.50/src/grasp_agents_legacy/workflow/sequential_workflow.py +104 -0
- grasp_agents_legacy-0.6.50/src/grasp_agents_legacy/workflow/workflow_processor.py +91 -0
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
# Byte-compiled / optimized / DLL files
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[cod]
|
|
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
|
+
#uv.lock
|
|
102
|
+
|
|
103
|
+
# poetry
|
|
104
|
+
# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
|
|
105
|
+
# This is especially recommended for binary packages to ensure reproducibility, and is more
|
|
106
|
+
# commonly ignored for libraries.
|
|
107
|
+
# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
|
|
108
|
+
#poetry.lock
|
|
109
|
+
|
|
110
|
+
# pdm
|
|
111
|
+
# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
|
|
112
|
+
#pdm.lock
|
|
113
|
+
# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
|
|
114
|
+
# in version control.
|
|
115
|
+
# https://pdm.fming.dev/latest/usage/project/#working-with-version-control
|
|
116
|
+
.pdm.toml
|
|
117
|
+
.pdm-python
|
|
118
|
+
.pdm-build/
|
|
119
|
+
|
|
120
|
+
# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
|
|
121
|
+
__pypackages__/
|
|
122
|
+
|
|
123
|
+
# Celery stuff
|
|
124
|
+
celerybeat-schedule
|
|
125
|
+
celerybeat.pid
|
|
126
|
+
|
|
127
|
+
# SageMath parsed files
|
|
128
|
+
*.sage.py
|
|
129
|
+
|
|
130
|
+
# Environments
|
|
131
|
+
.env
|
|
132
|
+
.venv
|
|
133
|
+
env/
|
|
134
|
+
venv/
|
|
135
|
+
ENV/
|
|
136
|
+
env.bak/
|
|
137
|
+
venv.bak/
|
|
138
|
+
|
|
139
|
+
# Spyder project settings
|
|
140
|
+
.spyderproject
|
|
141
|
+
.spyproject
|
|
142
|
+
|
|
143
|
+
# Rope project settings
|
|
144
|
+
.ropeproject
|
|
145
|
+
|
|
146
|
+
# mkdocs documentation
|
|
147
|
+
/site
|
|
148
|
+
|
|
149
|
+
# mypy
|
|
150
|
+
.mypy_cache/
|
|
151
|
+
.dmypy.json
|
|
152
|
+
dmypy.json
|
|
153
|
+
|
|
154
|
+
# Pyre type checker
|
|
155
|
+
.pyre/
|
|
156
|
+
|
|
157
|
+
# pytype static type analyzer
|
|
158
|
+
.pytype/
|
|
159
|
+
|
|
160
|
+
# Cython debug symbols
|
|
161
|
+
cython_debug/
|
|
162
|
+
|
|
163
|
+
# PyCharm
|
|
164
|
+
# JetBrains specific template is maintained in a separate JetBrains.gitignore that can
|
|
165
|
+
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
|
|
166
|
+
# and can be added to the global gitignore or merged into this file. For a more nuclear
|
|
167
|
+
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
|
|
168
|
+
#.idea/
|
|
169
|
+
|
|
170
|
+
# Ruff stuff:
|
|
171
|
+
.ruff_cache/
|
|
172
|
+
|
|
173
|
+
# PyPI configuration file
|
|
174
|
+
.pypirc
|
|
175
|
+
|
|
176
|
+
# MAC OS files
|
|
177
|
+
**/.DS_Store
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
Grasp Agents itself is [MIT](https://mit-license.org/)-licensed.
|
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: grasp_agents_legacy
|
|
3
|
+
Version: 0.6.50
|
|
4
|
+
Summary: Grasp Agents Library
|
|
5
|
+
License-File: LICENSE.md
|
|
6
|
+
Requires-Python: <4,>=3.11.4
|
|
7
|
+
Requires-Dist: google-genai>=1.45.0
|
|
8
|
+
Requires-Dist: httpx<1,>=0.27.0
|
|
9
|
+
Requires-Dist: litellm==1.83.10
|
|
10
|
+
Requires-Dist: numpy<2
|
|
11
|
+
Requires-Dist: openai<3,>=1.68.2
|
|
12
|
+
Requires-Dist: opentelemetry-sdk>=1.37.0
|
|
13
|
+
Requires-Dist: pydantic>=2
|
|
14
|
+
Requires-Dist: python-dotenv>=1.0
|
|
15
|
+
Requires-Dist: pyyaml>=6.0.2
|
|
16
|
+
Requires-Dist: tenacity<9,>=8.3.0
|
|
17
|
+
Requires-Dist: termcolor<3,>=2.4.0
|
|
18
|
+
Requires-Dist: tqdm<5,>=4.66.2
|
|
19
|
+
Requires-Dist: traceloop-sdk>=0.47.2
|
|
20
|
+
Provides-Extra: observability
|
|
21
|
+
Requires-Dist: arize-phoenix-otel>=0.13.1; extra == 'observability'
|
|
22
|
+
Requires-Dist: openinference-instrumentation-litellm>=0.1.25; extra == 'observability'
|
|
23
|
+
Requires-Dist: openinference-instrumentation-openai>=0.1.32; extra == 'observability'
|
|
24
|
+
Requires-Dist: openinference-instrumentation-openllmetry>=0.1.2; extra == 'observability'
|
|
25
|
+
Description-Content-Type: text/markdown
|
|
26
|
+
|
|
27
|
+
# Grasp Agents
|
|
28
|
+
|
|
29
|
+
<br/>
|
|
30
|
+
<picture>
|
|
31
|
+
<source srcset="https://raw.githubusercontent.com/grasp-technologies/grasp-agents/master/.assets/grasp-dark.svg" media="(prefers-color-scheme: dark)">
|
|
32
|
+
<img src="https://raw.githubusercontent.com/grasp-technologies/grasp-agents/master/.assets/grasp.svg" alt="Grasp Agents"/>
|
|
33
|
+
</picture>
|
|
34
|
+
<br/>
|
|
35
|
+
<br/>
|
|
36
|
+
|
|
37
|
+
[](https://badge.fury.io/py/grasp-agents)
|
|
38
|
+
[](https://mit-license.org/)
|
|
39
|
+
[](https://pypi.org/project/grasp-agents/)
|
|
40
|
+
[](https://github.com/grasp-technologies/grasp-agents/stargazers)
|
|
41
|
+
[](https://github.com/grasp-technologies/grasp-agents/network/members)
|
|
42
|
+
|
|
43
|
+
## Overview
|
|
44
|
+
|
|
45
|
+
**Grasp Agents** is a modular Python framework for building agentic AI pipelines and applications. It is meant to be minimalistic but functional, allowing for rapid experimentation while keeping full and granular low-level control over prompting, LLM handling, tool call loops, and inter-agent communication by avoiding excessive higher-level abstractions.
|
|
46
|
+
|
|
47
|
+
## Features
|
|
48
|
+
|
|
49
|
+
- Clean formulation of agents as generic entities over I/O schemas and shared context.
|
|
50
|
+
- Transparent implementation of common agentic patterns:
|
|
51
|
+
- Single-agent loops
|
|
52
|
+
- Workflows (static communication topology), including loops
|
|
53
|
+
- Agents-as-tools for task delegation
|
|
54
|
+
- Freeform A2A communication via the in-process actor model
|
|
55
|
+
- Built-in parallel processing with flexible retries and rate limiting.
|
|
56
|
+
- Support for all popular API providers via LiteLLM.
|
|
57
|
+
- Granular event streaming with separate events for LLM responses, thinking, and tool calls.
|
|
58
|
+
- Callbacks via decorators or subclassing for straightforward customisation of agentic loops and context management.
|
|
59
|
+
|
|
60
|
+
## Project Structure
|
|
61
|
+
|
|
62
|
+
- `processors/`, `llm_agent.py`: Core processor and agent class implementations.
|
|
63
|
+
- `event_bus.py`, `runner.py`: Communication management and orchestration.
|
|
64
|
+
- `llm_policy_executor.py`: LLM actions and tool call loops.
|
|
65
|
+
- `prompt_builder.py`: Tools for constructing prompts.
|
|
66
|
+
- `workflow/`: Modules for defining and managing static agent workflows.
|
|
67
|
+
- `llm.py`, `cloud_llm.py`: LLM integration and base LLM functionalities.
|
|
68
|
+
- `openai/`: Modules specific to OpenAI API integration.
|
|
69
|
+
- `litellm/`: Modules specific to LiteLLM integration.
|
|
70
|
+
- `memory.py`, `llm_agent_memory.py`: Memory management.
|
|
71
|
+
- `run_context.py`: Shared run context management.
|
|
72
|
+
|
|
73
|
+
## Usage
|
|
74
|
+
|
|
75
|
+
### Installation
|
|
76
|
+
|
|
77
|
+
Assuming your project manages dependencies through [uv](https://docs.astral.sh/uv/).
|
|
78
|
+
|
|
79
|
+
```bash
|
|
80
|
+
uv add grasp_agents
|
|
81
|
+
uv sync
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
You can of course also install using other managers like poetry or simply pip.
|
|
85
|
+
|
|
86
|
+
We recommend you use [dotenv](https://pypi.org/project/python-dotenv/) to automatically set enviroment variables from a `.env` file containting the necessary API keys, e.g.,
|
|
87
|
+
|
|
88
|
+
```
|
|
89
|
+
ANTHROPIC_API_KEY=your_anthropic_api_key
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
### Try it out
|
|
93
|
+
|
|
94
|
+
#### Jupyter Notebook Example
|
|
95
|
+
[Notebook Link](https://github.com/grasp-technologies/grasp-agents/blob/master/src/grasp_agents/examples/notebooks/agents_demo.ipynb)
|
|
96
|
+
|
|
97
|
+
#### A Grasp-Agents Powered Web App
|
|
98
|
+
[https://grasp.study/](https://grasp.study/)
|
|
99
|
+
|
|
100
|
+
#### Script Example
|
|
101
|
+
|
|
102
|
+
Create a script, e.g., `problem_recommender.py`:
|
|
103
|
+
|
|
104
|
+
```python
|
|
105
|
+
import asyncio
|
|
106
|
+
from typing import Any
|
|
107
|
+
|
|
108
|
+
from dotenv import load_dotenv
|
|
109
|
+
from pydantic import BaseModel
|
|
110
|
+
|
|
111
|
+
from grasp_agents import BaseTool, LLMAgent, RunContext
|
|
112
|
+
from grasp_agents.litellm import LiteLLM, LiteLLMSettings
|
|
113
|
+
from grasp_agents.printer import print_event_stream
|
|
114
|
+
from grasp_agents.typing.events import ProcPacketOutEvent
|
|
115
|
+
|
|
116
|
+
load_dotenv()
|
|
117
|
+
|
|
118
|
+
sys_prompt = """
|
|
119
|
+
Your task is to suggest an exciting stats problem to the student.
|
|
120
|
+
You should first ask the student about their education, interests, and preferences, then suggest a problem tailored specifically to them.
|
|
121
|
+
|
|
122
|
+
# Instructions
|
|
123
|
+
* Use the provided tool to ask questions.
|
|
124
|
+
* Ask questions one by one.
|
|
125
|
+
* The problem must have all the necessary data.
|
|
126
|
+
* Use the final answer tool to provide the problem.
|
|
127
|
+
"""
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
class TeacherQuestion(BaseModel):
|
|
131
|
+
question: str
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
StudentReply = str
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
ask_student_tool_description = """
|
|
138
|
+
"Ask the student a question and get their reply."
|
|
139
|
+
|
|
140
|
+
Args:
|
|
141
|
+
question: str
|
|
142
|
+
The question to ask the student.
|
|
143
|
+
Returns:
|
|
144
|
+
reply: str
|
|
145
|
+
The student's reply to the question.
|
|
146
|
+
"""
|
|
147
|
+
|
|
148
|
+
|
|
149
|
+
class AskStudentTool(BaseTool[TeacherQuestion, StudentReply, None]):
|
|
150
|
+
name: str = "ask_student"
|
|
151
|
+
description: str = ask_student_tool_description
|
|
152
|
+
|
|
153
|
+
async def run(self, inp: TeacherQuestion, **kwargs: Any) -> StudentReply:
|
|
154
|
+
return input(inp.question)
|
|
155
|
+
|
|
156
|
+
|
|
157
|
+
class Problem(BaseModel):
|
|
158
|
+
problem: str
|
|
159
|
+
|
|
160
|
+
|
|
161
|
+
teacher = LLMAgent[None, Problem, None](
|
|
162
|
+
name="teacher",
|
|
163
|
+
llm=LiteLLM(
|
|
164
|
+
model_name="claude-sonnet-4-5",
|
|
165
|
+
llm_settings=LiteLLMSettings(reasoning_effort="low"),
|
|
166
|
+
),
|
|
167
|
+
tools=[AskStudentTool()],
|
|
168
|
+
final_answer_as_tool_call=True,
|
|
169
|
+
sys_prompt=sys_prompt,
|
|
170
|
+
stream_llm_responses=True,
|
|
171
|
+
)
|
|
172
|
+
|
|
173
|
+
async def main():
|
|
174
|
+
ctx = RunContext[None]()
|
|
175
|
+
async for event in print_event_stream(teacher.run_stream("start", ctx=ctx)):
|
|
176
|
+
if isinstance(event, ProcPacketOutEvent):
|
|
177
|
+
result = event.data.payloads[0]
|
|
178
|
+
print(f"\n<Suggested Problem>:\n\n{result.problem}\n")
|
|
179
|
+
|
|
180
|
+
asyncio.run(main())
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
Run your script:
|
|
184
|
+
|
|
185
|
+
```bash
|
|
186
|
+
uv run problem_recommender.py
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
You can find more examples in [src/grasp_agents/examples/notebooks/agents_demo.ipynb](https://github.com/grasp-technologies/grasp-agents/tree/master/src/grasp_agents/examples/notebooks/agents_demo.ipynb).
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
# Grasp Agents
|
|
2
|
+
|
|
3
|
+
<br/>
|
|
4
|
+
<picture>
|
|
5
|
+
<source srcset="https://raw.githubusercontent.com/grasp-technologies/grasp-agents/master/.assets/grasp-dark.svg" media="(prefers-color-scheme: dark)">
|
|
6
|
+
<img src="https://raw.githubusercontent.com/grasp-technologies/grasp-agents/master/.assets/grasp.svg" alt="Grasp Agents"/>
|
|
7
|
+
</picture>
|
|
8
|
+
<br/>
|
|
9
|
+
<br/>
|
|
10
|
+
|
|
11
|
+
[](https://badge.fury.io/py/grasp-agents)
|
|
12
|
+
[](https://mit-license.org/)
|
|
13
|
+
[](https://pypi.org/project/grasp-agents/)
|
|
14
|
+
[](https://github.com/grasp-technologies/grasp-agents/stargazers)
|
|
15
|
+
[](https://github.com/grasp-technologies/grasp-agents/network/members)
|
|
16
|
+
|
|
17
|
+
## Overview
|
|
18
|
+
|
|
19
|
+
**Grasp Agents** is a modular Python framework for building agentic AI pipelines and applications. It is meant to be minimalistic but functional, allowing for rapid experimentation while keeping full and granular low-level control over prompting, LLM handling, tool call loops, and inter-agent communication by avoiding excessive higher-level abstractions.
|
|
20
|
+
|
|
21
|
+
## Features
|
|
22
|
+
|
|
23
|
+
- Clean formulation of agents as generic entities over I/O schemas and shared context.
|
|
24
|
+
- Transparent implementation of common agentic patterns:
|
|
25
|
+
- Single-agent loops
|
|
26
|
+
- Workflows (static communication topology), including loops
|
|
27
|
+
- Agents-as-tools for task delegation
|
|
28
|
+
- Freeform A2A communication via the in-process actor model
|
|
29
|
+
- Built-in parallel processing with flexible retries and rate limiting.
|
|
30
|
+
- Support for all popular API providers via LiteLLM.
|
|
31
|
+
- Granular event streaming with separate events for LLM responses, thinking, and tool calls.
|
|
32
|
+
- Callbacks via decorators or subclassing for straightforward customisation of agentic loops and context management.
|
|
33
|
+
|
|
34
|
+
## Project Structure
|
|
35
|
+
|
|
36
|
+
- `processors/`, `llm_agent.py`: Core processor and agent class implementations.
|
|
37
|
+
- `event_bus.py`, `runner.py`: Communication management and orchestration.
|
|
38
|
+
- `llm_policy_executor.py`: LLM actions and tool call loops.
|
|
39
|
+
- `prompt_builder.py`: Tools for constructing prompts.
|
|
40
|
+
- `workflow/`: Modules for defining and managing static agent workflows.
|
|
41
|
+
- `llm.py`, `cloud_llm.py`: LLM integration and base LLM functionalities.
|
|
42
|
+
- `openai/`: Modules specific to OpenAI API integration.
|
|
43
|
+
- `litellm/`: Modules specific to LiteLLM integration.
|
|
44
|
+
- `memory.py`, `llm_agent_memory.py`: Memory management.
|
|
45
|
+
- `run_context.py`: Shared run context management.
|
|
46
|
+
|
|
47
|
+
## Usage
|
|
48
|
+
|
|
49
|
+
### Installation
|
|
50
|
+
|
|
51
|
+
Assuming your project manages dependencies through [uv](https://docs.astral.sh/uv/).
|
|
52
|
+
|
|
53
|
+
```bash
|
|
54
|
+
uv add grasp_agents
|
|
55
|
+
uv sync
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
You can of course also install using other managers like poetry or simply pip.
|
|
59
|
+
|
|
60
|
+
We recommend you use [dotenv](https://pypi.org/project/python-dotenv/) to automatically set enviroment variables from a `.env` file containting the necessary API keys, e.g.,
|
|
61
|
+
|
|
62
|
+
```
|
|
63
|
+
ANTHROPIC_API_KEY=your_anthropic_api_key
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
### Try it out
|
|
67
|
+
|
|
68
|
+
#### Jupyter Notebook Example
|
|
69
|
+
[Notebook Link](https://github.com/grasp-technologies/grasp-agents/blob/master/src/grasp_agents/examples/notebooks/agents_demo.ipynb)
|
|
70
|
+
|
|
71
|
+
#### A Grasp-Agents Powered Web App
|
|
72
|
+
[https://grasp.study/](https://grasp.study/)
|
|
73
|
+
|
|
74
|
+
#### Script Example
|
|
75
|
+
|
|
76
|
+
Create a script, e.g., `problem_recommender.py`:
|
|
77
|
+
|
|
78
|
+
```python
|
|
79
|
+
import asyncio
|
|
80
|
+
from typing import Any
|
|
81
|
+
|
|
82
|
+
from dotenv import load_dotenv
|
|
83
|
+
from pydantic import BaseModel
|
|
84
|
+
|
|
85
|
+
from grasp_agents import BaseTool, LLMAgent, RunContext
|
|
86
|
+
from grasp_agents.litellm import LiteLLM, LiteLLMSettings
|
|
87
|
+
from grasp_agents.printer import print_event_stream
|
|
88
|
+
from grasp_agents.typing.events import ProcPacketOutEvent
|
|
89
|
+
|
|
90
|
+
load_dotenv()
|
|
91
|
+
|
|
92
|
+
sys_prompt = """
|
|
93
|
+
Your task is to suggest an exciting stats problem to the student.
|
|
94
|
+
You should first ask the student about their education, interests, and preferences, then suggest a problem tailored specifically to them.
|
|
95
|
+
|
|
96
|
+
# Instructions
|
|
97
|
+
* Use the provided tool to ask questions.
|
|
98
|
+
* Ask questions one by one.
|
|
99
|
+
* The problem must have all the necessary data.
|
|
100
|
+
* Use the final answer tool to provide the problem.
|
|
101
|
+
"""
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
class TeacherQuestion(BaseModel):
|
|
105
|
+
question: str
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
StudentReply = str
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
ask_student_tool_description = """
|
|
112
|
+
"Ask the student a question and get their reply."
|
|
113
|
+
|
|
114
|
+
Args:
|
|
115
|
+
question: str
|
|
116
|
+
The question to ask the student.
|
|
117
|
+
Returns:
|
|
118
|
+
reply: str
|
|
119
|
+
The student's reply to the question.
|
|
120
|
+
"""
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
class AskStudentTool(BaseTool[TeacherQuestion, StudentReply, None]):
|
|
124
|
+
name: str = "ask_student"
|
|
125
|
+
description: str = ask_student_tool_description
|
|
126
|
+
|
|
127
|
+
async def run(self, inp: TeacherQuestion, **kwargs: Any) -> StudentReply:
|
|
128
|
+
return input(inp.question)
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
class Problem(BaseModel):
|
|
132
|
+
problem: str
|
|
133
|
+
|
|
134
|
+
|
|
135
|
+
teacher = LLMAgent[None, Problem, None](
|
|
136
|
+
name="teacher",
|
|
137
|
+
llm=LiteLLM(
|
|
138
|
+
model_name="claude-sonnet-4-5",
|
|
139
|
+
llm_settings=LiteLLMSettings(reasoning_effort="low"),
|
|
140
|
+
),
|
|
141
|
+
tools=[AskStudentTool()],
|
|
142
|
+
final_answer_as_tool_call=True,
|
|
143
|
+
sys_prompt=sys_prompt,
|
|
144
|
+
stream_llm_responses=True,
|
|
145
|
+
)
|
|
146
|
+
|
|
147
|
+
async def main():
|
|
148
|
+
ctx = RunContext[None]()
|
|
149
|
+
async for event in print_event_stream(teacher.run_stream("start", ctx=ctx)):
|
|
150
|
+
if isinstance(event, ProcPacketOutEvent):
|
|
151
|
+
result = event.data.payloads[0]
|
|
152
|
+
print(f"\n<Suggested Problem>:\n\n{result.problem}\n")
|
|
153
|
+
|
|
154
|
+
asyncio.run(main())
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
Run your script:
|
|
158
|
+
|
|
159
|
+
```bash
|
|
160
|
+
uv run problem_recommender.py
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
You can find more examples in [src/grasp_agents/examples/notebooks/agents_demo.ipynb](https://github.com/grasp-technologies/grasp-agents/tree/master/src/grasp_agents/examples/notebooks/agents_demo.ipynb).
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "grasp_agents_legacy"
|
|
3
|
+
version = "0.6.50"
|
|
4
|
+
description = "Grasp Agents Library"
|
|
5
|
+
readme = "README.md"
|
|
6
|
+
requires-python = ">=3.11.4,<4"
|
|
7
|
+
dependencies = [
|
|
8
|
+
"httpx>=0.27.0,<1",
|
|
9
|
+
"openai>=1.68.2,<3",
|
|
10
|
+
"tenacity>=8.3.0,<9",
|
|
11
|
+
"tqdm>=4.66.2,<5",
|
|
12
|
+
"pyyaml>=6.0.2",
|
|
13
|
+
"pydantic>=2",
|
|
14
|
+
"litellm==1.83.10",
|
|
15
|
+
"opentelemetry-sdk>=1.37.0",
|
|
16
|
+
"traceloop-sdk>=0.47.2",
|
|
17
|
+
"termcolor>=2.4.0,<3",
|
|
18
|
+
"python-dotenv>=1.0",
|
|
19
|
+
"google-genai>=1.45.0",
|
|
20
|
+
"numpy<2",
|
|
21
|
+
]
|
|
22
|
+
|
|
23
|
+
[dependency-groups]
|
|
24
|
+
dev = [
|
|
25
|
+
"ipython>=8.3.0,<9",
|
|
26
|
+
"ipykernel>=6.19.1,<7",
|
|
27
|
+
"ipywidgets>=8.0.4,<9",
|
|
28
|
+
"widgetsnbextension>=4.0.5,<5",
|
|
29
|
+
"types-cachetools>=5.0.1,<6",
|
|
30
|
+
"pre-commit-uv>=4.1.4",
|
|
31
|
+
"twine>=5.1.1,<6",
|
|
32
|
+
"ruff>=0.11.8",
|
|
33
|
+
"pyright>=1.1.400",
|
|
34
|
+
"pip-licenses>=5.0.0",
|
|
35
|
+
"pytest>=8,<9",
|
|
36
|
+
]
|
|
37
|
+
|
|
38
|
+
[project.optional-dependencies]
|
|
39
|
+
observability = [
|
|
40
|
+
"arize-phoenix-otel>=0.13.1",
|
|
41
|
+
"openinference-instrumentation-openllmetry>=0.1.2",
|
|
42
|
+
"openinference-instrumentation-openai>=0.1.32",
|
|
43
|
+
"openinference-instrumentation-litellm>=0.1.25",
|
|
44
|
+
]
|
|
45
|
+
|
|
46
|
+
[build-system]
|
|
47
|
+
requires = ["hatchling"]
|
|
48
|
+
build-backend = "hatchling.build"
|
|
49
|
+
|
|
50
|
+
[tool.hatch.build.targets.sdist]
|
|
51
|
+
include = ["src/grasp_agents_legacy"]
|
|
52
|
+
exclude = ["src/grasp_agents_legacy/examples", "*.ipynb"]
|
|
53
|
+
|
|
54
|
+
[tool.hatch.build.targets.wheel]
|
|
55
|
+
packages = ["src/grasp_agents_legacy"]
|
|
56
|
+
exclude = ["src/grasp_agents_legacy/examples", "*.ipynb"]
|
|
57
|
+
|
|
58
|
+
[tool.hatch.metadata]
|
|
59
|
+
allow-direct-references = true
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# pyright: reportUnusedImport=false
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
from .llm import LLM, LLMSettings
|
|
5
|
+
from .llm_agent import LLMAgent
|
|
6
|
+
from .llm_agent_memory import LLMAgentMemory
|
|
7
|
+
from .memory import Memory
|
|
8
|
+
from .packet import Packet
|
|
9
|
+
from .printer import Printer, print_event_stream
|
|
10
|
+
from .processors.base_processor import BaseProcessor
|
|
11
|
+
from .processors.parallel_processor import ParallelProcessor
|
|
12
|
+
from .processors.processor import Processor
|
|
13
|
+
from .run_context import RunContext
|
|
14
|
+
from .typing.completion import Completion
|
|
15
|
+
from .typing.content import Content, ImageData
|
|
16
|
+
from .typing.io import LLMPrompt, ProcName
|
|
17
|
+
from .typing.message import AssistantMessage, Messages, SystemMessage, UserMessage
|
|
18
|
+
from .typing.tool import BaseTool
|
|
19
|
+
|
|
20
|
+
__all__ = [
|
|
21
|
+
"LLM",
|
|
22
|
+
"AssistantMessage",
|
|
23
|
+
"BaseProcessor",
|
|
24
|
+
"BaseTool",
|
|
25
|
+
"Completion",
|
|
26
|
+
"Content",
|
|
27
|
+
"ImageData",
|
|
28
|
+
"LLMAgent",
|
|
29
|
+
"LLMAgentMemory",
|
|
30
|
+
"LLMPrompt",
|
|
31
|
+
"LLMSettings",
|
|
32
|
+
"Memory",
|
|
33
|
+
"Messages",
|
|
34
|
+
"Packet",
|
|
35
|
+
"Packet",
|
|
36
|
+
"ParallelProcessor",
|
|
37
|
+
"Printer",
|
|
38
|
+
"ProcName",
|
|
39
|
+
"Processor",
|
|
40
|
+
"RunContext",
|
|
41
|
+
"SystemMessage",
|
|
42
|
+
"UserMessage",
|
|
43
|
+
"print_event_stream",
|
|
44
|
+
]
|