Name | py-calling-agent JSON |
Version |
0.3.3
JSON |
| download |
home_page | None |
Summary | A Python agent framework that enables function-calling through LLM code generation |
upload_time | 2025-07-29 08:23:03 |
maintainer | None |
docs_url | None |
author | None |
requires_python | >=3.11 |
license | None |
keywords |
agent
function-calling
llm
|
VCS |
 |
bugtrack_url |
|
requirements |
No requirements were recorded.
|
Travis-CI |
No Travis.
|
coveralls test coverage |
No coveralls.
|
# 🤖 PyCallingAgent
**🚀 AI that executes, not just generates!**
[](https://opensource.org/licenses/MIT)
[](https://www.python.org/downloads/)
[](https://pypi.org/project/py-calling-agent)
PyCallingAgent 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.
> *"When your AI needs to run code, not just write it"*
## Why PyCallingAgent?
**Traditional function calling is broken.** JSON schemas are rigid, error-prone, and limit what your AI can do. PyCallingAgent unleashes your LLM's natural coding abilities:
- 🧠 **Native Code Generation** - LLMs excel at writing code, not parsing JSON
- ⚡ **Fewer Iterations** - Execute complex multi-step workflows in a single turn
- 🔄 **Persistent State** - Maintain variables and objects across conversations
- 🎯 **Maximum Flexibility** - Handle dynamic workflows that JSON schemas can't express
- 🛡️ **Secure by Design** - AST validation prevents dangerous code execution
- 📡 **Real-time Streaming** - Watch your AI think and execute in real-time
- 🌐 **Universal LLM Support** - Works with OpenAI, Anthropic, Google, and 100+ providers
## Quick Start
```bash
pip install 'py-calling-agent[all]'
```
Choose your installation:
```bash
# OpenAI support
pip install 'py-calling-agent[openai]'
# 100+ LLM providers via LiteLLM
pip install 'py-calling-agent[litellm]'
```
### Simple Function Calling
```python
import asyncio
from py_calling_agent import PyCallingAgent
from py_calling_agent.models import OpenAIServerModel
from py_calling_agent.python_runtime import PythonRuntime, Function, Variable
async def main():
# Initialize LLM model
model = OpenAIServerModel(
model_id="your-model",
api_key="your-api-key",
base_url="your-base-url"
)
# Define tool functions
def add_task(task_name: str) -> str:
"""Add a new task to the task list"""
tasks.append({"name": task_name, "done": False})
return f"Added task: {task_name}"
def complete_task(task_name: str) -> str:
"""Mark a task as completed"""
for task in tasks:
if task_name.lower() in task["name"].lower():
task["done"] = True
return f"Completed: {task['name']}"
return f"Task '{task_name}' not found"
def send_reminder(message: str) -> str:
"""Send a reminder notification"""
return f"Reminder: {message}"
# Initialize data
tasks = []
# Setup Runtime
runtime = PythonRuntime(
variables=[
Variable("tasks", tasks, "List of user's tasks. Example: [{'name': 'walk the dog', 'done': False}]")
],
functions=[
Function(add_task),
Function(complete_task),
Function(send_reminder)
]
)
agent = PyCallingAgent(model, runtime=runtime)
await agent.run("Add buy groceries and call mom to my tasks")
print(f"Current tasks: {runtime.get_variable_value('tasks')}")
await agent.run("Mark groceries done and remind me about mom")
print(f"Final state: {runtime.get_variable_value('tasks')}")
response = await agent.run("What's my progress?")
print(response.content)
if __name__ == "__main__":
asyncio.run(main())
```
### Advanced: Stateful Object Interactions
```python
import asyncio
from py_calling_agent import PyCallingAgent
from py_calling_agent.models import LiteLLMModel
from py_calling_agent.python_runtime import PythonRuntime, Function, Variable
async def main():
# Initialize LLM model
model = LiteLLMModel(
model_id="your-model",
api_key="your-api-key",
base_url="your-base-url"
)
# Define a class with methods
class DataProcessor:
"""A utility class for processing and filtering data collections.
This class provides methods for basic data processing operations such as
sorting, removing duplicates, and filtering based on thresholds.
Example:
>>> processor = DataProcessor()
>>> processor.process_list([3, 1, 2, 1, 3])
[1, 2, 3]
>>> processor.filter_numbers([1, 5, 3, 8, 2], 4)
[5, 8]
"""
def process_list(self, data: list) -> list:
"""Sort a list and remove duplicates"""
return sorted(set(data))
def filter_numbers(self, data: list, threshold: int) -> list:
"""Filter numbers greater than threshold"""
return [x for x in data if x > threshold]
# Prepare context
processor = DataProcessor()
numbers = [3, 1, 4, 1, 5, 9, 2, 6, 5]
# Create runtime with variables and functions
runtime = PythonRuntime(
variables=[
Variable(
name="processor",
value=processor,
description="Data processing tool with various methods"
),
Variable(
name="numbers",
value=numbers,
description="Input list of numbers"
),
Variable(
name="processed_data",
description="Store processed data in this variable"
),
Variable(
name="filtered_data",
description="Store filtered data in this variable"
)
]
)
# Create agent
agent = PyCallingAgent(model, runtime=runtime)
# Process data
await agent.run("Use processor to sort and deduplicate numbers")
processed_data = agent.runtime.get_variable_value('processed_data')
print("Processed data:", processed_data)
# Filter data
await agent.run("Filter numbers greater than 4")
filtered_data = agent.runtime.get_variable_value('filtered_data')
print("Filtered data:", filtered_data)
if __name__ == "__main__":
asyncio.run(main())
```
### Real-time Streaming
Watch your AI think and execute code in real-time:
```python
async for event in agent.stream_events("Analyze this data and create a summary"):
if event.type.value == 'CODE':
print(f"🔧 Executing: {event.content}")
elif event.type.value == 'EXECUTION_RESULT':
print(f"✅ Result: {event.content}")
elif event.type.value == 'TEXT':
print(event.content, end="", flush=True)
```
## Key Features
- **🤖 Code-Based Function Calling**: Leverages LLM's natural coding abilities instead of rigid JSON schemas
- **🔧 Secure Runtime Environment**:
- Inject Python objects, variables, and functions as tools
- AST-based security validation prevents dangerous code execution
- Access execution results and maintain state across interactions
- **💬 Multi-Turn Conversations**: Persistent context and runtime state across multiple interactions
- **⚡ Streaming & Async**: Real-time event streaming and full async/await support for optimal performance
- **🛡️ Execution Control**: Configurable step limits and error handling to prevent infinite loops
- **🎯 Unmatched Flexibility**: JSON schemas break with dynamic workflows. Python code adapts to any situation - conditional logic, loops, and complex data transformations.
- **🌐 Flexible LLM Support**: Works with any LLM provider via OpenAI-compatible APIs or LiteLLM
## Real-World Examples
For more examples, check out the [examples](examples) directory:
- [Basic Usage](examples/basic_usage.py): Simple function calling and object processing
- [Runtime State](examples/runtime_state.py): Managing runtime state across interactions
- [Object Methods](examples/object_methods.py): Using class methods and complex objects
- [Multi-Turn](examples/multi_turn.py): Complex analysis conversations with state persistence
- [Stream](examples/stream.py): Streaming responses and execution events
## LLM Provider Support
PyCallingAgent supports multiple LLM providers:
### OpenAI-Compatible Models
```python
from py_calling_agent.models import OpenAIServerModel
model = OpenAIServerModel(
model_id="gpt-4",
api_key="your-api-key",
base_url="https://api.openai.com/v1" # or your custom endpoint
)
```
### LiteLLM Models (Recommended)
LiteLLM provides unified access to hundreds of LLM providers:
```python
from py_calling_agent.models import LiteLLMModel
# OpenAI
model = LiteLLMModel(
model_id="gpt-4",
api_key="your-api-key",
custom_llm_provider='openai'
)
# Anthropic Claude
model = LiteLLMModel(
model_id="claude-3-sonnet-20240229",
api_key="your-api-key",
custom_llm_provider='anthropic'
)
# Google Gemini
model = LiteLLMModel(
model_id="gemini/gemini-pro",
api_key="your-api-key"
)
```
## Contributing
Contributions are welcome! Please feel free to submit a PR.
For more details, see [CONTRIBUTING.md](CONTRIBUTING.md).
## License
MIT License - see [LICENSE](LICENSE) for details.
Raw data
{
"_id": null,
"home_page": null,
"name": "py-calling-agent",
"maintainer": null,
"docs_url": null,
"requires_python": ">=3.11",
"maintainer_email": null,
"keywords": "agent, function-calling, llm",
"author": null,
"author_email": "Ram <codermao@gmail.com>, Cooper <cooperimmaculate@gmail.com>",
"download_url": "https://files.pythonhosted.org/packages/ce/f9/5059dd9db008a40c9221799e8b13f5e254e68b21828bdafdd448e8ecaa7f/py_calling_agent-0.3.3.tar.gz",
"platform": null,
"description": "# \ud83e\udd16 PyCallingAgent\n**\ud83d\ude80 AI that executes, not just generates!**\n\n[](https://opensource.org/licenses/MIT)\n[](https://www.python.org/downloads/)\n[](https://pypi.org/project/py-calling-agent)\n\nPyCallingAgent 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.\n\n> *\"When your AI needs to run code, not just write it\"*\n\n## Why PyCallingAgent?\n\n**Traditional function calling is broken.** JSON schemas are rigid, error-prone, and limit what your AI can do. PyCallingAgent unleashes your LLM's natural coding abilities:\n\n- \ud83e\udde0 **Native Code Generation** - LLMs excel at writing code, not parsing JSON\n- \u26a1 **Fewer Iterations** - Execute complex multi-step workflows in a single turn\n- \ud83d\udd04 **Persistent State** - Maintain variables and objects across conversations \n- \ud83c\udfaf **Maximum Flexibility** - Handle dynamic workflows that JSON schemas can't express\n- \ud83d\udee1\ufe0f **Secure by Design** - AST validation prevents dangerous code execution\n- \ud83d\udce1 **Real-time Streaming** - Watch your AI think and execute in real-time\n- \ud83c\udf10 **Universal LLM Support** - Works with OpenAI, Anthropic, Google, and 100+ providers\n\n## Quick Start\n\n```bash\npip install 'py-calling-agent[all]'\n```\n\nChoose your installation:\n\n```bash\n# OpenAI support\npip install 'py-calling-agent[openai]'\n\n# 100+ LLM providers via LiteLLM \npip install 'py-calling-agent[litellm]'\n```\n\n### Simple Function Calling\n\n```python\nimport asyncio\nfrom py_calling_agent import PyCallingAgent\nfrom py_calling_agent.models import OpenAIServerModel\nfrom py_calling_agent.python_runtime import PythonRuntime, Function, Variable\n\nasync def main():\n # Initialize LLM model\n model = OpenAIServerModel(\n model_id=\"your-model\",\n api_key=\"your-api-key\",\n base_url=\"your-base-url\"\n )\n\n # Define tool functions\n def add_task(task_name: str) -> str:\n \"\"\"Add a new task to the task list\"\"\"\n tasks.append({\"name\": task_name, \"done\": False})\n return f\"Added task: {task_name}\"\n\n def complete_task(task_name: str) -> str:\n \"\"\"Mark a task as completed\"\"\"\n for task in tasks:\n if task_name.lower() in task[\"name\"].lower():\n task[\"done\"] = True\n return f\"Completed: {task['name']}\"\n return f\"Task '{task_name}' not found\"\n\n def send_reminder(message: str) -> str:\n \"\"\"Send a reminder notification\"\"\"\n return f\"Reminder: {message}\"\n\n # Initialize data\n tasks = []\n\n # Setup Runtime\n runtime = PythonRuntime(\n variables=[\n Variable(\"tasks\", tasks, \"List of user's tasks. Example: [{'name': 'walk the dog', 'done': False}]\")\n ],\n functions=[\n Function(add_task),\n Function(complete_task), \n Function(send_reminder)\n ]\n )\n\n agent = PyCallingAgent(model, runtime=runtime)\n\n await agent.run(\"Add buy groceries and call mom to my tasks\")\n print(f\"Current tasks: {runtime.get_variable_value('tasks')}\")\n\n await agent.run(\"Mark groceries done and remind me about mom\")\n print(f\"Final state: {runtime.get_variable_value('tasks')}\")\n\n response = await agent.run(\"What's my progress?\")\n print(response.content)\n\nif __name__ == \"__main__\":\n asyncio.run(main())\n```\n\n### Advanced: Stateful Object Interactions\n\n```python\nimport asyncio\nfrom py_calling_agent import PyCallingAgent\nfrom py_calling_agent.models import LiteLLMModel\nfrom py_calling_agent.python_runtime import PythonRuntime, Function, Variable\n\nasync def main():\n # Initialize LLM model\n model = LiteLLMModel(\n model_id=\"your-model\",\n api_key=\"your-api-key\",\n base_url=\"your-base-url\"\n )\n\n # Define a class with methods\n class DataProcessor:\n \"\"\"A utility class for processing and filtering data collections.\n \n This class provides methods for basic data processing operations such as\n sorting, removing duplicates, and filtering based on thresholds.\n \n Example:\n >>> processor = DataProcessor()\n >>> processor.process_list([3, 1, 2, 1, 3])\n [1, 2, 3]\n >>> processor.filter_numbers([1, 5, 3, 8, 2], 4)\n [5, 8]\n \"\"\"\n def process_list(self, data: list) -> list:\n \"\"\"Sort a list and remove duplicates\"\"\"\n return sorted(set(data))\n \n def filter_numbers(self, data: list, threshold: int) -> list:\n \"\"\"Filter numbers greater than threshold\"\"\"\n return [x for x in data if x > threshold]\n\n # Prepare context\n processor = DataProcessor()\n numbers = [3, 1, 4, 1, 5, 9, 2, 6, 5]\n\n # Create runtime with variables and functions\n runtime = PythonRuntime(\n variables=[\n Variable(\n name=\"processor\",\n value=processor,\n description=\"Data processing tool with various methods\"\n ),\n Variable(\n name=\"numbers\",\n value=numbers,\n description=\"Input list of numbers\"\n ),\n Variable(\n name=\"processed_data\",\n description=\"Store processed data in this variable\"\n ),\n Variable(\n name=\"filtered_data\",\n description=\"Store filtered data in this variable\"\n )\n ]\n )\n\n # Create agent\n agent = PyCallingAgent(model, runtime=runtime)\n\n # Process data\n await agent.run(\"Use processor to sort and deduplicate numbers\")\n processed_data = agent.runtime.get_variable_value('processed_data')\n print(\"Processed data:\", processed_data)\n\n # Filter data\n await agent.run(\"Filter numbers greater than 4\")\n filtered_data = agent.runtime.get_variable_value('filtered_data')\n print(\"Filtered data:\", filtered_data)\n\nif __name__ == \"__main__\":\n asyncio.run(main())\n```\n\n### Real-time Streaming\n\nWatch your AI think and execute code in real-time:\n\n```python\nasync for event in agent.stream_events(\"Analyze this data and create a summary\"):\n if event.type.value == 'CODE':\n print(f\"\ud83d\udd27 Executing: {event.content}\")\n elif event.type.value == 'EXECUTION_RESULT':\n print(f\"\u2705 Result: {event.content}\")\n elif event.type.value == 'TEXT':\n print(event.content, end=\"\", flush=True)\n```\n\n## Key Features\n\n- **\ud83e\udd16 Code-Based Function Calling**: Leverages LLM's natural coding abilities instead of rigid JSON schemas\n- **\ud83d\udd27 Secure Runtime Environment**: \n - Inject Python objects, variables, and functions as tools\n - AST-based security validation prevents dangerous code execution\n - Access execution results and maintain state across interactions\n- **\ud83d\udcac Multi-Turn Conversations**: Persistent context and runtime state across multiple interactions\n- **\u26a1 Streaming & Async**: Real-time event streaming and full async/await support for optimal performance\n- **\ud83d\udee1\ufe0f Execution Control**: Configurable step limits and error handling to prevent infinite loops\n- **\ud83c\udfaf Unmatched Flexibility**: JSON schemas break with dynamic workflows. Python code adapts to any situation - conditional logic, loops, and complex data transformations.\n- **\ud83c\udf10 Flexible LLM Support**: Works with any LLM provider via OpenAI-compatible APIs or LiteLLM\n\n## Real-World Examples\n\nFor more examples, check out the [examples](examples) directory:\n\n- [Basic Usage](examples/basic_usage.py): Simple function calling and object processing\n- [Runtime State](examples/runtime_state.py): Managing runtime state across interactions\n- [Object Methods](examples/object_methods.py): Using class methods and complex objects\n- [Multi-Turn](examples/multi_turn.py): Complex analysis conversations with state persistence\n- [Stream](examples/stream.py): Streaming responses and execution events\n\n## LLM Provider Support\n\nPyCallingAgent supports multiple LLM providers:\n\n### OpenAI-Compatible Models\n```python\nfrom py_calling_agent.models import OpenAIServerModel\n\nmodel = OpenAIServerModel(\n model_id=\"gpt-4\",\n api_key=\"your-api-key\",\n base_url=\"https://api.openai.com/v1\" # or your custom endpoint\n)\n```\n\n### LiteLLM Models (Recommended)\nLiteLLM provides unified access to hundreds of LLM providers:\n\n```python\nfrom py_calling_agent.models import LiteLLMModel\n\n# OpenAI\nmodel = LiteLLMModel(\n model_id=\"gpt-4\",\n api_key=\"your-api-key\"\uff0c\n custom_llm_provider='openai'\n)\n\n# Anthropic Claude\nmodel = LiteLLMModel(\n model_id=\"claude-3-sonnet-20240229\",\n api_key=\"your-api-key\",\n custom_llm_provider='anthropic' \n)\n\n# Google Gemini\nmodel = LiteLLMModel(\n model_id=\"gemini/gemini-pro\",\n api_key=\"your-api-key\"\n)\n```\n\n\n## Contributing\n\nContributions are welcome! Please feel free to submit a PR.\nFor more details, see [CONTRIBUTING.md](CONTRIBUTING.md).\n\n## License\n\nMIT License - see [LICENSE](LICENSE) for details.\n",
"bugtrack_url": null,
"license": null,
"summary": "A Python agent framework that enables function-calling through LLM code generation",
"version": "0.3.3",
"project_urls": {
"Homepage": "https://github.com/acodercat/py-calling-agent",
"Repository": "https://github.com/acodercat/py-calling-agent"
},
"split_keywords": [
"agent",
" function-calling",
" llm"
],
"urls": [
{
"comment_text": null,
"digests": {
"blake2b_256": "1ebd907a70ebd32ec568efb8428eed5bd1c9676e33a312888d0bb2e64fc674b5",
"md5": "5ec325692c9f91925ad377bbb0f88577",
"sha256": "6ae5b10a21503d0f0fe31e8d957a7e3b8421733f0fa03412404a29607f41f00c"
},
"downloads": -1,
"filename": "py_calling_agent-0.3.3-py3-none-any.whl",
"has_sig": false,
"md5_digest": "5ec325692c9f91925ad377bbb0f88577",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": ">=3.11",
"size": 19437,
"upload_time": "2025-07-29T08:23:01",
"upload_time_iso_8601": "2025-07-29T08:23:01.660598Z",
"url": "https://files.pythonhosted.org/packages/1e/bd/907a70ebd32ec568efb8428eed5bd1c9676e33a312888d0bb2e64fc674b5/py_calling_agent-0.3.3-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": null,
"digests": {
"blake2b_256": "cef95059dd9db008a40c9221799e8b13f5e254e68b21828bdafdd448e8ecaa7f",
"md5": "9bd9ec31977086fbd6b39a0b9f242baf",
"sha256": "7f98e734a953159709a90a7b0928ccfaed5093b94f02aa250a6742fea9ddfaec"
},
"downloads": -1,
"filename": "py_calling_agent-0.3.3.tar.gz",
"has_sig": false,
"md5_digest": "9bd9ec31977086fbd6b39a0b9f242baf",
"packagetype": "sdist",
"python_version": "source",
"requires_python": ">=3.11",
"size": 134349,
"upload_time": "2025-07-29T08:23:03",
"upload_time_iso_8601": "2025-07-29T08:23:03.281699Z",
"url": "https://files.pythonhosted.org/packages/ce/f9/5059dd9db008a40c9221799e8b13f5e254e68b21828bdafdd448e8ecaa7f/py_calling_agent-0.3.3.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2025-07-29 08:23:03",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "acodercat",
"github_project": "py-calling-agent",
"travis_ci": false,
"coveralls": false,
"github_actions": false,
"lcname": "py-calling-agent"
}