{"id":50168193,"url":"https://github.com/cyphercoderr/wandai-challenge-1-multi-agent-task-solver","last_synced_at":"2026-05-24T22:02:54.215Z","repository":{"id":313550030,"uuid":"1051796931","full_name":"cyphercoderr/WandAI-Challenge-1-Multi-Agent-Task-Solver","owner":"cyphercoderr","description":" Implement the agent orchestration layer: Each agent runs in isolation but can pass results to others.   Handle concurrency, retries, and timeouts.   Enable pluggable tools (e.g., data fetcher, chart generator).   Provide a clear API for frontend consumption.","archived":false,"fork":false,"pushed_at":"2025-09-06T21:17:16.000Z","size":11,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"master","last_synced_at":"2025-09-06T21:29:26.442Z","etag":null,"topics":["asyncio","fastapi","python","uvicorn"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/cyphercoderr.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2025-09-06T18:32:24.000Z","updated_at":"2025-09-06T21:17:19.000Z","dependencies_parsed_at":"2025-09-06T21:29:30.125Z","dependency_job_id":"0388e71a-dad4-4479-8b00-23b8e154f703","html_url":"https://github.com/cyphercoderr/WandAI-Challenge-1-Multi-Agent-Task-Solver","commit_stats":null,"previous_names":["cyphercoderr/wandai-challenge-1-multi-agent-task-solver"],"tags_count":null,"template":false,"template_full_name":null,"purl":"pkg:github/cyphercoderr/WandAI-Challenge-1-Multi-Agent-Task-Solver","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cyphercoderr%2FWandAI-Challenge-1-Multi-Agent-Task-Solver","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cyphercoderr%2FWandAI-Challenge-1-Multi-Agent-Task-Solver/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cyphercoderr%2FWandAI-Challenge-1-Multi-Agent-Task-Solver/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cyphercoderr%2FWandAI-Challenge-1-Multi-Agent-Task-Solver/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/cyphercoderr","download_url":"https://codeload.github.com/cyphercoderr/WandAI-Challenge-1-Multi-Agent-Task-Solver/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cyphercoderr%2FWandAI-Challenge-1-Multi-Agent-Task-Solver/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":33452033,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-24T19:21:36.376Z","status":"ssl_error","status_checked_at":"2026-05-24T19:21:10.562Z","response_time":57,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["asyncio","fastapi","python","uvicorn"],"created_at":"2026-05-24T22:02:50.135Z","updated_at":"2026-05-24T22:02:54.205Z","avatar_url":"https://github.com/cyphercoderr.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Wand AI – Challenge 1: Multi-Agent Task Solver\n\nA minimal, production-lean prototype of an **agent orchestration layer** built with  \n**Python + FastAPI + asyncio**.\n\n---\n\n## Note\nThe agents provided here (Echo, Sum, HttpGet) are **hardcoded sample agents** to mimic real-time conversation behavior. They demonstrate orchestration mechanics, not domain logic.\n\n---\n\n## Why Challenge 1?\nThis aligns directly with Wand AI’s mission of operating and connecting **agent ecosystems**.  \nThe prototype demonstrates:\n\n- **Dynamic agent creation** and a **DAG execution graph**\n- **Concurrency**, **retries**, and **timeouts**\n- **Pluggable tools** (e.g., HTTP data fetcher, chart generator)\n- A clean **HTTP API** ready for frontend consumption\n\n---\n\n## Architecture\n- **FastAPI** → API layer  \n- **Orchestrator** → DAG executor (via `networkx`) with concurrency  \n- **Retries** → with exponential backoff (`tenacity`)  \n- **Timeouts** → via `asyncio.wait_for`  \n- **Pluggable agents/tools** → registered in simple registries  \n- **In-memory run store** → for simplicity (can be swapped with Redis/Postgres)\n```\napp/\nagents.py # BaseAgent + sample agents (Echo, Sum, HttpGet)\ntools.py # BaseTool + sample tools (DataFetcher, ChartGenerator)\norchestrator.py # DAG builder + concurrent executor, retries/timeouts\nmodels.py # Pydantic models for API contracts\nmain.py # FastAPI app (execute graph, get run)\n```\n\n---\n\n## How It Works\n\n1. **User submits a graph** via `POST /graph/execute`  \n   - Nodes = agents with configs \u0026 inputs  \n   - Edges = dependencies between nodes  \n\n2. **The Orchestrator**:  \n   - Builds the DAG and validates it is acyclic  \n   - Resolves dependencies (inputs can reference outputs from other nodes)  \n   - Runs nodes layer-by-layer with concurrency (using `asyncio.Semaphore`)  \n   - Applies **retries** and **timeouts** per node  \n\n3. **Agents**:  \n   - Run in isolation and return results  \n   - Results are stored in the orchestration context and passed downstream  \n\n4. **Response**:  \n   - The API returns a `run_id`, `status`, `result` (node outputs), and any `error`  \n\n---\n\n## Running Locally\n**Prereqs:** Python 3.11+\n\n```bash\npip install -r requirements.txt\nuvicorn app.main:app --reload\n# open http://localhost:8000/docs\n```\n## Running with Docker\n```\ndocker build -t wandai-agents .\ndocker run -p 8000:8000 wandai-agents\n# or: docker compose up --build\n```\n## Example: Execute a 3-node DAG\n\nHere’s a sample request where:\n* Node A echoes a message\n* Node B sums numbers [1,2,3,4]\n* Node C fetches content from https://example.com, depending on A \u0026 B\n\n## JSON request (for Swagger /graph/execute)\n```json\n{\n  \"concurrency\": 4,\n  \"graph\": {\n    \"nodes\": [\n      {\n        \"id\": \"A\",\n        \"agent\": { \"name\": \"echo\", \"params\": {}, \"tools\": [] },\n        \"inputs\": { \"msg\": \"hello from A\" },\n        \"timeout_seconds\": 10,\n        \"max_retries\": 2\n      },\n      {\n        \"id\": \"B\",\n        \"agent\": { \"name\": \"sum\", \"params\": {}, \"tools\": [] },\n        \"inputs\": { \"numbers\": [1, 2, 3, 4] },\n        \"timeout_seconds\": 10,\n        \"max_retries\": 2\n      },\n      {\n        \"id\": \"C\",\n        \"agent\": {\n          \"name\": \"http_get\",\n          \"params\": {},\n          \"tools\": [\n            { \"name\": \"data_fetcher\", \"config\": { \"timeout\": 5 } }\n          ]\n        },\n        \"inputs\": { \"url\": \"https://example.com\" },\n        \"timeout_seconds\": 10,\n        \"max_retries\": 2\n      }\n    ],\n    \"edges\": [\n      { \"source\": \"A\", \"target\": \"C\" },\n      { \"source\": \"B\", \"target\": \"C\" }\n    ]\n  }\n}\n```\n## Example Success Response\n```bash\n{\n  \"run_id\": \"498454e7-e10d-4e30-973e-fc2d6f53ac5d\",\n  \"status\": \"succeeded\",\n  \"result\": {\n    \"B\": {\n      \"sum\": 10,\n      \"params\": {}\n    },\n    \"A\": {\n      \"echo\": {\n        \"msg\": \"hello from A\"\n      },\n      \"params\": {}\n    },\n    \"C\": {\n      \"status\": 200,\n      \"length\": 1256,\n      \"headers\": {\n        \"Accept-Ranges\": \"bytes\",\n        \"Content-Type\": \"text/html\",\n        \"Etag\": \"\\\"84238dfc8092e5d9c0dac8ef93371a07:1736799080.121134\\\"\",\n        \"Last-Modified\": \"Mon, 13 Jan 2025 20:11:20 GMT\",\n        \"Vary\": \"Accept-Encoding\",\n        \"Content-Encoding\": \"gzip\",\n        \"Cache-Control\": \"max-age=86000\",\n        \"Date\": \"Sat, 06 Sep 2025 20:52:14 GMT\",\n        \"Alt-Svc\": \"h3=\\\":443\\\"; ma=93600,h3-29=\\\":443\\\"; ma=93600\",\n        \"Content-Length\": \"648\",\n        \"Connection\": \"keep-alive\"\n      }\n    }\n  },\n  \"error\": null\n}\n\n```\n## Design Decisions\n* Orchestrator executes DAGs layer-by-layer with concurrency (`asyncio` + `networkx`).\n* Retries with exponential backoff (`tenacity`) ensure robustness.\n* Timeouts handled via `asyncio.wait_for` to prevent stuck nodes.\n* Agents and tools are modular via registries for easy extensibility.\n\n## Trade-offs (24h Constraint)\n* In-memory run store for speed → would use Redis/Postgres in production.\n* Minimal logging/metrics to save time → production would need structured logs \u0026 observability.\n* No authentication layer → acceptable for prototype, enterprise setup would need OAuth/JWT.\n* Single-process asyncio execution → good enough here, but a distributed queue (Celery/RQ) is better at scale.\n\n\n## Extending\n\n* Add new agents by subclassing BaseAgent and registering in AGENT_REGISTRY\n* Add tools by subclassing BaseTool and registering in TOOL_REGISTRY\n* Support future features: streaming outputs, cancellation, checkpointing\n\n## Demo Script (≤5 min)\n\n* Start API → open /docs swagger.\n* Run the example DAG request → see concurrency and results.\n* Open agents.py → show how to plug in new agents.\n* Explain retries \u0026 timeouts → show config per node.\n* Close with production hardening roadmap (auth, persistence, observability).\n\n## Tests (Quick Smoke)\n\nYou can run the sample JSON (above) in Swagger or test Orchestrator.run_graph directly.\n**For example, with pytest:**\n```python\nimport pytest\nfrom app.orchestrator import Orchestrator\nfrom app.models import GraphSpec, NodeSpec, AgentConfig\n\n@pytest.mark.asyncio\nasync def test_sum_agent():\n    graph = GraphSpec(\n        nodes=[\n            NodeSpec(\n                id=\"B\",\n                agent=AgentConfig(name=\"sum\", params={}, tools=[]),\n                inputs={\"numbers\": [1, 2, 3]},\n            )\n        ]\n    )\n    orch = Orchestrator(concurrency=2)\n    result = await orch.run_graph(graph)\n    assert result[\"B\"][\"sum\"] == 6\n```\n\n## Author\nChallenge completed by Ahmad.","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcyphercoderr%2Fwandai-challenge-1-multi-agent-task-solver","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcyphercoderr%2Fwandai-challenge-1-multi-agent-task-solver","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcyphercoderr%2Fwandai-challenge-1-multi-agent-task-solver/lists"}