django-agent-runtime 0.3.5__tar.gz → 0.3.11__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.
- {django_agent_runtime-0.3.5/django_agent_runtime.egg-info → django_agent_runtime-0.3.11}/PKG-INFO +645 -8
- {django_agent_runtime-0.3.5 → django_agent_runtime-0.3.11}/README.md +639 -6
- {django_agent_runtime-0.3.5 → django_agent_runtime-0.3.11}/api/views.py +2 -2
- {django_agent_runtime-0.3.5 → django_agent_runtime-0.3.11}/conf.py +1 -1
- {django_agent_runtime-0.3.5 → django_agent_runtime-0.3.11/django_agent_runtime.egg-info}/PKG-INFO +645 -8
- {django_agent_runtime-0.3.5 → django_agent_runtime-0.3.11}/django_agent_runtime.egg-info/SOURCES.txt +2 -0
- {django_agent_runtime-0.3.5 → django_agent_runtime-0.3.11}/django_agent_runtime.egg-info/requires.txt +7 -1
- {django_agent_runtime-0.3.5 → django_agent_runtime-0.3.11}/management/commands/runagent.py +66 -5
- {django_agent_runtime-0.3.5 → django_agent_runtime-0.3.11}/pyproject.toml +8 -2
- {django_agent_runtime-0.3.5 → django_agent_runtime-0.3.11}/runtime/__init__.py +7 -0
- {django_agent_runtime-0.3.5 → django_agent_runtime-0.3.11}/runtime/registry.py +70 -7
- django_agent_runtime-0.3.11/runtime/tools.py +179 -0
- {django_agent_runtime-0.3.5 → django_agent_runtime-0.3.11}/LICENSE +0 -0
- {django_agent_runtime-0.3.5 → django_agent_runtime-0.3.11}/MANIFEST.in +0 -0
- {django_agent_runtime-0.3.5 → django_agent_runtime-0.3.11}/__init__.py +0 -0
- {django_agent_runtime-0.3.5 → django_agent_runtime-0.3.11}/admin.py +0 -0
- {django_agent_runtime-0.3.5 → django_agent_runtime-0.3.11}/api/__init__.py +0 -0
- {django_agent_runtime-0.3.5 → django_agent_runtime-0.3.11}/api/permissions.py +0 -0
- {django_agent_runtime-0.3.5 → django_agent_runtime-0.3.11}/api/serializers.py +0 -0
- {django_agent_runtime-0.3.5 → django_agent_runtime-0.3.11}/apps.py +0 -0
- {django_agent_runtime-0.3.5 → django_agent_runtime-0.3.11}/django_agent_runtime.egg-info/dependency_links.txt +0 -0
- {django_agent_runtime-0.3.5 → django_agent_runtime-0.3.11}/django_agent_runtime.egg-info/top_level.txt +0 -0
- {django_agent_runtime-0.3.5 → django_agent_runtime-0.3.11}/examples/__init__.py +0 -0
- {django_agent_runtime-0.3.5 → django_agent_runtime-0.3.11}/examples/langgraph_adapter.py +0 -0
- {django_agent_runtime-0.3.5 → django_agent_runtime-0.3.11}/examples/langgraph_tools.py +0 -0
- {django_agent_runtime-0.3.5 → django_agent_runtime-0.3.11}/examples/simple_chat.py +0 -0
- {django_agent_runtime-0.3.5 → django_agent_runtime-0.3.11}/examples/tool_agent.py +0 -0
- {django_agent_runtime-0.3.5 → django_agent_runtime-0.3.11}/management/__init__.py +0 -0
- {django_agent_runtime-0.3.5 → django_agent_runtime-0.3.11}/management/commands/__init__.py +0 -0
- {django_agent_runtime-0.3.5 → django_agent_runtime-0.3.11}/migrations/0001_initial.py +0 -0
- {django_agent_runtime-0.3.5 → django_agent_runtime-0.3.11}/migrations/0002_persistence_models.py +0 -0
- {django_agent_runtime-0.3.5 → django_agent_runtime-0.3.11}/migrations/0003_persistenceconversation_active_branch_id_and_more.py +0 -0
- {django_agent_runtime-0.3.5 → django_agent_runtime-0.3.11}/migrations/0004_add_anonymous_session_id.py +0 -0
- {django_agent_runtime-0.3.5 → django_agent_runtime-0.3.11}/migrations/__init__.py +0 -0
- {django_agent_runtime-0.3.5 → django_agent_runtime-0.3.11}/models/__init__.py +0 -0
- {django_agent_runtime-0.3.5 → django_agent_runtime-0.3.11}/models/base.py +0 -0
- {django_agent_runtime-0.3.5 → django_agent_runtime-0.3.11}/models/concrete.py +0 -0
- {django_agent_runtime-0.3.5 → django_agent_runtime-0.3.11}/persistence/__init__.py +0 -0
- {django_agent_runtime-0.3.5 → django_agent_runtime-0.3.11}/persistence/helpers.py +0 -0
- {django_agent_runtime-0.3.5 → django_agent_runtime-0.3.11}/persistence/models.py +0 -0
- {django_agent_runtime-0.3.5 → django_agent_runtime-0.3.11}/persistence/stores.py +0 -0
- {django_agent_runtime-0.3.5 → django_agent_runtime-0.3.11}/runtime/events/__init__.py +0 -0
- {django_agent_runtime-0.3.5 → django_agent_runtime-0.3.11}/runtime/events/base.py +0 -0
- {django_agent_runtime-0.3.5 → django_agent_runtime-0.3.11}/runtime/events/db.py +0 -0
- {django_agent_runtime-0.3.5 → django_agent_runtime-0.3.11}/runtime/events/redis.py +0 -0
- {django_agent_runtime-0.3.5 → django_agent_runtime-0.3.11}/runtime/events/sync.py +0 -0
- {django_agent_runtime-0.3.5 → django_agent_runtime-0.3.11}/runtime/interfaces.py +0 -0
- {django_agent_runtime-0.3.5 → django_agent_runtime-0.3.11}/runtime/llm/__init__.py +0 -0
- {django_agent_runtime-0.3.5 → django_agent_runtime-0.3.11}/runtime/llm/anthropic.py +0 -0
- {django_agent_runtime-0.3.5 → django_agent_runtime-0.3.11}/runtime/llm/litellm_adapter.py +0 -0
- {django_agent_runtime-0.3.5 → django_agent_runtime-0.3.11}/runtime/llm/openai.py +0 -0
- {django_agent_runtime-0.3.5 → django_agent_runtime-0.3.11}/runtime/queue/__init__.py +0 -0
- {django_agent_runtime-0.3.5 → django_agent_runtime-0.3.11}/runtime/queue/base.py +0 -0
- {django_agent_runtime-0.3.5 → django_agent_runtime-0.3.11}/runtime/queue/postgres.py +0 -0
- {django_agent_runtime-0.3.5 → django_agent_runtime-0.3.11}/runtime/queue/redis_streams.py +0 -0
- {django_agent_runtime-0.3.5 → django_agent_runtime-0.3.11}/runtime/queue/sync.py +0 -0
- {django_agent_runtime-0.3.5 → django_agent_runtime-0.3.11}/runtime/runner.py +0 -0
- {django_agent_runtime-0.3.5 → django_agent_runtime-0.3.11}/runtime/tracing/__init__.py +0 -0
- {django_agent_runtime-0.3.5 → django_agent_runtime-0.3.11}/runtime/tracing/langfuse.py +0 -0
- {django_agent_runtime-0.3.5 → django_agent_runtime-0.3.11}/runtime/tracing/noop.py +0 -0
- {django_agent_runtime-0.3.5 → django_agent_runtime-0.3.11}/setup.cfg +0 -0
- {django_agent_runtime-0.3.5 → django_agent_runtime-0.3.11}/tests/test_api.py +0 -0
- {django_agent_runtime-0.3.5 → django_agent_runtime-0.3.11}/tests/test_events.py +0 -0
- {django_agent_runtime-0.3.5 → django_agent_runtime-0.3.11}/tests/test_interfaces.py +0 -0
- {django_agent_runtime-0.3.5 → django_agent_runtime-0.3.11}/tests/test_llm.py +0 -0
- {django_agent_runtime-0.3.5 → django_agent_runtime-0.3.11}/tests/test_models.py +0 -0
- {django_agent_runtime-0.3.5 → django_agent_runtime-0.3.11}/tests/test_persistence.py +0 -0
- {django_agent_runtime-0.3.5 → django_agent_runtime-0.3.11}/tests/test_queue.py +0 -0
- {django_agent_runtime-0.3.5 → django_agent_runtime-0.3.11}/tests/test_registry.py +0 -0
- {django_agent_runtime-0.3.5 → django_agent_runtime-0.3.11}/tests/test_runner.py +0 -0
- {django_agent_runtime-0.3.5 → django_agent_runtime-0.3.11}/urls.py +0 -0
{django_agent_runtime-0.3.5/django_agent_runtime.egg-info → django_agent_runtime-0.3.11}/PKG-INFO
RENAMED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: django-agent-runtime
|
|
3
|
-
Version: 0.3.
|
|
3
|
+
Version: 0.3.11
|
|
4
4
|
Summary: Production-grade AI agent runtime for Django - framework and model agnostic
|
|
5
5
|
Author: Chris Barry
|
|
6
6
|
License-Expression: MIT
|
|
@@ -37,8 +37,12 @@ Provides-Extra: litellm
|
|
|
37
37
|
Requires-Dist: litellm>=1.0.0; extra == "litellm"
|
|
38
38
|
Provides-Extra: langfuse
|
|
39
39
|
Requires-Dist: langfuse>=2.0.0; extra == "langfuse"
|
|
40
|
+
Provides-Extra: framework
|
|
41
|
+
Requires-Dist: agent-runtime-framework>=0.1.0; extra == "framework"
|
|
42
|
+
Provides-Extra: recommended
|
|
43
|
+
Requires-Dist: django-agent-runtime[framework,openai,redis]; extra == "recommended"
|
|
40
44
|
Provides-Extra: all
|
|
41
|
-
Requires-Dist: django-agent-runtime[anthropic,langfuse,litellm,openai,redis]; extra == "all"
|
|
45
|
+
Requires-Dist: django-agent-runtime[anthropic,framework,langfuse,litellm,openai,redis]; extra == "all"
|
|
42
46
|
Provides-Extra: dev
|
|
43
47
|
Requires-Dist: pytest>=7.0; extra == "dev"
|
|
44
48
|
Requires-Dist: pytest-django>=4.5; extra == "dev"
|
|
@@ -62,6 +66,13 @@ A production-ready Django app for AI agent execution. Provides everything you ne
|
|
|
62
66
|
|
|
63
67
|
| Version | Date | Changes |
|
|
64
68
|
|---------|------|---------|
|
|
69
|
+
| **0.3.11** | 2025-01-19 | Add Full Stack Setup Guide for AI agents |
|
|
70
|
+
| **0.3.10** | 2025-01-15 | SSE named events for addEventListener support, flexible registry path format |
|
|
71
|
+
| **0.3.9** | 2025-01-14 | Add `[recommended]` and `[framework]` install extras |
|
|
72
|
+
| **0.3.8** | 2025-01-14 | Add agent-frontend docs, agent framework options (OpenAI, Anthropic, LangGraph) |
|
|
73
|
+
| **0.3.7** | 2025-01-13 | Fix auto-reload signal handler in threaded mode |
|
|
74
|
+
| **0.3.6** | 2025-01-13 | Auto-reload for `runagent` in DEBUG mode (like Django's runserver) |
|
|
75
|
+
| **0.3.5** | 2025-01-13 | Added Recent Updates changelog to README |
|
|
65
76
|
| **0.3.4** | 2025-01-13 | Documentation updates for message history |
|
|
66
77
|
| **0.3.3** | 2025-01-13 | Added `conversation.get_message_history()` for retrieving full message sequences |
|
|
67
78
|
| **0.3.2** | 2025-01-13 | Event visibility system - filter events by `internal`/`debug`/`user` levels |
|
|
@@ -84,6 +95,13 @@ A production-ready Django app for AI agent execution. Provides everything you ne
|
|
|
84
95
|
```bash
|
|
85
96
|
pip install django-agent-runtime
|
|
86
97
|
|
|
98
|
+
# Recommended: Redis + OpenAI + agent-runtime-framework
|
|
99
|
+
pip install django-agent-runtime[recommended]
|
|
100
|
+
|
|
101
|
+
# Pick specific extras (comma-separated)
|
|
102
|
+
pip install django-agent-runtime[openai,framework]
|
|
103
|
+
pip install django-agent-runtime[redis,anthropic]
|
|
104
|
+
|
|
87
105
|
# With LLM providers
|
|
88
106
|
pip install django-agent-runtime[openai]
|
|
89
107
|
pip install django-agent-runtime[anthropic]
|
|
@@ -91,6 +109,9 @@ pip install django-agent-runtime[anthropic]
|
|
|
91
109
|
# With Redis support (recommended for production)
|
|
92
110
|
pip install django-agent-runtime[redis]
|
|
93
111
|
|
|
112
|
+
# With agent-runtime-framework for journey-based agents
|
|
113
|
+
pip install django-agent-runtime[framework]
|
|
114
|
+
|
|
94
115
|
# Everything
|
|
95
116
|
pip install django-agent-runtime[all]
|
|
96
117
|
```
|
|
@@ -645,9 +666,55 @@ python manage.py runagent \
|
|
|
645
666
|
--queue-poll-interval 1.0
|
|
646
667
|
```
|
|
647
668
|
|
|
669
|
+
#### Auto-Reload (Development)
|
|
670
|
+
|
|
671
|
+
In `DEBUG=True` mode, `runagent` automatically reloads when Python files change—just like Django's `runserver`:
|
|
672
|
+
|
|
673
|
+
```bash
|
|
674
|
+
# Auto-reload enabled by default in DEBUG mode
|
|
675
|
+
python manage.py runagent
|
|
676
|
+
|
|
677
|
+
# Disable auto-reload
|
|
678
|
+
python manage.py runagent --noreload
|
|
679
|
+
```
|
|
680
|
+
|
|
681
|
+
**Note:** Auto-reload only works in single-process mode. Multi-process mode (`--processes > 1`) automatically disables auto-reload.
|
|
682
|
+
|
|
648
683
|
## Frontend Integration
|
|
649
684
|
|
|
650
|
-
###
|
|
685
|
+
### agent-frontend (Recommended)
|
|
686
|
+
|
|
687
|
+
The easiest way to add a chat UI is with [agent-frontend](https://github.com/makemore/agent-frontend) - a zero-dependency, embeddable chat widget:
|
|
688
|
+
|
|
689
|
+
```html
|
|
690
|
+
<!-- Include the widget -->
|
|
691
|
+
<link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/makemore/agent-frontend@main/dist/chat-widget.css">
|
|
692
|
+
<script src="https://cdn.jsdelivr.net/gh/makemore/agent-frontend@main/dist/chat-widget.js"></script>
|
|
693
|
+
|
|
694
|
+
<!-- Initialize -->
|
|
695
|
+
<script>
|
|
696
|
+
ChatWidget.init({
|
|
697
|
+
backendUrl: 'https://your-api.com',
|
|
698
|
+
agentKey: 'chat-agent',
|
|
699
|
+
title: 'Support Chat',
|
|
700
|
+
primaryColor: '#0066cc',
|
|
701
|
+
});
|
|
702
|
+
</script>
|
|
703
|
+
```
|
|
704
|
+
|
|
705
|
+
Features:
|
|
706
|
+
- **Zero dependencies** - Pure vanilla JavaScript
|
|
707
|
+
- **SSE streaming** - Real-time token-by-token responses
|
|
708
|
+
- **CSS isolated** - Won't conflict with your existing styles
|
|
709
|
+
- **Dark mode** - Automatic based on system preferences
|
|
710
|
+
- **Session management** - Anonymous sessions out of the box
|
|
711
|
+
- **Demo flows** - Built-in auto-run mode for showcasing agent journeys
|
|
712
|
+
|
|
713
|
+
See the [agent-frontend documentation](https://github.com/makemore/agent-frontend) for full configuration options.
|
|
714
|
+
|
|
715
|
+
### Custom JavaScript SSE Client
|
|
716
|
+
|
|
717
|
+
If you're building your own UI:
|
|
651
718
|
|
|
652
719
|
```javascript
|
|
653
720
|
const eventSource = new EventSource('/api/agents/runs/550e8400.../events/');
|
|
@@ -675,29 +742,599 @@ eventSource.addEventListener('run.failed', (event) => {
|
|
|
675
742
|
function useAgentRun(runId: string) {
|
|
676
743
|
const [events, setEvents] = useState<AgentEvent[]>([]);
|
|
677
744
|
const [status, setStatus] = useState<'running' | 'complete' | 'error'>('running');
|
|
678
|
-
|
|
745
|
+
|
|
679
746
|
useEffect(() => {
|
|
680
747
|
const es = new EventSource(`/api/agents/runs/${runId}/events/`);
|
|
681
|
-
|
|
748
|
+
|
|
682
749
|
es.onmessage = (event) => {
|
|
683
750
|
const data = JSON.parse(event.data);
|
|
684
751
|
setEvents(prev => [...prev, data]);
|
|
685
|
-
|
|
752
|
+
|
|
686
753
|
if (data.type === 'run.succeeded') setStatus('complete');
|
|
687
754
|
if (data.type === 'run.failed') setStatus('error');
|
|
688
755
|
};
|
|
689
|
-
|
|
756
|
+
|
|
690
757
|
return () => es.close();
|
|
691
758
|
}, [runId]);
|
|
692
|
-
|
|
759
|
+
|
|
693
760
|
return { events, status };
|
|
694
761
|
}
|
|
695
762
|
```
|
|
696
763
|
|
|
764
|
+
## Agent Framework Options
|
|
765
|
+
|
|
766
|
+
django-agent-runtime is framework-agnostic. You can build agents using:
|
|
767
|
+
|
|
768
|
+
### Option 1: Direct AgentRuntime (Simple)
|
|
769
|
+
|
|
770
|
+
Best for simple agents or when you want full control:
|
|
771
|
+
|
|
772
|
+
```python
|
|
773
|
+
from django_agent_runtime.runtime.interfaces import AgentRuntime, RunContext, RunResult
|
|
774
|
+
|
|
775
|
+
class MyAgent(AgentRuntime):
|
|
776
|
+
@property
|
|
777
|
+
def key(self) -> str:
|
|
778
|
+
return "my-agent"
|
|
779
|
+
|
|
780
|
+
async def run(self, ctx: RunContext) -> RunResult:
|
|
781
|
+
# Your agent logic here
|
|
782
|
+
...
|
|
783
|
+
```
|
|
784
|
+
|
|
785
|
+
### Option 2: agent_runtime_framework (Journey-Based)
|
|
786
|
+
|
|
787
|
+
Best for multi-step conversational flows with state management:
|
|
788
|
+
|
|
789
|
+
```bash
|
|
790
|
+
pip install agent_runtime_framework
|
|
791
|
+
```
|
|
792
|
+
|
|
793
|
+
```python
|
|
794
|
+
from agent_runtime_framework.adapters import DjangoRuntimeAdapter
|
|
795
|
+
from agent_runtime_framework import BaseJourneyState, BaseJourneyTools, ToolSchema
|
|
796
|
+
from enum import Enum
|
|
797
|
+
|
|
798
|
+
class QuoteStep(str, Enum):
|
|
799
|
+
WELCOME = "welcome"
|
|
800
|
+
COLLECT_INFO = "collect_info"
|
|
801
|
+
GENERATE_QUOTE = "generate_quote"
|
|
802
|
+
COMPLETE = "complete"
|
|
803
|
+
|
|
804
|
+
class QuoteState(BaseJourneyState[QuoteStep]):
|
|
805
|
+
step: QuoteStep = QuoteStep.WELCOME
|
|
806
|
+
customer_name: str = ""
|
|
807
|
+
coverage_type: str = ""
|
|
808
|
+
# ... state fields
|
|
809
|
+
|
|
810
|
+
class QuoteTools(BaseJourneyTools[QuoteState]):
|
|
811
|
+
async def save_customer_info(self, name: str, coverage: str) -> str:
|
|
812
|
+
self.state.customer_name = name
|
|
813
|
+
self.state.coverage_type = coverage
|
|
814
|
+
self.state.step = QuoteStep.GENERATE_QUOTE
|
|
815
|
+
await self._notify_state_change()
|
|
816
|
+
return f"Got it, {name}! Generating your {coverage} quote..."
|
|
817
|
+
|
|
818
|
+
class QuoteAgent(DjangoRuntimeAdapter[QuoteState, QuoteTools, QuoteStep]):
|
|
819
|
+
@property
|
|
820
|
+
def key(self) -> str:
|
|
821
|
+
return "quote-agent"
|
|
822
|
+
|
|
823
|
+
def get_initial_state(self) -> QuoteState:
|
|
824
|
+
return QuoteState()
|
|
825
|
+
|
|
826
|
+
def get_system_prompt(self, state: QuoteState) -> str:
|
|
827
|
+
prompts = {
|
|
828
|
+
QuoteStep.WELCOME: "Welcome the user and ask what coverage they need.",
|
|
829
|
+
QuoteStep.COLLECT_INFO: "Collect customer name and coverage type.",
|
|
830
|
+
# ...
|
|
831
|
+
}
|
|
832
|
+
return prompts[state.step]
|
|
833
|
+
|
|
834
|
+
def get_tool_schemas(self, state: QuoteState) -> list[ToolSchema]:
|
|
835
|
+
# Return different tools based on current step
|
|
836
|
+
...
|
|
837
|
+
|
|
838
|
+
def create_tools(self, state, ctx, backend_client) -> QuoteTools:
|
|
839
|
+
return QuoteTools(state=state)
|
|
840
|
+
|
|
841
|
+
async def execute_tool(self, tools, name: str, arguments: dict) -> str:
|
|
842
|
+
return await getattr(tools, name)(**arguments)
|
|
843
|
+
|
|
844
|
+
# Register with django-agent-runtime
|
|
845
|
+
from django_agent_runtime.runtime.registry import register_runtime
|
|
846
|
+
register_runtime(QuoteAgent())
|
|
847
|
+
```
|
|
848
|
+
|
|
849
|
+
The adapter handles:
|
|
850
|
+
- Converting Django's `RunContext` to framework's `AgentContext`
|
|
851
|
+
- State persistence via Django's checkpoint system
|
|
852
|
+
- Event emission through Django's event bus
|
|
853
|
+
- Returning results in Django's `RunResult` format
|
|
854
|
+
|
|
855
|
+
See [agent_runtime_framework](https://github.com/makemore/agent-runtime-framework) for full documentation.
|
|
856
|
+
|
|
857
|
+
### Option 3: OpenAI Agents SDK
|
|
858
|
+
|
|
859
|
+
Use OpenAI's official Agents SDK with django-agent-runtime:
|
|
860
|
+
|
|
861
|
+
```python
|
|
862
|
+
from django_agent_runtime.runtime.interfaces import AgentRuntime, RunContext, RunResult, EventType
|
|
863
|
+
from agents import Agent, Runner
|
|
864
|
+
|
|
865
|
+
class OpenAIAgentRuntime(AgentRuntime):
|
|
866
|
+
@property
|
|
867
|
+
def key(self) -> str:
|
|
868
|
+
return "openai-agent"
|
|
869
|
+
|
|
870
|
+
def __init__(self):
|
|
871
|
+
self.agent = Agent(
|
|
872
|
+
name="Assistant",
|
|
873
|
+
instructions="You are a helpful assistant.",
|
|
874
|
+
model="gpt-4o",
|
|
875
|
+
)
|
|
876
|
+
|
|
877
|
+
async def run(self, ctx: RunContext) -> RunResult:
|
|
878
|
+
# Convert messages to OpenAI format
|
|
879
|
+
user_message = ctx.input_messages[-1]["content"]
|
|
880
|
+
|
|
881
|
+
# Run the OpenAI agent
|
|
882
|
+
result = await Runner.run(self.agent, user_message)
|
|
883
|
+
|
|
884
|
+
# Emit the response
|
|
885
|
+
await ctx.emit(EventType.ASSISTANT_MESSAGE, {
|
|
886
|
+
"content": result.final_output,
|
|
887
|
+
})
|
|
888
|
+
|
|
889
|
+
return RunResult(
|
|
890
|
+
final_output={"response": result.final_output},
|
|
891
|
+
final_messages=[{"role": "assistant", "content": result.final_output}],
|
|
892
|
+
)
|
|
893
|
+
```
|
|
894
|
+
|
|
895
|
+
### Option 4: Anthropic Claude with Tool Use
|
|
896
|
+
|
|
897
|
+
Use Anthropic's Claude directly:
|
|
898
|
+
|
|
899
|
+
```python
|
|
900
|
+
from django_agent_runtime.runtime.interfaces import AgentRuntime, RunContext, RunResult, EventType
|
|
901
|
+
import anthropic
|
|
902
|
+
|
|
903
|
+
class ClaudeAgent(AgentRuntime):
|
|
904
|
+
@property
|
|
905
|
+
def key(self) -> str:
|
|
906
|
+
return "claude-agent"
|
|
907
|
+
|
|
908
|
+
def __init__(self):
|
|
909
|
+
self.client = anthropic.AsyncAnthropic()
|
|
910
|
+
|
|
911
|
+
async def run(self, ctx: RunContext) -> RunResult:
|
|
912
|
+
messages = [
|
|
913
|
+
{"role": m["role"], "content": m["content"]}
|
|
914
|
+
for m in ctx.input_messages
|
|
915
|
+
]
|
|
916
|
+
|
|
917
|
+
response = await self.client.messages.create(
|
|
918
|
+
model="claude-sonnet-4-20250514",
|
|
919
|
+
max_tokens=1024,
|
|
920
|
+
messages=messages,
|
|
921
|
+
)
|
|
922
|
+
|
|
923
|
+
content = response.content[0].text
|
|
924
|
+
|
|
925
|
+
await ctx.emit(EventType.ASSISTANT_MESSAGE, {"content": content})
|
|
926
|
+
|
|
927
|
+
return RunResult(
|
|
928
|
+
final_output={"response": content},
|
|
929
|
+
final_messages=[{"role": "assistant", "content": content}],
|
|
930
|
+
)
|
|
931
|
+
```
|
|
932
|
+
|
|
933
|
+
### Option 5: LangGraph
|
|
934
|
+
|
|
935
|
+
Wrap LangGraph agents:
|
|
936
|
+
|
|
937
|
+
```python
|
|
938
|
+
from django_agent_runtime.runtime.interfaces import AgentRuntime, RunContext, RunResult, EventType
|
|
939
|
+
from langgraph.graph import StateGraph
|
|
940
|
+
|
|
941
|
+
class LangGraphRuntime(AgentRuntime):
|
|
942
|
+
@property
|
|
943
|
+
def key(self) -> str:
|
|
944
|
+
return "langgraph-agent"
|
|
945
|
+
|
|
946
|
+
def __init__(self):
|
|
947
|
+
self.graph = self._build_graph()
|
|
948
|
+
|
|
949
|
+
def _build_graph(self) -> StateGraph:
|
|
950
|
+
# Build your LangGraph here
|
|
951
|
+
...
|
|
952
|
+
|
|
953
|
+
async def run(self, ctx: RunContext) -> RunResult:
|
|
954
|
+
# Run the graph
|
|
955
|
+
result = await self.graph.ainvoke({
|
|
956
|
+
"messages": ctx.input_messages,
|
|
957
|
+
})
|
|
958
|
+
|
|
959
|
+
final_message = result["messages"][-1]
|
|
960
|
+
await ctx.emit(EventType.ASSISTANT_MESSAGE, {
|
|
961
|
+
"content": final_message.content,
|
|
962
|
+
})
|
|
963
|
+
|
|
964
|
+
return RunResult(
|
|
965
|
+
final_output={"response": final_message.content},
|
|
966
|
+
final_messages=result["messages"],
|
|
967
|
+
)
|
|
968
|
+
```
|
|
969
|
+
|
|
697
970
|
## Related Packages
|
|
698
971
|
|
|
972
|
+
- [agent-frontend](https://github.com/makemore/agent-frontend) - Zero-dependency embeddable chat widget for AI agents
|
|
973
|
+
- [agent-runtime-framework](https://github.com/makemore/agent-runtime-framework) - Journey-based conversational agents with state management
|
|
699
974
|
- [agent-runtime-core](https://pypi.org/project/agent-runtime-core/) - The framework-agnostic core library (used internally)
|
|
700
975
|
|
|
976
|
+
---
|
|
977
|
+
|
|
978
|
+
## Full Stack Setup Guide (For AI Agents)
|
|
979
|
+
|
|
980
|
+
This guide explains how to set up the complete agent stack from scratch. It's designed to be followed by another AI agent or developer.
|
|
981
|
+
|
|
982
|
+
### Package Overview
|
|
983
|
+
|
|
984
|
+
| Package | Purpose | Install |
|
|
985
|
+
|---------|---------|---------|
|
|
986
|
+
| **django-agent-runtime** | Django app for agent execution, API, queues, events | `pip install django-agent-runtime[recommended]` |
|
|
987
|
+
| **agent-runtime-core** | Core abstractions (tools, events, config) | Included with django-agent-runtime |
|
|
988
|
+
| **agent-runtime-framework** | Journey-based agents with state management | Included with `[recommended]` or `[framework]` |
|
|
989
|
+
| **@makemore/agent-frontend** | Embeddable chat widget (vanilla JS) | `npm install @makemore/agent-frontend` |
|
|
990
|
+
|
|
991
|
+
### Step 1: Create Django Project
|
|
992
|
+
|
|
993
|
+
```bash
|
|
994
|
+
# Create project directory
|
|
995
|
+
mkdir my_agent_project && cd my_agent_project
|
|
996
|
+
|
|
997
|
+
# Create virtual environment
|
|
998
|
+
python -m venv venv
|
|
999
|
+
source venv/bin/activate # On Windows: venv\Scripts\activate
|
|
1000
|
+
|
|
1001
|
+
# Install Django and agent runtime with recommended extras
|
|
1002
|
+
pip install django django-agent-runtime[recommended]
|
|
1003
|
+
|
|
1004
|
+
# Create Django project
|
|
1005
|
+
django-admin startproject config .
|
|
1006
|
+
python manage.py startapp agents
|
|
1007
|
+
```
|
|
1008
|
+
|
|
1009
|
+
### Step 2: Configure Django Settings
|
|
1010
|
+
|
|
1011
|
+
```python
|
|
1012
|
+
# config/settings.py
|
|
1013
|
+
|
|
1014
|
+
INSTALLED_APPS = [
|
|
1015
|
+
'django.contrib.admin',
|
|
1016
|
+
'django.contrib.auth',
|
|
1017
|
+
'django.contrib.contenttypes',
|
|
1018
|
+
'django.contrib.sessions',
|
|
1019
|
+
'django.contrib.messages',
|
|
1020
|
+
'django.contrib.staticfiles',
|
|
1021
|
+
'rest_framework',
|
|
1022
|
+
'django_agent_runtime',
|
|
1023
|
+
'agents',
|
|
1024
|
+
]
|
|
1025
|
+
|
|
1026
|
+
# Agent Runtime Configuration
|
|
1027
|
+
DJANGO_AGENT_RUNTIME = {
|
|
1028
|
+
'QUEUE_BACKEND': 'postgres',
|
|
1029
|
+
'EVENT_BUS_BACKEND': 'db',
|
|
1030
|
+
'MODEL_PROVIDER': 'openai',
|
|
1031
|
+
'DEFAULT_MODEL': 'gpt-4o',
|
|
1032
|
+
'RUNTIME_REGISTRY': [
|
|
1033
|
+
'agents.runtimes:register_agents',
|
|
1034
|
+
],
|
|
1035
|
+
}
|
|
1036
|
+
|
|
1037
|
+
# Required for API
|
|
1038
|
+
REST_FRAMEWORK = {
|
|
1039
|
+
'DEFAULT_AUTHENTICATION_CLASSES': [
|
|
1040
|
+
'rest_framework.authentication.SessionAuthentication',
|
|
1041
|
+
],
|
|
1042
|
+
'DEFAULT_PERMISSION_CLASSES': [
|
|
1043
|
+
'rest_framework.permissions.AllowAny', # For testing; tighten in production
|
|
1044
|
+
],
|
|
1045
|
+
}
|
|
1046
|
+
|
|
1047
|
+
# CORS for frontend (install django-cors-headers)
|
|
1048
|
+
CORS_ALLOW_ALL_ORIGINS = True # For development only
|
|
1049
|
+
```
|
|
1050
|
+
|
|
1051
|
+
### Step 3: Create a Simple Agent
|
|
1052
|
+
|
|
1053
|
+
```python
|
|
1054
|
+
# agents/runtimes.py
|
|
1055
|
+
from django_agent_runtime.runtime.interfaces import (
|
|
1056
|
+
AgentRuntime, RunContext, RunResult, EventType
|
|
1057
|
+
)
|
|
1058
|
+
from django_agent_runtime.runtime.registry import register_runtime
|
|
1059
|
+
from django_agent_runtime.runtime.llm import get_llm_client
|
|
1060
|
+
|
|
1061
|
+
|
|
1062
|
+
class HelloAgent(AgentRuntime):
|
|
1063
|
+
"""A simple agent that responds to messages."""
|
|
1064
|
+
|
|
1065
|
+
@property
|
|
1066
|
+
def key(self) -> str:
|
|
1067
|
+
return "hello-agent"
|
|
1068
|
+
|
|
1069
|
+
async def run(self, ctx: RunContext) -> RunResult:
|
|
1070
|
+
llm = get_llm_client()
|
|
1071
|
+
|
|
1072
|
+
# Add system message
|
|
1073
|
+
messages = [
|
|
1074
|
+
{"role": "system", "content": "You are a friendly assistant. Keep responses brief."},
|
|
1075
|
+
*ctx.input_messages
|
|
1076
|
+
]
|
|
1077
|
+
|
|
1078
|
+
# Call LLM
|
|
1079
|
+
response = await llm.generate(messages)
|
|
1080
|
+
content = response.message.get("content", "")
|
|
1081
|
+
|
|
1082
|
+
# Emit for real-time streaming
|
|
1083
|
+
await ctx.emit(EventType.ASSISTANT_MESSAGE, {
|
|
1084
|
+
"content": content,
|
|
1085
|
+
"role": "assistant",
|
|
1086
|
+
})
|
|
1087
|
+
|
|
1088
|
+
return RunResult(
|
|
1089
|
+
final_output={"response": content},
|
|
1090
|
+
final_messages=[response.message],
|
|
1091
|
+
)
|
|
1092
|
+
|
|
1093
|
+
|
|
1094
|
+
def register_agents():
|
|
1095
|
+
"""Called by django-agent-runtime on startup."""
|
|
1096
|
+
register_runtime(HelloAgent())
|
|
1097
|
+
```
|
|
1098
|
+
|
|
1099
|
+
### Step 4: Set Up API URLs
|
|
1100
|
+
|
|
1101
|
+
```python
|
|
1102
|
+
# agents/urls.py
|
|
1103
|
+
from django.urls import path, include
|
|
1104
|
+
from rest_framework.routers import DefaultRouter
|
|
1105
|
+
from django_agent_runtime.api.views import (
|
|
1106
|
+
BaseAgentRunViewSet,
|
|
1107
|
+
BaseAgentConversationViewSet,
|
|
1108
|
+
sync_event_stream,
|
|
1109
|
+
)
|
|
1110
|
+
|
|
1111
|
+
router = DefaultRouter()
|
|
1112
|
+
router.register(r'conversations', BaseAgentConversationViewSet, basename='conversation')
|
|
1113
|
+
router.register(r'runs', BaseAgentRunViewSet, basename='run')
|
|
1114
|
+
|
|
1115
|
+
urlpatterns = [
|
|
1116
|
+
path('', include(router.urls)),
|
|
1117
|
+
path('runs/<str:run_id>/events/', sync_event_stream, name='run-events'),
|
|
1118
|
+
]
|
|
1119
|
+
```
|
|
1120
|
+
|
|
1121
|
+
```python
|
|
1122
|
+
# config/urls.py
|
|
1123
|
+
from django.contrib import admin
|
|
1124
|
+
from django.urls import path, include
|
|
1125
|
+
|
|
1126
|
+
urlpatterns = [
|
|
1127
|
+
path('admin/', admin.site.urls),
|
|
1128
|
+
path('api/agents/', include('agents.urls')),
|
|
1129
|
+
]
|
|
1130
|
+
```
|
|
1131
|
+
|
|
1132
|
+
### Step 5: Run Migrations and Start Services
|
|
1133
|
+
|
|
1134
|
+
```bash
|
|
1135
|
+
# Set your OpenAI API key
|
|
1136
|
+
export OPENAI_API_KEY="sk-..."
|
|
1137
|
+
|
|
1138
|
+
# Run migrations
|
|
1139
|
+
python manage.py migrate
|
|
1140
|
+
|
|
1141
|
+
# Start Django server (terminal 1)
|
|
1142
|
+
python manage.py runserver
|
|
1143
|
+
|
|
1144
|
+
# Start agent workers (terminal 2)
|
|
1145
|
+
python manage.py runagent
|
|
1146
|
+
```
|
|
1147
|
+
|
|
1148
|
+
### Step 6: Test the API
|
|
1149
|
+
|
|
1150
|
+
```bash
|
|
1151
|
+
# Create a conversation
|
|
1152
|
+
curl -X POST http://localhost:8000/api/agents/conversations/ \
|
|
1153
|
+
-H "Content-Type: application/json" \
|
|
1154
|
+
-d '{"agent_key": "hello-agent"}'
|
|
1155
|
+
|
|
1156
|
+
# Response: {"id": "conv-uuid-here", ...}
|
|
1157
|
+
|
|
1158
|
+
# Create a run (replace CONV_ID)
|
|
1159
|
+
curl -X POST http://localhost:8000/api/agents/runs/ \
|
|
1160
|
+
-H "Content-Type: application/json" \
|
|
1161
|
+
-d '{
|
|
1162
|
+
"conversation_id": "CONV_ID",
|
|
1163
|
+
"agent_key": "hello-agent",
|
|
1164
|
+
"messages": [{"role": "user", "content": "Hello! What can you do?"}]
|
|
1165
|
+
}'
|
|
1166
|
+
|
|
1167
|
+
# Response: {"id": "run-uuid-here", "status": "queued", ...}
|
|
1168
|
+
|
|
1169
|
+
# Stream events (replace RUN_ID)
|
|
1170
|
+
curl -N http://localhost:8000/api/agents/runs/RUN_ID/events/
|
|
1171
|
+
```
|
|
1172
|
+
|
|
1173
|
+
### Step 7: Add Frontend to Next.js
|
|
1174
|
+
|
|
1175
|
+
In your Next.js project:
|
|
1176
|
+
|
|
1177
|
+
```bash
|
|
1178
|
+
npm install @makemore/agent-frontend
|
|
1179
|
+
```
|
|
1180
|
+
|
|
1181
|
+
Create a chat component:
|
|
1182
|
+
|
|
1183
|
+
```tsx
|
|
1184
|
+
// components/AgentChat.tsx
|
|
1185
|
+
'use client';
|
|
1186
|
+
|
|
1187
|
+
import { useEffect } from 'react';
|
|
1188
|
+
|
|
1189
|
+
export default function AgentChat() {
|
|
1190
|
+
useEffect(() => {
|
|
1191
|
+
// Import and initialize the widget
|
|
1192
|
+
import('@makemore/agent-frontend/dist/chat-widget.js').then(() => {
|
|
1193
|
+
// @ts-ignore
|
|
1194
|
+
window.ChatWidget?.init({
|
|
1195
|
+
backendUrl: process.env.NEXT_PUBLIC_API_URL || 'http://localhost:8000',
|
|
1196
|
+
agentKey: 'hello-agent',
|
|
1197
|
+
title: 'AI Assistant',
|
|
1198
|
+
subtitle: 'Ask me anything!',
|
|
1199
|
+
primaryColor: '#0066cc',
|
|
1200
|
+
position: 'bottom-right',
|
|
1201
|
+
apiEndpoints: {
|
|
1202
|
+
conversations: '/api/agents/conversations/',
|
|
1203
|
+
runs: '/api/agents/runs/',
|
|
1204
|
+
events: '/api/agents/runs/{runId}/events/',
|
|
1205
|
+
},
|
|
1206
|
+
});
|
|
1207
|
+
});
|
|
1208
|
+
|
|
1209
|
+
return () => {
|
|
1210
|
+
// @ts-ignore
|
|
1211
|
+
window.ChatWidget?.destroy?.();
|
|
1212
|
+
};
|
|
1213
|
+
}, []);
|
|
1214
|
+
|
|
1215
|
+
return null; // Widget renders itself
|
|
1216
|
+
}
|
|
1217
|
+
```
|
|
1218
|
+
|
|
1219
|
+
Or use CDN in your layout:
|
|
1220
|
+
|
|
1221
|
+
```tsx
|
|
1222
|
+
// app/layout.tsx
|
|
1223
|
+
export default function RootLayout({ children }) {
|
|
1224
|
+
return (
|
|
1225
|
+
<html>
|
|
1226
|
+
<head>
|
|
1227
|
+
<link
|
|
1228
|
+
rel="stylesheet"
|
|
1229
|
+
href="https://unpkg.com/@makemore/agent-frontend/dist/chat-widget.css"
|
|
1230
|
+
/>
|
|
1231
|
+
</head>
|
|
1232
|
+
<body>
|
|
1233
|
+
{children}
|
|
1234
|
+
<script src="https://unpkg.com/@makemore/agent-frontend/dist/chat-widget.js" />
|
|
1235
|
+
<script
|
|
1236
|
+
dangerouslySetInnerHTML={{
|
|
1237
|
+
__html: `
|
|
1238
|
+
document.addEventListener('DOMContentLoaded', function() {
|
|
1239
|
+
ChatWidget.init({
|
|
1240
|
+
backendUrl: '${process.env.NEXT_PUBLIC_API_URL || 'http://localhost:8000'}',
|
|
1241
|
+
agentKey: 'hello-agent',
|
|
1242
|
+
title: 'AI Assistant',
|
|
1243
|
+
primaryColor: '#0066cc',
|
|
1244
|
+
});
|
|
1245
|
+
});
|
|
1246
|
+
`,
|
|
1247
|
+
}}
|
|
1248
|
+
/>
|
|
1249
|
+
</body>
|
|
1250
|
+
</html>
|
|
1251
|
+
);
|
|
1252
|
+
}
|
|
1253
|
+
```
|
|
1254
|
+
|
|
1255
|
+
### Step 8: Configure CORS (Production)
|
|
1256
|
+
|
|
1257
|
+
```bash
|
|
1258
|
+
pip install django-cors-headers
|
|
1259
|
+
```
|
|
1260
|
+
|
|
1261
|
+
```python
|
|
1262
|
+
# config/settings.py
|
|
1263
|
+
INSTALLED_APPS = [
|
|
1264
|
+
'corsheaders',
|
|
1265
|
+
...
|
|
1266
|
+
]
|
|
1267
|
+
|
|
1268
|
+
MIDDLEWARE = [
|
|
1269
|
+
'corsheaders.middleware.CorsMiddleware',
|
|
1270
|
+
...
|
|
1271
|
+
]
|
|
1272
|
+
|
|
1273
|
+
CORS_ALLOWED_ORIGINS = [
|
|
1274
|
+
'http://localhost:3000', # Next.js dev
|
|
1275
|
+
'https://your-frontend.com',
|
|
1276
|
+
]
|
|
1277
|
+
```
|
|
1278
|
+
|
|
1279
|
+
### Complete File Structure
|
|
1280
|
+
|
|
1281
|
+
```
|
|
1282
|
+
my_agent_project/
|
|
1283
|
+
├── config/
|
|
1284
|
+
│ ├── __init__.py
|
|
1285
|
+
│ ├── settings.py
|
|
1286
|
+
│ ├── urls.py
|
|
1287
|
+
│ └── wsgi.py
|
|
1288
|
+
├── agents/
|
|
1289
|
+
│ ├── __init__.py
|
|
1290
|
+
│ ├── runtimes.py # Your agent implementations
|
|
1291
|
+
│ └── urls.py # API routes
|
|
1292
|
+
├── manage.py
|
|
1293
|
+
└── requirements.txt
|
|
1294
|
+
|
|
1295
|
+
# Next.js frontend (separate repo)
|
|
1296
|
+
my-frontend/
|
|
1297
|
+
├── app/
|
|
1298
|
+
│ └── layout.tsx # Include chat widget here
|
|
1299
|
+
├── components/
|
|
1300
|
+
│ └── AgentChat.tsx # Or as a component
|
|
1301
|
+
└── package.json
|
|
1302
|
+
```
|
|
1303
|
+
|
|
1304
|
+
### Environment Variables
|
|
1305
|
+
|
|
1306
|
+
**Django (.env):**
|
|
1307
|
+
```bash
|
|
1308
|
+
OPENAI_API_KEY=sk-...
|
|
1309
|
+
DATABASE_URL=postgres://... # For production
|
|
1310
|
+
REDIS_URL=redis://... # For production
|
|
1311
|
+
DEBUG=True
|
|
1312
|
+
```
|
|
1313
|
+
|
|
1314
|
+
**Next.js (.env.local):**
|
|
1315
|
+
```bash
|
|
1316
|
+
NEXT_PUBLIC_API_URL=http://localhost:8000
|
|
1317
|
+
```
|
|
1318
|
+
|
|
1319
|
+
### Quick Reference Commands
|
|
1320
|
+
|
|
1321
|
+
```bash
|
|
1322
|
+
# Django
|
|
1323
|
+
python manage.py runserver # Start API server
|
|
1324
|
+
python manage.py runagent # Start agent workers
|
|
1325
|
+
python manage.py migrate # Run migrations
|
|
1326
|
+
|
|
1327
|
+
# Next.js
|
|
1328
|
+
npm run dev # Start frontend
|
|
1329
|
+
|
|
1330
|
+
# Testing
|
|
1331
|
+
curl -X POST http://localhost:8000/api/agents/conversations/ \
|
|
1332
|
+
-H "Content-Type: application/json" \
|
|
1333
|
+
-d '{"agent_key": "hello-agent"}'
|
|
1334
|
+
```
|
|
1335
|
+
|
|
1336
|
+
---
|
|
1337
|
+
|
|
701
1338
|
## Contributing
|
|
702
1339
|
|
|
703
1340
|
Contributions are welcome! Please feel free to submit a Pull Request.
|