From 950b5b31ce753b863b7a519e3f813b6bfa81f201 Mon Sep 17 00:00:00 2001 From: Ishaan Jaffer Date: Thu, 8 Jan 2026 13:52:05 +0530 Subject: [PATCH] init MANUS --- litellm/llms/manus/__init__.py | 2 + litellm/llms/manus/responses/__init__.py | 2 + .../test_manus_responses_api.py | 110 ++++++++++++++++++ tests/test_litellm/llms/manus/__init__.py | 2 + .../llms/manus/responses/__init__.py | 2 + 5 files changed, 118 insertions(+) create mode 100644 litellm/llms/manus/__init__.py create mode 100644 litellm/llms/manus/responses/__init__.py create mode 100644 tests/llm_responses_api_testing/test_manus_responses_api.py create mode 100644 tests/test_litellm/llms/manus/__init__.py create mode 100644 tests/test_litellm/llms/manus/responses/__init__.py diff --git a/litellm/llms/manus/__init__.py b/litellm/llms/manus/__init__.py new file mode 100644 index 00000000000..81eef025461 --- /dev/null +++ b/litellm/llms/manus/__init__.py @@ -0,0 +1,2 @@ +# Manus provider implementation + diff --git a/litellm/llms/manus/responses/__init__.py b/litellm/llms/manus/responses/__init__.py new file mode 100644 index 00000000000..e8cabc54266 --- /dev/null +++ b/litellm/llms/manus/responses/__init__.py @@ -0,0 +1,2 @@ +# Manus Responses API implementation + diff --git a/tests/llm_responses_api_testing/test_manus_responses_api.py b/tests/llm_responses_api_testing/test_manus_responses_api.py new file mode 100644 index 00000000000..eb2fc81a1fb --- /dev/null +++ b/tests/llm_responses_api_testing/test_manus_responses_api.py @@ -0,0 +1,110 @@ +import os +import sys +import pytest +import asyncio +from typing import Optional +from unittest.mock import patch, AsyncMock + +sys.path.insert(0, os.path.abspath("../..")) +import litellm +from litellm.integrations.custom_logger import CustomLogger +import json +from litellm.types.utils import StandardLoggingPayload +from litellm.types.llms.openai import ( + ResponseCompletedEvent, + ResponsesAPIResponse, + ResponseAPIUsage, + IncompleteDetails, +) +from litellm.llms.custom_httpx.http_handler import AsyncHTTPHandler +from base_responses_api import BaseResponsesAPITest + + +class TestManusResponsesAPITest(BaseResponsesAPITest): + def get_base_completion_call_args(self): + return { + "model": "manus/manus-1.6", + "api_key": os.getenv("MANUS_API_KEY"), + } + + @pytest.mark.parametrize("sync_mode", [True, False]) + @pytest.mark.asyncio + async def test_basic_openai_responses_delete_endpoint(self, sync_mode): + pytest.skip("DELETE responses is not supported for Manus") + + @pytest.mark.parametrize("sync_mode", [True, False]) + @pytest.mark.asyncio + async def test_basic_openai_responses_streaming_delete_endpoint(self, sync_mode): + pytest.skip("DELETE responses is not supported for Manus") + + @pytest.mark.parametrize("sync_mode", [True, False]) + @pytest.mark.asyncio + async def test_basic_openai_responses_get_endpoint(self, sync_mode): + pytest.skip("GET responses is not supported for Manus") + + @pytest.mark.parametrize("sync_mode", [True, False]) + @pytest.mark.asyncio + async def test_basic_openai_responses_cancel_endpoint(self, sync_mode): + pytest.skip("CANCEL responses is not supported for Manus") + + @pytest.mark.parametrize("sync_mode", [True, False]) + @pytest.mark.asyncio + async def test_cancel_responses_invalid_response_id(self, sync_mode): + pytest.skip("CANCEL responses is not supported for Manus") + + +@pytest.mark.asyncio +async def test_manus_responses_api_with_agent_profile(): + """ + Test that Manus API correctly extracts agent profile from model name + and includes task_mode and agent_profile in the request. + """ + litellm._turn_on_debug() + + response = await litellm.aresponses( + model="manus/manus-1.6", + input="What's the color of the sky?", + api_key=os.getenv("MANUS_API_KEY"), + max_output_tokens=50, + ) + + print("Manus response=", json.dumps(response, indent=4, default=str)) + + # Validate response structure + assert isinstance(response, ResponsesAPIResponse), "Response should be ResponsesAPIResponse" + assert response.id is not None, "Response should have an ID" + assert response.status in ["running", "completed", "pending"], f"Status should be valid, got {response.status}" + + # Check that metadata includes Manus-specific fields + if response.metadata: + assert "task_id" in response.metadata or "task_url" in response.metadata, ( + "Manus response should include task_id or task_url in metadata" + ) + + +@pytest.mark.asyncio +async def test_manus_responses_api_different_agent_profiles(): + """ + Test that different agent profiles work correctly. + """ + litellm._turn_on_debug() + + # Test with different agent profile variants + agent_profiles = ["manus-1.6", "manus-1.6-lite", "manus-1.6-max"] + + for profile in agent_profiles: + try: + response = await litellm.aresponses( + model=f"manus/{profile}", + input="Hello", + api_key=os.getenv("MANUS_API_KEY"), + max_output_tokens=20, + ) + + assert response.id is not None, f"Response for {profile} should have an ID" + print(f"✓ {profile} works: {response.id}") + except Exception as e: + # Some profiles might not be available, that's okay + print(f"⚠ {profile} not available: {e}") + pass + diff --git a/tests/test_litellm/llms/manus/__init__.py b/tests/test_litellm/llms/manus/__init__.py new file mode 100644 index 00000000000..d4037b65199 --- /dev/null +++ b/tests/test_litellm/llms/manus/__init__.py @@ -0,0 +1,2 @@ +# Manus provider tests + diff --git a/tests/test_litellm/llms/manus/responses/__init__.py b/tests/test_litellm/llms/manus/responses/__init__.py new file mode 100644 index 00000000000..a7131749c5c --- /dev/null +++ b/tests/test_litellm/llms/manus/responses/__init__.py @@ -0,0 +1,2 @@ +# Manus Responses API tests +