Repository: BerriAI/litellm

Issue:
[Bug]: Ollama cannot be added in the UI BASE_URL is missing
### What happened?

Ollama cannot be added in the UI BASE_URL is missing.

I want to use LiteLLM to host a number of devices with varying providers. One Ollama, another LM Studio, etc and expose it via the LiteLLM Proxy so I don't need to expose everything but can proxy everything through one portal.

![Image](https://github.com/user-attachments/assets/705ff955-b43e-42a1-b45d-df168e9f9cfe)

### Relevant log output

```shell

```

### Are you a ML Ops Team?

No

### What LiteLLM version are you on ?

ghcr.io/berriai/litellm:main-stable

### Twitter / LinkedIn details

_No response_

Discussion:
@devbysb: Hi by default it is localhost but I need to custom api_base the only way I've found is to use the config.yaml files. Is it possible to add this custom parameter on the ui ?

Solution patch:
diff --git a/litellm/constants.py b/litellm/constants.py
index 6ef284bc3..8d49f2bef 100644
--- a/litellm/constants.py
+++ b/litellm/constants.py
@@ -4,7 +4,7 @@ ROUTER_MAX_FALLBACKS = 5
 DEFAULT_BATCH_SIZE = 512
 DEFAULT_FLUSH_INTERVAL_SECONDS = 5
 DEFAULT_MAX_RETRIES = 2
-DEFAULT_MAX_RECURSE_DEPTH = 10
+DEFAULT_MAX_RECURSE_DEPTH = 100
 DEFAULT_FAILURE_THRESHOLD_PERCENT = (
     0.5  # default cooldown a deployment if 50% of requests fail in a given minute
 )
diff --git a/ui/litellm-dashboard/src/components/add_model/provider_specific_fields.tsx b/ui/litellm-dashboard/src/components/add_model/provider_specific_fields.tsx
index 7146ae2b9..bc826c27d 100644
--- a/ui/litellm-dashboard/src/components/add_model/provider_specific_fields.tsx
+++ b/ui/litellm-dashboard/src/components/add_model/provider_specific_fields.tsx
@@ -241,7 +241,16 @@ const PROVIDER_CREDENTIAL_FIELDS: Record<Providers, ProviderCredentialField[]> =
       tooltip: "You can provide the raw key or the environment variable (e.g. `os.environ/MY_SECRET_KEY`)."
     }
   ],
-  [Providers.Ollama]: [], // No specific fields needed
+  [Providers.Ollama]: [
+    {
+      key: "api_base",
+      label: "API Base",
+      placeholder: "http://localhost:11434",
+      defaultValue: "http://localhost:11434",
+      required: false,
+      tooltip: "The base URL for your Ollama server. Defaults to http://localhost:11434 if not specified."
+    }
+  ],
   [Providers.Anthropic]: [{
     key: "api_key",
     label: "API Key",


Test patch:
diff --git a/tests/litellm/llms/vertex_ai/test_vertex_ai_common_utils.py b/tests/litellm/llms/vertex_ai/test_vertex_ai_common_utils.py
index ddf3f8fde..90a7fb30e 100644
--- a/tests/litellm/llms/vertex_ai/test_vertex_ai_common_utils.py
+++ b/tests/litellm/llms/vertex_ai/test_vertex_ai_common_utils.py
@@ -292,3 +292,227 @@ def test_process_items_basic():
     }
     process_items(schema)
     assert schema["properties"]["nested"]["items"] == {"type": "object"}
+
+
+def test_vertex_ai_complex_response_schema():
+    import json
+    from copy import deepcopy
+
+    from litellm.llms.vertex_ai.gemini.vertex_and_google_ai_studio_gemini import (
+        VertexGeminiConfig,
+    )
+
+    v = VertexGeminiConfig()
+    non_default_params = {
+        "messages": [{"role": "user", "content": "Hello, world!"}],
+        "response_format": {
+            "type": "json_schema",
+            "json_schema": {
+                "name": "generic_schema",
+                "schema": {
+                    "$id": "https://example.com/schema",
+                    "type": "object",
+                    "$schema": "https://json-schema.org/draft/2020-12/schema",
+                    "required": ["field1", "field2", "field3"],
+                    "properties": {
+                        "field3": {
+                            "type": "array",
+                            "items": {
+                                "type": "object",
+                                "required": ["subfield1", "subfield2"],
+                                "properties": {
+                                    "subfield1": {
+                                        "type": "string",
+                                        "description": "string field",
+                                    },
+                                    "subfield2": {
+                                        "type": "array",
+                                        "items": {
+                                            "type": "object",
+                                            "oneOf": [
+                                                {
+                                                    "title": "Type1",
+                                                    "required": ["Type1"],
+                                                },
+                                                {
+                                                    "title": "Type2",
+                                                    "required": ["Type2"],
+                                                },
+                                                {
+                                                    "title": "Type3",
+                                                    "required": ["Type3"],
+                                                },
+                                            ],
+                                            "properties": {
+                                                "Type1": {
+                                                    "type": "object",
+                                                    "required": ["prop1", "prop2"],
+                                                    "properties": {
+                                                        "prop1": {
+                                                            "type": "string",
+                                                            "description": "string value",
+                                                        },
+                                                        "prop2": {
+                                                            "type": "string",
+                                                            "description": "string value",
+                                                        },
+                                                    },
+                                                    "additionalProperties": False,
+                                                },
+                                                "Type3": {
+                                                    "type": "object",
+                                                    "required": ["prop1", "prop3"],
+                                                    "properties": {
+                                                        "prop1": {
+                                                            "type": "string",
+                                                            "description": "string value",
+                                                        },
+                                                        "prop3": {
+                                                            "type": "array",
+                                                            "items": {
+                                                                "type": "object",
+                                                                "required": [
+                                                                    "item1",
+                                                                    "item2",
+                                                                ],
+                                                                "properties": {
+                                                                    "item1": {
+                                                                        "type": "string",
+                                                                        "description": "string value",
+                                                                    },
+                                                                    "item2": {
+                                                                        "type": "boolean",
+                                                                        "description": "boolean value",
+                                                                    },
+                                                                },
+                                                                "additionalProperties": False,
+                                                            },
+                                                        },
+                                                    },
+                                                    "additionalProperties": False,
+                                                },
+                                                "Type2": {
+                                                    "type": "object",
+                                                    "required": ["prop1", "prop3"],
+                                                    "properties": {
+                                                        "prop1": {
+                                                            "type": "string",
+                                                            "description": "string value",
+                                                        },
+                                                        "prop3": {
+                                                            "type": "array",
+                                                            "items": {
+                                                                "type": "object",
+                                                                "required": [
+                                                                    "item1",
+                                                                    "item2",
+                                                                ],
+                                                                "properties": {
+                                                                    "item1": {
+                                                                        "type": "string",
+                                                                        "description": "string value",
+                                                                    },
+                                                                    "item2": {
+                                                                        "type": "boolean",
+                                                                        "description": "boolean value",
+                                                                    },
+                                                                },
+                                                                "additionalProperties": False,
+                                                            },
+                                                        },
+                                                    },
+                                                    "additionalProperties": False,
+                                                },
+                                            },
+                                            "additionalProperties": False,
+                                        },
+                                    },
+                                },
+                                "additionalProperties": False,
+                            },
+                        },
+                        "field1": {"type": "string", "description": "string field"},
+                        "field2": {"type": "string", "description": "string field"},
+                    },
+                    "additionalProperties": False,
+                },
+                "strict": True,
+                "description": "Generic schema for testing",
+            },
+        },
+    }
+    original_non_default_params = deepcopy(non_default_params)
+    optional_params = {}
+
+    v.apply_response_schema_transformation(
+        value=non_default_params["response_format"], optional_params=optional_params
+    )
+
+    # Assertions for the transformed schema
+    transformed_schema = optional_params["response_schema"]
+
+    # Check top level structure
+    assert transformed_schema["type"] == "object"
+    assert "propertyOrdering" in transformed_schema
+    assert transformed_schema["propertyOrdering"] == ["field3", "field1", "field2"]
+    assert set(transformed_schema["required"]) == {"field1", "field2", "field3"}
+
+    # Check field3 structure (array of objects)
+    field3 = transformed_schema["properties"]["field3"]
+    assert field3["type"] == "array"
+
+    # Check field3 items structure
+    field3_items = field3["items"]
+    assert field3_items["type"] == "object"
+    assert "propertyOrdering" in field3_items
+    assert field3_items["propertyOrdering"] == ["subfield1", "subfield2"]
+    assert set(field3_items["required"]) == {"subfield1", "subfield2"}
+
+    # Check subfield2 structure (array of objects)
+    subfield2 = field3_items["properties"]["subfield2"]
+    assert subfield2["type"] == "array"
+
+    # Check subfield2 items structure
+    subfield2_items = subfield2["items"]
+    assert subfield2_items["type"] == "object"
+    assert "propertyOrdering" in subfield2_items
+    assert subfield2_items["propertyOrdering"] == ["Type1", "Type3", "Type2"]
+
+    # Check Type1 structure
+    type1 = subfield2_items["properties"]["Type1"]
+    assert type1["type"] == "object"
+    assert "propertyOrdering" in type1
+    assert type1["propertyOrdering"] == ["prop1", "prop2"]
+    assert set(type1["required"]) == {"prop1", "prop2"}
+
+    # Check Type2 structure
+    type2 = subfield2_items["properties"]["Type2"]
+    assert type2["type"] == "object"
+    assert "propertyOrdering" in type2
+    assert type2["propertyOrdering"] == ["prop1", "prop3"]
+    assert set(type2["required"]) == {"prop1", "prop3"}
+
+    # Check Type3 structure
+    type3 = subfield2_items["properties"]["Type3"]
+    assert type3["type"] == "object"
+    assert "propertyOrdering" in type3
+    assert type3["propertyOrdering"] == ["prop1", "prop3"]
+    assert set(type3["required"]) == {"prop1", "prop3"}
+
+    # Check nested items in Type3's prop3
+    type3_prop3 = type3["properties"]["prop3"]
+    assert type3_prop3["type"] == "array"
+    type3_prop3_items = type3_prop3["items"]
+    assert type3_prop3_items["type"] == "object"
+    assert "propertyOrdering" in type3_prop3_items
+    assert type3_prop3_items["propertyOrdering"] == ["item1", "item2"]
+    assert set(type3_prop3_items["required"]) == {"item1", "item2"}
+
+    # Verify additionalProperties were removed during transformation
+    assert "additionalProperties" not in transformed_schema
+    assert "additionalProperties" not in field3_items
+    assert "additionalProperties" not in subfield2_items
+    assert "additionalProperties" not in type1
+    assert "additionalProperties" not in type2
+    assert "additionalProperties" not in type3
+    assert "additionalProperties" not in type3_prop3_items