Skip to content

Commit c47e4e0

Browse files
authored
Merge pull request #15 from rpdevmp/crewai-render-agent
Add CrewAI Render agent example
2 parents cc3d811 + 66b66b6 commit c47e4e0

File tree

5 files changed

+186
-0
lines changed

5 files changed

+186
-0
lines changed
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
# crewai-render-agent
2+
3+
Minimal example of hosting **CrewAI agents behind an HTTP API** using **FastAPI**, designed to be deployed on **Render** and consumed by **Redpanda ADP** (or any system expecting an OpenAI-compatible API).
4+
The service exposes a `/v1/chat/completions` endpoint and returns responses generated by a CrewAI agent.
5+
6+
---
7+
8+
## Features
9+
10+
- CrewAI agent execution
11+
- OpenAI-compatible `POST /v1/chat/completions`
12+
- Works locally and on Render (free tier)
13+
- Designed for ADP agent base URL integration
14+
15+
---
16+
17+
## Requirements
18+
19+
- Python 3.11 (recommended)
20+
- pip
21+
- OpenAI API key or Azure OpenAI credentials
22+
23+
---
24+
25+
## Local Setup
26+
27+
### Create virtual environment
28+
```bash
29+
python3.11 -m venv .venv
30+
source .venv/bin/activate
31+
```
32+
33+
### Install dependencies
34+
```bash
35+
pip install -r requirements.txt
36+
```
37+
38+
### Create .env
39+
```env
40+
OPENAI_API_KEY=sk-xxxx
41+
```
42+
43+
### Run Locally
44+
```bash
45+
uvicorn main:app --reload --host 0.0.0.0 --port 8000
46+
```
47+
48+
### Health check:
49+
```bash
50+
curl http://localhost:8000/health
51+
```
52+
53+
### Test agent:
54+
```json
55+
curl -s http://localhost:8000/v1/chat/completions \
56+
-H "Content-Type: application/json" \
57+
-d '{"messages":[{"role":"user","content":"hello"}]}'
58+
```
59+
60+
## API
61+
POST /v1/chat/completions
62+
63+
64+
### Request:
65+
```bash
66+
{
67+
"messages": [
68+
{ "role": "user", "content": "hello" }
69+
]
70+
}
71+
```
72+
73+
### Response:
74+
```bash
75+
{
76+
"choices": [
77+
{
78+
"message": {
79+
"role": "assistant",
80+
"content": "..."
81+
}
82+
}
83+
]
84+
}
85+
```
Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
import traceback
2+
import uuid
3+
4+
from crewai import Agent, Crew, Process, Task
5+
from dotenv import load_dotenv
6+
from fastapi import FastAPI
7+
from pydantic import BaseModel
8+
9+
load_dotenv()
10+
11+
app = FastAPI()
12+
13+
@app.get("/health")
14+
def health():
15+
return {"ok": True}
16+
17+
18+
class ChatCompletionRequest(BaseModel):
19+
model: str | None = None
20+
messages: list[dict] # [{"role":"user","content":"hello"}]
21+
temperature: float | None = None
22+
stream: bool | None = False
23+
24+
25+
def run_crewai(user_text: str) -> str:
26+
# Minimal CrewAI example: 1 agent, 1 task
27+
agent = Agent(
28+
role="Assistant",
29+
goal="Reply helpfully and concisely.",
30+
backstory="You are a helpful AI agent hosted for ADP integration.",
31+
verbose=True,
32+
allow_delegation=False,
33+
)
34+
35+
task = Task(
36+
description=f"User said: {user_text}\nReply to the user.",
37+
expected_output="A helpful natural-language reply to the user.",
38+
agent=agent,
39+
)
40+
41+
crew = Crew(
42+
agents=[agent],
43+
tasks=[task],
44+
process=Process.sequential,
45+
verbose=1,
46+
)
47+
48+
result = crew.kickoff()
49+
return str(result)
50+
51+
52+
@app.post("/v1/chat/completions")
53+
async def chat_completions(req: ChatCompletionRequest):
54+
try:
55+
user_text = ""
56+
for m in reversed(req.messages):
57+
if m.get("role") == "user":
58+
user_text = (m.get("content") or "").strip()
59+
break
60+
61+
if not user_text:
62+
return {
63+
"error": {
64+
"message": "No user message provided.",
65+
"type": "invalid_request_error",
66+
}
67+
}
68+
69+
answer = run_crewai(user_text)
70+
71+
return {
72+
"id": f"chatcmpl-{uuid.uuid4().hex}",
73+
"object": "chat.completion",
74+
"choices": [
75+
{
76+
"index": 0,
77+
"message": {"role": "assistant", "content": answer},
78+
"finish_reason": "stop",
79+
}
80+
],
81+
}
82+
except Exception:
83+
traceback.print_exc()
84+
return {
85+
"error": {
86+
"message": "An internal error occurred.",
87+
"type": "internal_error",
88+
}
89+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
{
2+
"reportMissingImports": "none",
3+
"reportMissingModuleSource": "none",
4+
"exclude": [
5+
"examples/crewai-render-agent"
6+
]
7+
}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
fastapi
2+
uvicorn[standard]
3+
crewai
4+
python-dotenv

pyproject.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@ packages = ["src/redpanda"]
7575
[tool.pyright]
7676
exclude = [
7777
"src/redpanda/runtime/v1alpha1/**",
78+
"examples/crewai-render-agent/**",
7879
"**/__pycache__",
7980
"**/.*",
8081
]

0 commit comments

Comments
 (0)