langgenius / dify

Dify is an open-source LLM app development platform. Dify's intuitive interface combines AI workflow, RAG pipeline, agent capabilities, model management, observability features and more, letting you quickly go from prototype to production.
https://dify.ai
Other
50.24k stars 7.2k forks source link

When an array is specified as the request body type for a custom tool, a string is actually required #10007

Open ardRiriy opened 2 days ago

ardRiriy commented 2 days ago

Self Checks

Dify version

0.10.2

Cloud or Self Hosted

Self Hosted (Docker)

Steps to reproduce

Create a new custom tool, specify a schema that uses array as the type of request body, and save it.

Example of a problematic schema ``` { "openapi": "3.1.0", "servers": [ { "url": "http://host.docker.internal:8000" } ], "info": { "title": "FastAPI", "version": "0.1.0" }, "paths": { "/health": { "get": { "summary": "Health", "operationId": "health_health_get", "responses": { "200": { "description": "Successful Response", "content": { "application/json": { "schema": {} } } } } } }, "/v1/cluster/auth": { "get": { "summary": "Cluster Auth", "operationId": "cluster_auth_v1_cluster_auth_get", "responses": { "200": { "description": "Successful Response", "content": { "application/json": { "schema": {} } } } } } }, "/v1/models/{uid}": { "get": { "summary": "Describe Model", "operationId": "describe_model_v1_models__uid__get", "parameters": [ { "name": "uid", "in": "path", "required": true, "schema": { "type": "string", "title": "Uid" } } ], "responses": { "200": { "description": "Successful Response", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ModelDescription" } } } }, "422": { "description": "Validation Error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } } } } } }, "/v1/rerank": { "post": { "summary": "Rerank", "operationId": "rerank_v1_rerank_post", "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/RerankRequest" } } }, "required": true }, "responses": { "200": { "description": "Successful Response", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/RerankResponse" } } } }, "422": { "description": "Validation Error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } } } } } } }, "components": { "schemas": { "HTTPValidationError": { "properties": { "detail": { "items": { "$ref": "#/components/schemas/ValidationError" }, "type": "array", "title": "Detail" } }, "type": "object", "title": "HTTPValidationError" }, "ModelDescription": { "properties": { "model_type": { "type": "string", "title": "Model Type" }, "model_name": { "type": "string", "title": "Model Name" }, "model_lang": { "items": { "type": "string" }, "type": "array", "title": "Model Lang" }, "model_ability": { "items": { "type": "string" }, "type": "array", "title": "Model Ability" }, "model_description": { "type": "string", "title": "Model Description" }, "model_format": { "type": "string", "title": "Model Format" }, "model_size_in_billions": { "type": "integer", "title": "Model Size In Billions" }, "quantization": { "type": "string", "title": "Quantization" }, "revision": { "type": "string", "title": "Revision" }, "context_length": { "type": "integer", "title": "Context Length" } }, "type": "object", "required": [ "model_type", "model_name", "model_lang", "model_ability", "model_description", "model_format", "model_size_in_billions", "quantization", "revision", "context_length" ], "title": "ModelDescription" }, "RerankRequest": { "properties": { "model": { "type": "string", "title": "Model" }, "query": { "type": "string", "title": "Query" }, "documents": { "items": { "type": "string" }, "type": "array", "title": "Documents" }, "documents_json": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Documents Json" } }, "type": "object", "required": [ "model", "query", "documents" ], "title": "RerankRequest" }, "RerankResponse": { "properties": { "id": { "type": "string", "title": "Id" }, "results": { "items": { "$ref": "#/components/schemas/RerankResult" }, "type": "array", "title": "Results" } }, "type": "object", "required": [ "id", "results" ], "title": "RerankResponse" }, "RerankResult": { "properties": { "index": { "type": "integer", "title": "Index" }, "relevance_score": { "type": "number", "title": "Relevance Score" }, "document": { "type": "string", "title": "Document" } }, "type": "object", "required": [ "index", "relevance_score", "document" ], "title": "RerankResult" }, "ValidationError": { "properties": { "loc": { "items": { "anyOf": [ { "type": "string" }, { "type": "integer" } ] }, "type": "array", "title": "Location" }, "msg": { "type": "string", "title": "Message" }, "type": { "type": "string", "title": "Error Type" } }, "type": "object", "required": [ "loc", "msg", "type" ], "title": "ValidationError" } } } } ```

Check for methods that use arrays in the request body (in my example, rerank_v1_rerank_post uses arrays). A string is specified instead of an array.

This is the expected schema

      "RerankRequest": {
        "properties": {
          "model": {
            "type": "string",
            "title": "Model"
          },
          "query": {
            "type": "string",
            "title": "Query"
          },
          "documents": {
            "items": {
              "type": "string"
            },
            "type": "array",
            "title": "Documents"
          },
          "documents_json": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Documents Json"
          }
        },
        "type": "object",
        "required": [
          "model",
          "query",
          "documents"
        ],
        "title": "RerankRequest"
      },

but as shown below, documents was originally supposed to be an array but is now a string. スクリーンショット 2024-10-29 18 10 47

✔️ Expected Behavior

If an array is specified in the schema in a custom tool, it works by giving the array when using that custom tool.

❌ Actual Behavior

スクリーンショット 2024-10-29 18 18 22

Expects array[string] but requires string.

dosubot[bot] commented 2 days ago

@ardRiriy Hello there! I'm here to help you with any bugs, questions, or contributions.

I found a similar unsolved discussion regarding the issue where only strings are accepted by the Chart Tool, and arrays/lists/numbers are not accepted. You can view the discussion here [1].

In Dify, schema validation for request bodies, including arrays, is handled using JSON Schema. For arrays, you define the type as "array" and specify the "items" property to define the type of elements within the array. Here's an example:

{
    "type": "array",
    "description": "Array of reasoning steps",
    "items": {
        "type": "object",
        "properties": {
            "explanation": {
                "type": "string",
                "description": "Explanation of the reasoning step"
            },
            "output": {
                "type": "string",
                "description": "Output of the reasoning step"
            }
        },
        "required": ["explanation", "output"],
        "additionalProperties": false
    }
}

This schema defines an array where each item is an object with specific properties, and it enforces that these properties are required and no additional properties are allowed [2].

If you're encountering an issue where an array is specified but a string is required, it might be due to a mismatch in how the schema is being interpreted or converted in the configuration interface. This could be related to how the do_http_request method in the ApiTool class handles parsing and validation, or how the ApiBasedToolSchemaParser class processes the OpenAPI specifications [3][4].

To continue talking to Dosu, mention @dosu.