cave-agent 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.
@@ -0,0 +1,210 @@
1
+ # Created by https://www.toptal.com/developers/gitignore/api/macos,python
2
+ # Edit at https://www.toptal.com/developers/gitignore?templates=macos,python
3
+
4
+ ### macOS ###
5
+ # General
6
+ .DS_Store
7
+ .AppleDouble
8
+ .LSOverride
9
+
10
+ # Icon must end with two \r
11
+ Icon
12
+
13
+
14
+ # Thumbnails
15
+ ._*
16
+
17
+ # Files that might appear in the root of a volume
18
+ .DocumentRevisions-V100
19
+ .fseventsd
20
+ .Spotlight-V100
21
+ .TemporaryItems
22
+ .Trashes
23
+ .VolumeIcon.icns
24
+ .com.apple.timemachine.donotpresent
25
+
26
+ # Directories potentially created on remote AFP share
27
+ .AppleDB
28
+ .AppleDesktop
29
+ Network Trash Folder
30
+ Temporary Items
31
+ .apdisk
32
+
33
+ ### macOS Patch ###
34
+ # iCloud generated files
35
+ *.icloud
36
+
37
+ ### Python ###
38
+ # Byte-compiled / optimized / DLL files
39
+ __pycache__/
40
+ *.py[cod]
41
+ *$py.class
42
+
43
+ # C extensions
44
+ *.so
45
+
46
+ # Distribution / packaging
47
+ .Python
48
+ build/
49
+ develop-eggs/
50
+ dist/
51
+ downloads/
52
+ eggs/
53
+ .eggs/
54
+ lib/
55
+ lib64/
56
+ parts/
57
+ sdist/
58
+ var/
59
+ wheels/
60
+ share/python-wheels/
61
+ *.egg-info/
62
+ .installed.cfg
63
+ *.egg
64
+ MANIFEST
65
+
66
+ # PyInstaller
67
+ # Usually these files are written by a python script from a template
68
+ # before PyInstaller builds the exe, so as to inject date/other infos into it.
69
+ *.manifest
70
+ *.spec
71
+
72
+ # Installer logs
73
+ pip-log.txt
74
+ pip-delete-this-directory.txt
75
+
76
+ # Unit test / coverage reports
77
+ htmlcov/
78
+ .tox/
79
+ .nox/
80
+ .coverage
81
+ .coverage.*
82
+ .cache
83
+ nosetests.xml
84
+ coverage.xml
85
+ *.cover
86
+ *.py,cover
87
+ .hypothesis/
88
+ .pytest_cache/
89
+ cover/
90
+
91
+ # Translations
92
+ *.mo
93
+ *.pot
94
+
95
+ # Django stuff:
96
+ *.log
97
+ local_settings.py
98
+ db.sqlite3
99
+ db.sqlite3-journal
100
+
101
+ # Flask stuff:
102
+ instance/
103
+ .webassets-cache
104
+
105
+ # Scrapy stuff:
106
+ .scrapy
107
+
108
+ # Sphinx documentation
109
+ docs/_build/
110
+
111
+ # PyBuilder
112
+ .pybuilder/
113
+ target/
114
+
115
+ # Jupyter Notebook
116
+ .ipynb_checkpoints
117
+
118
+ # IPython
119
+ profile_default/
120
+ ipython_config.py
121
+
122
+ # pyenv
123
+ # For a library or package, you might want to ignore these files since the code is
124
+ # intended to run in multiple environments; otherwise, check them in:
125
+ # .python-version
126
+
127
+ # pipenv
128
+ # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
129
+ # However, in case of collaboration, if having platform-specific dependencies or dependencies
130
+ # having no cross-platform support, pipenv may install dependencies that don't work, or not
131
+ # install all needed dependencies.
132
+ #Pipfile.lock
133
+
134
+ # poetry
135
+ # Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
136
+ # This is especially recommended for binary packages to ensure reproducibility, and is more
137
+ # commonly ignored for libraries.
138
+ # https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
139
+ #poetry.lock
140
+
141
+ # pdm
142
+ # Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
143
+ #pdm.lock
144
+ # pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
145
+ # in version control.
146
+ # https://pdm.fming.dev/#use-with-ide
147
+ .pdm.toml
148
+
149
+ # PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
150
+ __pypackages__/
151
+
152
+ # Celery stuff
153
+ celerybeat-schedule
154
+ celerybeat.pid
155
+
156
+ # SageMath parsed files
157
+ *.sage.py
158
+
159
+ # Environments
160
+ .env
161
+ .env.*
162
+ .venv
163
+ env/
164
+ venv/
165
+ ENV/
166
+ env.bak/
167
+ venv.bak/
168
+
169
+ # Spyder project settings
170
+ .spyderproject
171
+ .spyproject
172
+
173
+ # Rope project settings
174
+ .ropeproject
175
+
176
+ # mkdocs documentation
177
+ /site
178
+
179
+ # mypy
180
+ .mypy_cache/
181
+ .dmypy.json
182
+ dmypy.json
183
+
184
+ # Pyre type checker
185
+ .pyre/
186
+
187
+ # pytype static type analyzer
188
+ .pytype/
189
+
190
+ # Cython debug symbols
191
+ cython_debug/
192
+
193
+ # PyCharm
194
+ # JetBrains specific template is maintained in a separate JetBrains.gitignore that can
195
+ # be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
196
+ # and can be added to the global gitignore or merged into this file. For a more nuclear
197
+ # option (not recommended) you can uncomment the following to ignore the entire idea folder.
198
+ .idea/
199
+
200
+ ### Python Patch ###
201
+ # Poetry local configuration file - https://python-poetry.org/docs/configuration/#local-configuration
202
+ poetry.toml
203
+
204
+ # ruff
205
+ .ruff_cache/
206
+
207
+ # LSP config files
208
+ pyrightconfig.json
209
+
210
+ # End of https://www.toptal.com/developers/gitignore/api/macos,python
@@ -0,0 +1,21 @@
1
+ ## Contribute to CaveAgent
2
+
3
+ We welcome contributions to CaveAgent! Here's how you can help:
4
+
5
+ ### Types of Contributions
6
+
7
+ - Bug fixes
8
+ - Feature additions
9
+ - Documentation improvements
10
+ - Test coverage improvements
11
+
12
+ ### Development Process
13
+
14
+ 1. Fork the repository
15
+ 2. Create a feature branch (`git checkout -b feature/amazing-feature`)
16
+ 3. Make your changes
17
+ 4. Run tests to ensure everything works
18
+ 5. Commit your changes (`git commit -m 'Add amazing feature'`)
19
+ 6. Push to your branch (`git push origin feature/amazing-feature`)
20
+ 7. Open a Pull Request
21
+
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Ram, Copper
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,346 @@
1
+ Metadata-Version: 2.4
2
+ Name: cave-agent
3
+ Version: 0.5.0
4
+ Summary: A Python agent framework that enables function-calling through LLM code generation
5
+ Project-URL: Homepage, https://github.com/acodercat/cave-agent
6
+ Project-URL: Repository, https://github.com/acodercat/cave-agent
7
+ Author-email: Ram <codermao@gmail.com>, Cooper <cooperimmaculate@gmail.com>
8
+ License-File: LICENSE
9
+ Keywords: agent,function-calling,llm
10
+ Classifier: Development Status :: 3 - Alpha
11
+ Classifier: Intended Audience :: Developers
12
+ Classifier: License :: OSI Approved :: MIT License
13
+ Classifier: Programming Language :: Python :: 3.11
14
+ Classifier: Programming Language :: Python :: 3.12
15
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
16
+ Requires-Python: >=3.11
17
+ Requires-Dist: ipython>=9.0.2
18
+ Requires-Dist: rich>=13.9.4
19
+ Provides-Extra: all
20
+ Requires-Dist: litellm>=1.73.0; extra == 'all'
21
+ Requires-Dist: openai>=1.91.0; extra == 'all'
22
+ Provides-Extra: litellm
23
+ Requires-Dist: litellm>=1.73.0; extra == 'litellm'
24
+ Provides-Extra: openai
25
+ Requires-Dist: openai>=1.91.0; extra == 'openai'
26
+ Description-Content-Type: text/markdown
27
+
28
+ # 🤖 CaveAgent
29
+ **🚀 AI that executes, not just generates!**
30
+
31
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
32
+ [![Python 3.11+](https://img.shields.io/badge/python-3.11+-blue.svg)](https://www.python.org/downloads/)
33
+ [![PyPI version](https://img.shields.io/badge/pypi-0.4.4-blue.svg)](https://pypi.org/project/cave-agent)
34
+
35
+ CaveAgent is a tool-augmented agent framework that enables function-calling through LLM code generation and provides runtime state management. Unlike traditional JSON-schema approaches, it leverages LLM's inherent coding capabilities to interact with tools through a Python runtime environment, allowing direct access to execution results and runtime state.
36
+
37
+ > *"When your AI needs to run code, not just write it"*
38
+
39
+ ## Why CaveAgent?
40
+
41
+ **Traditional function calling is broken.** JSON schemas are rigid, error-prone, and limit what your AI can do. CaveAgent unleashes your LLM's natural coding abilities:
42
+
43
+ - 🧠 **Native Code Generation** - LLMs excel at writing code, not parsing JSON
44
+ - ⚡ **Fewer Iterations** - Execute complex multi-step workflows in a single turn
45
+ - 🔄 **Persistent State** - Maintain variables and objects across conversations
46
+ - 🎯 **Maximum Flexibility** - Handle dynamic workflows that JSON schemas can't express
47
+ - 🛡️ **Secure by Design** - AST validation prevents dangerous code execution
48
+ - 📡 **Real-time Streaming** - Watch your AI think and execute in real-time
49
+ - 🌐 **Universal LLM Support** - Works with OpenAI, Anthropic, Google, and 100+ providers
50
+
51
+ ## Quick Start
52
+
53
+ ```bash
54
+ pip install 'cave-agent[all]'
55
+ ```
56
+
57
+ Choose your installation:
58
+
59
+ ```bash
60
+ # OpenAI support
61
+ pip install 'cave-agent[openai]'
62
+
63
+ # 100+ LLM providers via LiteLLM
64
+ pip install 'cave-agent[litellm]'
65
+ ```
66
+
67
+ ### Simple Function Calling
68
+
69
+ ```python
70
+ import asyncio
71
+ from cave_agent import CaveAgent
72
+ from cave_agent.models import OpenAIServerModel
73
+ from cave_agent.python_runtime import PythonRuntime, Function, Variable
74
+
75
+ async def main():
76
+ # Initialize LLM model
77
+ model = OpenAIServerModel(
78
+ model_id="your-model",
79
+ api_key="your-api-key",
80
+ base_url="your-base-url"
81
+ )
82
+
83
+ # Define tool functions
84
+ def add_task(task_name: str) -> str:
85
+ """Add a new task to the task list"""
86
+ tasks.append({"name": task_name, "done": False})
87
+ return f"Added task: {task_name}"
88
+
89
+ def complete_task(task_name: str) -> str:
90
+ """Mark a task as completed"""
91
+ for task in tasks:
92
+ if task_name.lower() in task["name"].lower():
93
+ task["done"] = True
94
+ return f"Completed: {task['name']}"
95
+ return f"Task '{task_name}' not found"
96
+
97
+ def send_reminder(message: str) -> str:
98
+ """Send a reminder notification"""
99
+ return f"Reminder: {message}"
100
+
101
+ # Initialize data
102
+ tasks = []
103
+
104
+ # Setup Runtime
105
+ runtime = PythonRuntime(
106
+ variables=[
107
+ Variable("tasks", tasks, "List of user's tasks. Example: [{'name': 'walk the dog', 'done': False}]")
108
+ ],
109
+ functions=[
110
+ Function(add_task),
111
+ Function(complete_task),
112
+ Function(send_reminder)
113
+ ]
114
+ )
115
+
116
+ agent = CaveAgent(model, runtime=runtime)
117
+
118
+ await agent.run("Add buy groceries and call mom to my tasks")
119
+ print(f"Current tasks: {runtime.get_variable_value('tasks')}")
120
+
121
+ await agent.run("Mark groceries done and remind me about mom")
122
+ print(f"Final state: {runtime.get_variable_value('tasks')}")
123
+
124
+ response = await agent.run("What's my progress?")
125
+ print(response.content)
126
+
127
+ if __name__ == "__main__":
128
+ asyncio.run(main())
129
+ ```
130
+
131
+ ### Advanced: Stateful Object Interactions
132
+
133
+ ```python
134
+ import asyncio
135
+ from cave_agent import CaveAgent
136
+ from cave_agent.models import LiteLLMModel
137
+ from cave_agent.python_runtime import PythonRuntime, Function, Variable
138
+
139
+ async def main():
140
+ # Initialize LLM model
141
+ model = LiteLLMModel(
142
+ model_id="your-model",
143
+ api_key="your-api-key",
144
+ base_url="your-base-url"
145
+ )
146
+
147
+ # Define a class with methods
148
+ class DataProcessor:
149
+ """A utility class for processing and filtering data collections.
150
+
151
+ This class provides methods for basic data processing operations such as
152
+ sorting, removing duplicates, and filtering based on thresholds.
153
+
154
+ Example:
155
+ >>> processor = DataProcessor()
156
+ >>> processor.process_list([3, 1, 2, 1, 3])
157
+ [1, 2, 3]
158
+ >>> processor.filter_numbers([1, 5, 3, 8, 2], 4)
159
+ [5, 8]
160
+ """
161
+ def process_list(self, data: list) -> list:
162
+ """Sort a list and remove duplicates"""
163
+ return sorted(set(data))
164
+
165
+ def filter_numbers(self, data: list, threshold: int) -> list:
166
+ """Filter numbers greater than threshold"""
167
+ return [x for x in data if x > threshold]
168
+
169
+ # Prepare context
170
+ processor = DataProcessor()
171
+ numbers = [3, 1, 4, 1, 5, 9, 2, 6, 5]
172
+
173
+ # Create runtime with variables and functions
174
+ runtime = PythonRuntime(
175
+ variables=[
176
+ Variable(
177
+ name="processor",
178
+ value=processor,
179
+ description="Data processing tool with various methods"
180
+ ),
181
+ Variable(
182
+ name="numbers",
183
+ value=numbers,
184
+ description="Input list of numbers"
185
+ ),
186
+ Variable(
187
+ name="processed_data",
188
+ description="Store processed data in this variable"
189
+ ),
190
+ Variable(
191
+ name="filtered_data",
192
+ description="Store filtered data in this variable"
193
+ )
194
+ ]
195
+ )
196
+
197
+ # Create agent
198
+ agent = CaveAgent(model, runtime=runtime)
199
+
200
+ # Process data
201
+ await agent.run("Use processor to sort and deduplicate numbers")
202
+ processed_data = agent.runtime.get_variable_value('processed_data')
203
+ print("Processed data:", processed_data)
204
+
205
+ # Filter data
206
+ await agent.run("Filter numbers greater than 4")
207
+ filtered_data = agent.runtime.get_variable_value('filtered_data')
208
+ print("Filtered data:", filtered_data)
209
+
210
+ if __name__ == "__main__":
211
+ asyncio.run(main())
212
+ ```
213
+
214
+ ### Real-time Streaming
215
+
216
+ Watch your AI think and execute code in real-time:
217
+
218
+ ```python
219
+ async for event in agent.stream_events("Analyze this data and create a summary"):
220
+ if event.type.value == 'CODE':
221
+ print(f"🔧 Executing: {event.content}")
222
+ elif event.type.value == 'EXECUTION_RESULT':
223
+ print(f"✅ Result: {event.content}")
224
+ elif event.type.value == 'TEXT':
225
+ print(event.content, end="", flush=True)
226
+ ```
227
+
228
+ ### Security Features
229
+
230
+ CaveAgent includes rule-based security to prevent dangerous code execution:
231
+
232
+ ```python
233
+ import asyncio
234
+ from cave_agent import CaveAgent
235
+ from cave_agent.models import OpenAIServerModel
236
+ from cave_agent.python_runtime import PythonRuntime
237
+ from cave_agent.security_checker import (
238
+ SecurityChecker, ImportRule, FunctionRule, AttributeRule, RegexRule
239
+ )
240
+
241
+ async def main():
242
+ model = OpenAIServerModel(
243
+ model_id="gpt-4",
244
+ api_key="your-api-key",
245
+ base_url="https://api.openai.com/v1"
246
+ )
247
+
248
+ # Configure security with specific rules
249
+ rules = [
250
+ ImportRule({"os", "subprocess", "sys", "socket"}), # Block dangerous imports
251
+ FunctionRule({"eval", "exec", "compile", "open"}), # Block dangerous functions
252
+ AttributeRule({"__globals__", "__builtins__"}), # Block attribute access
253
+ RegexRule("no_print", "Block print statements", r"print\s*\(") # Custom regex
254
+ ]
255
+
256
+ checker = SecurityChecker(rules)
257
+ runtime = PythonRuntime(security_checker=checker)
258
+
259
+ agent = CaveAgent(model, runtime=runtime)
260
+
261
+ # This will be blocked by security
262
+ try:
263
+ await agent.run("import os and list files")
264
+ except Exception as e:
265
+ print(f"Blocked: {e}")
266
+
267
+ if __name__ == "__main__":
268
+ asyncio.run(main())
269
+ ```
270
+
271
+ ## Key Features
272
+
273
+ - **🤖 Code-Based Function Calling**: Leverages LLM's natural coding abilities instead of rigid JSON schemas
274
+ - **🛡️ Secure Runtime Environment**:
275
+ - Inject Python objects, variables, and functions as tools
276
+ - Rule-based security validation prevents dangerous code execution
277
+ - Flexible security rules: ImportRule, FunctionRule, AttributeRule, RegexRule
278
+ - Customizable security policies for different use cases
279
+ - Access execution results and maintain state across interactions
280
+ - **💬 Multi-Turn Conversations**: Persistent context and runtime state across multiple interactions
281
+ - **⚡ Streaming & Async**: Real-time event streaming and full async/await support for optimal performance
282
+ - **🛡️ Execution Control**: Configurable step limits and error handling to prevent infinite loops
283
+ - **🎯 Unmatched Flexibility**: JSON schemas break with dynamic workflows. Python code adapts to any situation - conditional logic, loops, and complex data transformations.
284
+ - **🌐 Flexible LLM Support**: Works with any LLM provider via OpenAI-compatible APIs or LiteLLM
285
+
286
+ ## Real-World Examples
287
+
288
+ For more examples, check out the [examples](examples) directory:
289
+
290
+ - [Basic Usage](examples/basic_usage.py): Simple function calling and object processing
291
+ - [Runtime State](examples/runtime_state.py): Managing runtime state across interactions
292
+ - [Object Methods](examples/object_methods.py): Using class methods and complex objects
293
+ - [Multi-Turn](examples/multi_turn.py): Complex analysis conversations with state persistence
294
+ - [Stream](examples/stream.py): Streaming responses and execution events
295
+
296
+ ## LLM Provider Support
297
+
298
+ CaveAgent supports multiple LLM providers:
299
+
300
+ ### OpenAI-Compatible Models
301
+ ```python
302
+ from cave_agent.models import OpenAIServerModel
303
+
304
+ model = OpenAIServerModel(
305
+ model_id="gpt-4",
306
+ api_key="your-api-key",
307
+ base_url="https://api.openai.com/v1" # or your custom endpoint
308
+ )
309
+ ```
310
+
311
+ ### LiteLLM Models (Recommended)
312
+ LiteLLM provides unified access to hundreds of LLM providers:
313
+
314
+ ```python
315
+ from cave_agent.models import LiteLLMModel
316
+
317
+ # OpenAI
318
+ model = LiteLLMModel(
319
+ model_id="gpt-4",
320
+ api_key="your-api-key",
321
+ custom_llm_provider='openai'
322
+ )
323
+
324
+ # Anthropic Claude
325
+ model = LiteLLMModel(
326
+ model_id="claude-3-sonnet-20240229",
327
+ api_key="your-api-key",
328
+ custom_llm_provider='anthropic'
329
+ )
330
+
331
+ # Google Gemini
332
+ model = LiteLLMModel(
333
+ model_id="gemini/gemini-pro",
334
+ api_key="your-api-key"
335
+ )
336
+ ```
337
+
338
+
339
+ ## Contributing
340
+
341
+ Contributions are welcome! Please feel free to submit a PR.
342
+ For more details, see [CONTRIBUTING.md](CONTRIBUTING.md).
343
+
344
+ ## License
345
+
346
+ MIT License - see [LICENSE](LICENSE) for details.