Sheyda Kiani Mehr commited on
Commit
160df9d
·
1 Parent(s): bb3a1e6

Swap to minimal FastAPI A2A server (no a2a lib)

Browse files
Files changed (5) hide show
  1. Dockefile +9 -0
  2. main.py +58 -32
  3. requirements.txt +4 -0
  4. test.py +41 -0
  5. Dockerfile → test_docker +1 -0
Dockefile ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
 
1
+ FROM python:3.11-slim
2
+ ENV PYTHONDONTWRITEBYTECODE=1 PYTHONUNBUFFERED=1 PORT=7860
3
+ WORKDIR /app
4
+ COPY requirements.txt .
5
+ RUN pip install --no-cache-dir -r requirements.txt
6
+ COPY . .
7
+ EXPOSE 7860
8
+ CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "7860"]
9
+
main.py CHANGED
@@ -1,41 +1,67 @@
1
- # main.py
2
  import os
3
- import uvicorn
 
4
 
5
- # ---- Adjust imports to match a2a-python ----
6
- # These paths are common in the tutorial; if yours differ, change them accordingly.
7
- from a2a.server.apps import A2AStarletteApplication
8
- from a2a.server.request_handlers import DefaultRequestHandler
9
- from a2a.server.tasks import InMemoryTaskStore
10
 
11
- # Example minimal executor
12
- class HelloWorldAgentExecutor:
13
- async def call(self, message: str, **kwargs):
14
- return {"text": f"Hello from A2A on HF Spaces! You said: {message}"}
15
 
16
- # Example minimal public AgentCard (adjust fields to your spec)
17
  AGENT_CARD = {
18
- "name": "HF A2A Agent",
19
- "version": "1.0",
20
- "description": "A2A demo running on Hugging Face Spaces",
21
- "endpoints": {
22
- "send": "/message/send",
23
- "stream": "/message/stream"
24
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
25
  }
26
 
27
- def build_app():
28
- app = A2AStarletteApplication(
29
- agent_card=AGENT_CARD,
30
- http_handler=DefaultRequestHandler(
31
- agent_executor=HelloWorldAgentExecutor(),
32
- task_store=InMemoryTaskStore(),
33
- ),
34
- # extended_agent_card=... # optional
35
- ).build()
36
- return app
37
 
38
- if __name__ == "__main__":
39
- port = int(os.getenv("PORT", "7860")) # HF provides PORT
40
- uvicorn.run(build_app(), host="0.0.0.0", port=port)
 
 
 
 
 
 
 
 
 
 
41
 
 
 
1
  import os
2
+ from fastapi import FastAPI, Request
3
+ from fastapi.responses import JSONResponse
4
 
5
+ app = FastAPI(title="HF A2A Agent")
 
 
 
 
6
 
7
+ def hello_agent(message: str):
8
+ return {"text": f"Hello from A2A on HF Spaces! You said: {message}"}
 
 
9
 
 
10
  AGENT_CARD = {
11
+ "protocolVersion": "0.3.0",
12
+ "name": "Hello World Agent",
13
+ "description": "A simple A2A agent that responds with 'Hello World' to any request",
14
+ "url": "https://{HOST}/a2a",
15
+ "preferredTransport": "HTTP+JSON",
16
+ "version": "1.0.0",
17
+ "capabilities": {
18
+ "streaming": False,
19
+ "pushNotifications": False,
20
+ "stateTransitionHistory": False
21
+ },
22
+ "defaultInputModes": ["text/plain", "application/json"],
23
+ "defaultOutputModes": ["text/plain", "application/json"],
24
+ "skills": [
25
+ {
26
+ "id": "hello",
27
+ "name": "Say Hello",
28
+ "description": "Responds with a friendly 'Hello World' message",
29
+ "tags": ["greeting", "hello", "simple"],
30
+ "inputModes": ["text/plain", "application/json"],
31
+ "outputModes": ["text/plain", "application/json"],
32
+ "examples": ["Say hello", "Greet me", "Hello"]
33
+ }
34
+ ],
35
+ "provider": {
36
+ "organization": "A2A Registry Team",
37
+ "url": "https://github.com/prassanna-ravishankar/a2a-registry"
38
+ },
39
+ "documentationUrl": "https://github.com/prassanna-ravishankar/a2a-registry",
40
+ "author": "A2A Registry Team",
41
+ "homepage": "https://hello.a2aregistry.org",
42
+ "license": "MIT"
43
  }
44
 
45
+ @app.get("/.well-known/agent-card.json")
46
+ async def agent_card(request: Request):
47
+ host = request.headers.get("x-forwarded-host") or request.headers.get("host") or "localhost:7860"
48
+ proto = request.headers.get("x-forwarded-proto") or "https"
49
+ url_base = f"{proto}://{host}"
50
+ card = dict(AGENT_CARD)
51
+ card["url"] = AGENT_CARD["url"].replace("{HOST}", host).replace("https://{HOST}", url_base)
52
+ return JSONResponse(card)
 
 
53
 
54
+ @app.get("/")
55
+ async def root():
56
+ return {"status": "ok", "send_endpoint": "/a2a"}
57
+
58
+ @app.post("/a2a")
59
+ async def a2a_endpoint(request: Request):
60
+ ctype = request.headers.get("content-type", "")
61
+ if "application/json" in ctype:
62
+ body = await request.json()
63
+ msg = body.get("message") or body.get("text") or str(body)
64
+ return JSONResponse(hello_agent(msg))
65
+ text = (await request.body()).decode("utf-8", errors="ignore")
66
+ return JSONResponse(hello_agent(text))
67
 
requirements.txt CHANGED
@@ -1,4 +1,8 @@
1
  uvicorn>=0.30
2
  starlette>=0.37
 
 
3
  # The A2A library (adjust to the name/extra you use)
4
  a2a-python
 
 
 
1
  uvicorn>=0.30
2
  starlette>=0.37
3
+ fastapi==0.115.0
4
+ uvicorn[standard]==0.30.6
5
  # The A2A library (adjust to the name/extra you use)
6
  a2a-python
7
+ #fastapi==0.115.0
8
+ #uvicorn[standard]==0.30.6
test.py ADDED
@@ -0,0 +1,41 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # main.py
2
+ import os
3
+ import uvicorn
4
+
5
+ # ---- Adjust imports to match a2a-python ----
6
+ # These paths are common in the tutorial; if yours differ, change them accordingly.
7
+ from a2a.server.apps import A2AStarletteApplication
8
+ from a2a.server.request_handlers import DefaultRequestHandler
9
+ from a2a.server.tasks import InMemoryTaskStore
10
+
11
+ # Example minimal executor
12
+ class HelloWorldAgentExecutor:
13
+ async def call(self, message: str, **kwargs):
14
+ return {"text": f"Hello from A2A on HF Spaces! You said: {message}"}
15
+
16
+ # Example minimal public AgentCard (adjust fields to your spec)
17
+ AGENT_CARD = {
18
+ "name": "HF A2A Agent",
19
+ "version": "1.0",
20
+ "description": "A2A demo running on Hugging Face Spaces",
21
+ "endpoints": {
22
+ "send": "/message/send",
23
+ "stream": "/message/stream"
24
+ }
25
+ }
26
+
27
+ def build_app():
28
+ app = A2AStarletteApplication(
29
+ agent_card=AGENT_CARD,
30
+ http_handler=DefaultRequestHandler(
31
+ agent_executor=HelloWorldAgentExecutor(),
32
+ task_store=InMemoryTaskStore(),
33
+ ),
34
+ # extended_agent_card=... # optional
35
+ ).build()
36
+ return app
37
+
38
+ if __name__ == "__main__":
39
+ port = int(os.getenv("PORT", "7860")) # HF provides PORT
40
+ uvicorn.run(build_app(), host="0.0.0.0", port=port)
41
+
Dockerfile → test_docker RENAMED
@@ -12,4 +12,5 @@ COPY . .
12
 
13
  # Start the server. HF injects $PORT; our main.py reads it.
14
  CMD ["python", "main.py"]
 
15
 
 
12
 
13
  # Start the server. HF injects $PORT; our main.py reads it.
14
  CMD ["python", "main.py"]
15
+ :x
16