feat: Add cURL command unescaping for API request parsing (#7026)

* feat: Add cURL command unescaping for API request parsing

Enhance APIRequestComponent with a new _unescape_curl method to handle:
- JSON string encoded curl commands
- Double and single escaped quotes
- Robust error handling for curl command parsing

The new method improves flexibility when parsing curl commands with various escape sequences.

* [autofix.ci] apply automated fixes

* refactor: Simplify cURL command unescaping logic in APIRequestComponent

Updated the unescaping logic to improve readability and maintainability. The method now directly attempts to decode JSON strings and handles escaped quotes more efficiently, with enhanced error handling for various exceptions.

* [autofix.ci] apply automated fixes

* [autofix.ci] apply automated fixes

* fix pokedex agent

* Please provide the output of 'git diff --staged' command.

---------

Co-authored-by: Edwin Jose <edwin.jose@datastax.com>
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
Co-authored-by: Ítalo Johnny <italojohnnydosanjos@gmail.com>
Co-authored-by: Cristhian Zanforlin Lousa <cristhian.lousa@gmail.com>
This commit is contained in:
Rodrigo Nader 2025-03-21 09:47:23 -03:00 committed by GitHub
commit 166b0a07da
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 361 additions and 140 deletions

View file

@ -224,6 +224,30 @@ class APIRequestComponent(Component):
"""Check if an item is a valid key-value dictionary."""
return isinstance(item, dict) and "key" in item and "value" in item
def _unescape_curl(self, curl: str) -> str:
"""Unescape a cURL command that might have escaped characters.
This method handles various forms of escaped cURL commands:
1. JSON string encoded curl commands
2. Double escaped quotes
3. Single escaped quotes
"""
if not curl:
return curl
try:
# Handle escaped quotes if present
if '\\"' in curl or "\\'" in curl:
curl = curl.replace('\\"', '"').replace("\\'", "'")
try:
return json.loads(curl)
except json.JSONDecodeError:
# If JSON decoding fails, try to handle escaped quotes
return curl.strip('"')
except (ValueError, AttributeError) as e:
self.log(f"Error unescaping curl command: {e}")
return curl # Return original if unescaping fails
def parse_curl(self, curl: str, build_config: dotdict) -> dotdict:
"""Parse a cURL command and update build configuration.
@ -234,6 +258,9 @@ class APIRequestComponent(Component):
Updated build configuration
"""
try:
# Unescape the curl command if it contains escaped characters
curl = self._unescape_curl(curl)
self.log(f"Unescaped curl command: {curl}") # Log for debugging
parsed = parse_context(curl)
# Update basic configuration

File diff suppressed because one or more lines are too long

View file

@ -9,12 +9,16 @@
"dataType": "File",
"id": "File-Ktatn",
"name": "data",
"output_types": ["Data"]
"output_types": [
"Data"
]
},
"targetHandle": {
"fieldName": "data",
"id": "ParseData-gouVC",
"inputTypes": ["Data"],
"inputTypes": [
"Data"
],
"type": "other"
}
},
@ -33,12 +37,16 @@
"dataType": "ParseData",
"id": "ParseData-gouVC",
"name": "text",
"output_types": ["Message"]
"output_types": [
"Message"
]
},
"targetHandle": {
"fieldName": "text",
"id": "Prompt-epiSD",
"inputTypes": ["Message"],
"inputTypes": [
"Message"
],
"type": "str"
}
},
@ -57,12 +65,16 @@
"dataType": "Prompt",
"id": "Prompt-epiSD",
"name": "prompt",
"output_types": ["Message"]
"output_types": [
"Message"
]
},
"targetHandle": {
"fieldName": "system_message",
"id": "OpenAIModel-ppS3O",
"inputTypes": ["Message"],
"inputTypes": [
"Message"
],
"type": "str"
}
},
@ -81,12 +93,16 @@
"dataType": "OpenAIModel",
"id": "OpenAIModel-ppS3O",
"name": "text_output",
"output_types": ["Message"]
"output_types": [
"Message"
]
},
"targetHandle": {
"fieldName": "summary",
"id": "Prompt-l9XAo",
"inputTypes": ["Message"],
"inputTypes": [
"Message"
],
"type": "str"
}
},
@ -105,12 +121,16 @@
"dataType": "Prompt",
"id": "Prompt-l9XAo",
"name": "prompt",
"output_types": ["Message"]
"output_types": [
"Message"
]
},
"targetHandle": {
"fieldName": "system_message",
"id": "OpenAIModel-DxfrQ",
"inputTypes": ["Message"],
"inputTypes": [
"Message"
],
"type": "str"
}
},
@ -129,12 +149,16 @@
"dataType": "Prompt",
"id": "Prompt-LKleN",
"name": "prompt",
"output_types": ["Message"]
"output_types": [
"Message"
]
},
"targetHandle": {
"fieldName": "system_message",
"id": "OpenAIModel-W1vhv",
"inputTypes": ["Message"],
"inputTypes": [
"Message"
],
"type": "str"
}
},
@ -153,12 +177,16 @@
"dataType": "ParseData",
"id": "ParseData-gouVC",
"name": "text",
"output_types": ["Message"]
"output_types": [
"Message"
]
},
"targetHandle": {
"fieldName": "input_value",
"id": "OpenAIModel-W1vhv",
"inputTypes": ["Message"],
"inputTypes": [
"Message"
],
"type": "str"
}
},
@ -177,12 +205,18 @@
"dataType": "OpenAIModel",
"id": "OpenAIModel-W1vhv",
"name": "text_output",
"output_types": ["Message"]
"output_types": [
"Message"
]
},
"targetHandle": {
"fieldName": "input_value",
"id": "ChatOutput-V5ZFA",
"inputTypes": ["Data", "DataFrame", "Message"],
"inputTypes": [
"Data",
"DataFrame",
"Message"
],
"type": "other"
}
},
@ -201,12 +235,18 @@
"dataType": "OpenAIModel",
"id": "OpenAIModel-DxfrQ",
"name": "text_output",
"output_types": ["Message"]
"output_types": [
"Message"
]
},
"targetHandle": {
"fieldName": "input_value",
"id": "ChatOutput-8y94b",
"inputTypes": ["Data", "DataFrame", "Message"],
"inputTypes": [
"Data",
"DataFrame",
"Message"
],
"type": "other"
}
},
@ -223,7 +263,9 @@
"data": {
"id": "File-Ktatn",
"node": {
"base_classes": ["Data"],
"base_classes": [
"Data"
],
"beta": false,
"category": "data",
"conditional_paths": [],
@ -260,7 +302,9 @@
"required_inputs": [],
"selected": "Data",
"tool_mode": true,
"types": ["Data"],
"types": [
"Data"
],
"value": "__UNDEFINED__"
},
{
@ -272,7 +316,9 @@
"required_inputs": [],
"selected": "DataFrame",
"tool_mode": true,
"types": ["DataFrame"],
"types": [
"DataFrame"
],
"value": "__UNDEFINED__"
},
{
@ -284,7 +330,9 @@
"required_inputs": [],
"selected": "Message",
"tool_mode": true,
"types": ["Message"],
"types": [
"Message"
],
"value": "__UNDEFINED__"
}
],
@ -352,7 +400,10 @@
"display_name": "Server File Path",
"dynamic": false,
"info": "Data object with a 'file_path' property pointing to server file or a Message object with a path to the file. Supercedes 'Path' but supports same file types.",
"input_types": ["Data", "Message"],
"input_types": [
"Data",
"Message"
],
"list": true,
"list_add_label": "Add More",
"name": "file_path",
@ -521,7 +572,10 @@
"data": {
"id": "ParseData-gouVC",
"node": {
"base_classes": ["Data", "Message"],
"base_classes": [
"Data",
"Message"
],
"beta": false,
"conditional_paths": [],
"custom_fields": {},
@ -529,7 +583,11 @@
"display_name": "Data to Message",
"documentation": "",
"edited": false,
"field_order": ["data", "template", "sep"],
"field_order": [
"data",
"template",
"sep"
],
"frozen": false,
"icon": "message-square",
"legacy": false,
@ -548,7 +606,9 @@
"name": "text",
"selected": "Message",
"tool_mode": true,
"types": ["Message"],
"types": [
"Message"
],
"value": "__UNDEFINED__"
},
{
@ -559,7 +619,9 @@
"name": "data_list",
"selected": "Data",
"tool_mode": true,
"types": ["Data"],
"types": [
"Data"
],
"value": "__UNDEFINED__"
}
],
@ -590,7 +652,9 @@
"display_name": "Data",
"dynamic": false,
"info": "The data to convert to text.",
"input_types": ["Data"],
"input_types": [
"Data"
],
"list": true,
"list_add_label": "Add More",
"name": "data",
@ -629,7 +693,9 @@
"display_name": "Template",
"dynamic": false,
"info": "The template to use for formatting the data. It can contain the keys {text}, {data} or any other key in the Data.",
"input_types": ["Message"],
"input_types": [
"Message"
],
"list": false,
"list_add_label": "Add More",
"load_from_db": false,
@ -668,18 +734,25 @@
"data": {
"id": "Prompt-l9XAo",
"node": {
"base_classes": ["Message"],
"base_classes": [
"Message"
],
"beta": false,
"conditional_paths": [],
"custom_fields": {
"template": ["summary"]
"template": [
"summary"
]
},
"description": "Create a prompt template with dynamic variables.",
"display_name": "Prompt",
"documentation": "",
"edited": false,
"error": null,
"field_order": ["template", "tool_placeholder"],
"field_order": [
"template",
"tool_placeholder"
],
"frozen": false,
"full_path": null,
"icon": "prompts",
@ -701,7 +774,9 @@
"name": "prompt",
"selected": "Message",
"tool_mode": true,
"types": ["Message"],
"types": [
"Message"
],
"value": "__UNDEFINED__"
}
],
@ -734,7 +809,9 @@
"fileTypes": [],
"file_path": "",
"info": "",
"input_types": ["Message"],
"input_types": [
"Message"
],
"list": false,
"load_from_db": false,
"multiline": true,
@ -770,7 +847,9 @@
"display_name": "Tool Placeholder",
"dynamic": false,
"info": "A placeholder input for tool mode.",
"input_types": ["Message"],
"input_types": [
"Message"
],
"list": false,
"list_add_label": "Add More",
"load_from_db": false,
@ -808,18 +887,25 @@
"data": {
"id": "Prompt-epiSD",
"node": {
"base_classes": ["Message"],
"base_classes": [
"Message"
],
"beta": false,
"conditional_paths": [],
"custom_fields": {
"template": ["text"]
"template": [
"text"
]
},
"description": "Create a prompt template with dynamic variables.",
"display_name": "Prompt",
"documentation": "",
"edited": false,
"error": null,
"field_order": ["template", "tool_placeholder"],
"field_order": [
"template",
"tool_placeholder"
],
"frozen": false,
"full_path": null,
"icon": "prompts",
@ -841,7 +927,9 @@
"name": "prompt",
"selected": "Message",
"tool_mode": true,
"types": ["Message"],
"types": [
"Message"
],
"value": "__UNDEFINED__"
}
],
@ -892,7 +980,9 @@
"fileTypes": [],
"file_path": "",
"info": "",
"input_types": ["Message"],
"input_types": [
"Message"
],
"list": false,
"load_from_db": false,
"multiline": true,
@ -910,7 +1000,9 @@
"display_name": "Tool Placeholder",
"dynamic": false,
"info": "A placeholder input for tool mode.",
"input_types": ["Message"],
"input_types": [
"Message"
],
"list": false,
"list_add_label": "Add More",
"load_from_db": false,
@ -948,7 +1040,10 @@
"data": {
"id": "OpenAIModel-ppS3O",
"node": {
"base_classes": ["LanguageModel", "Message"],
"base_classes": [
"LanguageModel",
"Message"
],
"beta": false,
"conditional_paths": [],
"custom_fields": {},
@ -988,7 +1083,9 @@
"required_inputs": [],
"selected": "Message",
"tool_mode": true,
"types": ["Message"],
"types": [
"Message"
],
"value": "__UNDEFINED__"
},
{
@ -997,10 +1094,14 @@
"display_name": "Language Model",
"method": "build_model",
"name": "model_output",
"required_inputs": ["api_key"],
"required_inputs": [
"api_key"
],
"selected": "LanguageModel",
"tool_mode": true,
"types": ["LanguageModel"],
"types": [
"LanguageModel"
],
"value": "__UNDEFINED__"
}
],
@ -1013,7 +1114,9 @@
"display_name": "OpenAI API Key",
"dynamic": false,
"info": "The OpenAI API Key to use for the OpenAI model.",
"input_types": ["Message"],
"input_types": [
"Message"
],
"load_from_db": false,
"name": "api_key",
"password": true,
@ -1048,7 +1151,9 @@
"display_name": "Input",
"dynamic": false,
"info": "",
"input_types": ["Message"],
"input_types": [
"Message"
],
"list": false,
"list_add_label": "Add More",
"load_from_db": false,
@ -1230,7 +1335,9 @@
"display_name": "System Message",
"dynamic": false,
"info": "System message to pass to the model.",
"input_types": ["Message"],
"input_types": [
"Message"
],
"list": false,
"list_add_label": "Add More",
"load_from_db": false,
@ -1315,7 +1422,10 @@
"data": {
"id": "OpenAIModel-DxfrQ",
"node": {
"base_classes": ["LanguageModel", "Message"],
"base_classes": [
"LanguageModel",
"Message"
],
"beta": false,
"conditional_paths": [],
"custom_fields": {},
@ -1355,7 +1465,9 @@
"required_inputs": [],
"selected": "Message",
"tool_mode": true,
"types": ["Message"],
"types": [
"Message"
],
"value": "__UNDEFINED__"
},
{
@ -1364,10 +1476,14 @@
"display_name": "Language Model",
"method": "build_model",
"name": "model_output",
"required_inputs": ["api_key"],
"required_inputs": [
"api_key"
],
"selected": "LanguageModel",
"tool_mode": true,
"types": ["LanguageModel"],
"types": [
"LanguageModel"
],
"value": "__UNDEFINED__"
}
],
@ -1380,7 +1496,9 @@
"display_name": "OpenAI API Key",
"dynamic": false,
"info": "The OpenAI API Key to use for the OpenAI model.",
"input_types": ["Message"],
"input_types": [
"Message"
],
"load_from_db": false,
"name": "api_key",
"password": true,
@ -1415,7 +1533,9 @@
"display_name": "Input",
"dynamic": false,
"info": "",
"input_types": ["Message"],
"input_types": [
"Message"
],
"list": false,
"list_add_label": "Add More",
"load_from_db": false,
@ -1597,7 +1717,9 @@
"display_name": "System Message",
"dynamic": false,
"info": "System message to pass to the model.",
"input_types": ["Message"],
"input_types": [
"Message"
],
"list": false,
"list_add_label": "Add More",
"load_from_db": false,
@ -1682,7 +1804,9 @@
"data": {
"id": "Prompt-LKleN",
"node": {
"base_classes": ["Message"],
"base_classes": [
"Message"
],
"beta": false,
"conditional_paths": [],
"custom_fields": {
@ -1693,7 +1817,10 @@
"documentation": "",
"edited": false,
"error": null,
"field_order": ["template", "tool_placeholder"],
"field_order": [
"template",
"tool_placeholder"
],
"frozen": false,
"full_path": null,
"icon": "prompts",
@ -1715,7 +1842,9 @@
"name": "prompt",
"selected": "Message",
"tool_mode": true,
"types": ["Message"],
"types": [
"Message"
],
"value": "__UNDEFINED__"
}
],
@ -1764,7 +1893,9 @@
"display_name": "Tool Placeholder",
"dynamic": false,
"info": "A placeholder input for tool mode.",
"input_types": ["Message"],
"input_types": [
"Message"
],
"list": false,
"list_add_label": "Add More",
"load_from_db": false,
@ -1802,7 +1933,10 @@
"data": {
"id": "OpenAIModel-W1vhv",
"node": {
"base_classes": ["LanguageModel", "Message"],
"base_classes": [
"LanguageModel",
"Message"
],
"beta": false,
"conditional_paths": [],
"custom_fields": {},
@ -1842,7 +1976,9 @@
"required_inputs": [],
"selected": "Message",
"tool_mode": true,
"types": ["Message"],
"types": [
"Message"
],
"value": "__UNDEFINED__"
},
{
@ -1851,10 +1987,14 @@
"display_name": "Language Model",
"method": "build_model",
"name": "model_output",
"required_inputs": ["api_key"],
"required_inputs": [
"api_key"
],
"selected": "LanguageModel",
"tool_mode": true,
"types": ["LanguageModel"],
"types": [
"LanguageModel"
],
"value": "__UNDEFINED__"
}
],
@ -1867,7 +2007,9 @@
"display_name": "OpenAI API Key",
"dynamic": false,
"info": "The OpenAI API Key to use for the OpenAI model.",
"input_types": ["Message"],
"input_types": [
"Message"
],
"load_from_db": false,
"name": "api_key",
"password": true,
@ -1902,7 +2044,9 @@
"display_name": "Input",
"dynamic": false,
"info": "",
"input_types": ["Message"],
"input_types": [
"Message"
],
"list": false,
"list_add_label": "Add More",
"load_from_db": false,
@ -2084,7 +2228,9 @@
"display_name": "System Message",
"dynamic": false,
"info": "System message to pass to the model.",
"input_types": ["Message"],
"input_types": [
"Message"
],
"list": false,
"list_add_label": "Add More",
"load_from_db": false,
@ -2196,7 +2342,9 @@
"data": {
"id": "ChatOutput-V5ZFA",
"node": {
"base_classes": ["Message"],
"base_classes": [
"Message"
],
"beta": false,
"conditional_paths": [],
"custom_fields": {},
@ -2232,7 +2380,9 @@
"name": "message",
"selected": "Message",
"tool_mode": true,
"types": ["Message"],
"types": [
"Message"
],
"value": "__UNDEFINED__"
}
],
@ -2245,7 +2395,9 @@
"display_name": "Background Color",
"dynamic": false,
"info": "The background color of the icon.",
"input_types": ["Message"],
"input_types": [
"Message"
],
"list": false,
"list_add_label": "Add More",
"load_from_db": false,
@ -2266,7 +2418,9 @@
"display_name": "Icon",
"dynamic": false,
"info": "The icon of the message.",
"input_types": ["Message"],
"input_types": [
"Message"
],
"list": false,
"list_add_label": "Add More",
"load_from_db": false,
@ -2323,7 +2477,9 @@
"display_name": "Data Template",
"dynamic": false,
"info": "Template to convert Data to Text. If left empty, it will be dynamically set to the Data's text key.",
"input_types": ["Message"],
"input_types": [
"Message"
],
"list": false,
"list_add_label": "Add More",
"load_from_db": false,
@ -2344,7 +2500,11 @@
"display_name": "Text",
"dynamic": false,
"info": "Message to be passed as output.",
"input_types": ["Data", "DataFrame", "Message"],
"input_types": [
"Data",
"DataFrame",
"Message"
],
"list": false,
"list_add_label": "Add More",
"name": "input_value",
@ -2365,7 +2525,10 @@
"dynamic": false,
"info": "Type of sender.",
"name": "sender",
"options": ["Machine", "User"],
"options": [
"Machine",
"User"
],
"options_metadata": [],
"placeholder": "",
"required": false,
@ -2382,7 +2545,9 @@
"display_name": "Sender Name",
"dynamic": false,
"info": "Name of the sender.",
"input_types": ["Message"],
"input_types": [
"Message"
],
"list": false,
"list_add_label": "Add More",
"load_from_db": false,
@ -2403,7 +2568,9 @@
"display_name": "Session ID",
"dynamic": false,
"info": "The session ID of the chat. If empty, the current session ID parameter will be used.",
"input_types": ["Message"],
"input_types": [
"Message"
],
"list": false,
"list_add_label": "Add More",
"load_from_db": false,
@ -2442,7 +2609,9 @@
"display_name": "Text Color",
"dynamic": false,
"info": "The text color of the name",
"input_types": ["Message"],
"input_types": [
"Message"
],
"list": false,
"list_add_label": "Add More",
"load_from_db": false,
@ -2480,7 +2649,9 @@
"data": {
"id": "ChatOutput-8y94b",
"node": {
"base_classes": ["Message"],
"base_classes": [
"Message"
],
"beta": false,
"conditional_paths": [],
"custom_fields": {},
@ -2516,7 +2687,9 @@
"name": "message",
"selected": "Message",
"tool_mode": true,
"types": ["Message"],
"types": [
"Message"
],
"value": "__UNDEFINED__"
}
],
@ -2529,7 +2702,9 @@
"display_name": "Background Color",
"dynamic": false,
"info": "The background color of the icon.",
"input_types": ["Message"],
"input_types": [
"Message"
],
"list": false,
"list_add_label": "Add More",
"load_from_db": false,
@ -2550,7 +2725,9 @@
"display_name": "Icon",
"dynamic": false,
"info": "The icon of the message.",
"input_types": ["Message"],
"input_types": [
"Message"
],
"list": false,
"list_add_label": "Add More",
"load_from_db": false,
@ -2607,7 +2784,9 @@
"display_name": "Data Template",
"dynamic": false,
"info": "Template to convert Data to Text. If left empty, it will be dynamically set to the Data's text key.",
"input_types": ["Message"],
"input_types": [
"Message"
],
"list": false,
"list_add_label": "Add More",
"load_from_db": false,
@ -2628,7 +2807,11 @@
"display_name": "Text",
"dynamic": false,
"info": "Message to be passed as output.",
"input_types": ["Data", "DataFrame", "Message"],
"input_types": [
"Data",
"DataFrame",
"Message"
],
"list": false,
"list_add_label": "Add More",
"name": "input_value",
@ -2649,7 +2832,10 @@
"dynamic": false,
"info": "Type of sender.",
"name": "sender",
"options": ["Machine", "User"],
"options": [
"Machine",
"User"
],
"options_metadata": [],
"placeholder": "",
"required": false,
@ -2666,7 +2852,9 @@
"display_name": "Sender Name",
"dynamic": false,
"info": "Name of the sender.",
"input_types": ["Message"],
"input_types": [
"Message"
],
"list": false,
"list_add_label": "Add More",
"load_from_db": false,
@ -2687,7 +2875,9 @@
"display_name": "Session ID",
"dynamic": false,
"info": "The session ID of the chat. If empty, the current session ID parameter will be used.",
"input_types": ["Message"],
"input_types": [
"Message"
],
"list": false,
"list_add_label": "Add More",
"load_from_db": false,
@ -2726,7 +2916,9 @@
"display_name": "Text Color",
"dynamic": false,
"info": "The text color of the name",
"input_types": ["Message"],
"input_types": [
"Message"
],
"list": false,
"list_add_label": "Add More",
"load_from_db": false,
@ -2854,5 +3046,7 @@
"is_component": false,
"last_tested_version": "1.2.0",
"name": "Text Sentiment Analysis",
"tags": ["classification"]
}
"tags": [
"classification"
]
}