From c59ae4c7c22b67df54dcb3400816f2e760c96d6d Mon Sep 17 00:00:00 2001 From: eviaaaaa <2278596667@qq.com> Date: Thu, 29 Jan 2026 19:22:35 +0800 Subject: [PATCH] Fix: codeExec return types & error handling; Update Spark model mappings (#12896) ## What problem does this PR solve? This PR addresses three specific issues to improve agent reliability and model support: 1. **`codeExec` Output Limitation**: Previously, the `codeExec` tool was strictly limited to returning `string` types. I updated the output constraint to `object` to support structured data (Dicts, Lists, etc.) required for complex downstream tasks. 2. **`codeExec` Error Handling**: Improved the execution logic so that when runtime errors occur, the tool captures the exception and returns the error message as the output instead of causing the process to abort or fail silently. 3. **Spark Model Configuration**: - Added support for the `MAX-32k` model variant. - Fixed the `Spark-Lite` mapping from `general` to `lite` to match the latest API specifications. ## Type of change - [x] Bug Fix (fixes execution logic and model mapping) - [x] New Feature / Enhancement (adds model support and improves tool flexibility) ## Key Changes ### `agent/tools/code_exec.py` - Changed the output type definition from `string` to `object`. - Refactored the execution flow to gracefully catch exceptions and return error messages as part of the tool output. ### `rag/llm/chat_model.py` - Added `"Spark-Max-32K": "max-32k"` to the model list. - Updated `"Spark-Lite"` value from `"general"` to `"lite"`. ## Checklist - [x] My code follows the style guidelines of this project. - [x] I have performed a self-review of my own code. Signed-off-by: evilhero <2278596667@qq.com> --- agent/tools/code_exec.py | 19 ++++++++++++------- rag/llm/chat_model.py | 3 ++- 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/agent/tools/code_exec.py b/agent/tools/code_exec.py index 10bc772f7..bc42415e0 100644 --- a/agent/tools/code_exec.py +++ b/agent/tools/code_exec.py @@ -110,7 +110,7 @@ module.exports = { main }; self.lang = Language.PYTHON.value self.script = 'def main(arg1: str, arg2: str) -> dict: return {"result": arg1 + arg2}' self.arguments = {} - self.outputs = {"result": {"value": "", "type": "string"}} + self.outputs = {"result": {"value": "", "type": "object"}} def check(self): self.check_valid_value(self.lang, "Support languages", ["python", "python3", "nodejs", "javascript"]) @@ -140,13 +140,13 @@ class CodeExec(ToolBase, ABC): continue arguments[k] = self._canvas.get_variable_value(v) if v else None - self._execute_code(language=lang, code=script, arguments=arguments) + return self._execute_code(language=lang, code=script, arguments=arguments) def _execute_code(self, language: str, code: str, arguments: dict): import requests if self.check_if_canceled("CodeExec execution"): - return + return self.output() try: # Try using the new sandbox provider system first @@ -186,13 +186,15 @@ class CodeExec(ToolBase, ABC): code_req = CodeExecutionRequest(code_b64=code_b64, language=language, arguments=arguments).model_dump() except Exception as e: if self.check_if_canceled("CodeExec execution"): - return + return self.output() self.set_output("_ERROR", "construct code request error: " + str(e)) + return self.output() try: if self.check_if_canceled("CodeExec execution"): - return "Task has been canceled" + self.set_output("_ERROR", "Task has been canceled") + return self.output() resp = requests.post(url=f"http://{settings.SANDBOX_HOST}:9385/run", json=code_req, timeout=int(os.environ.get("COMPONENT_EXEC_TIMEOUT", 10 * 60))) logging.info(f"http://{settings.SANDBOX_HOST}:9385/run, code_req: {code_req}, resp.status_code {resp.status_code}:") @@ -207,17 +209,18 @@ class CodeExec(ToolBase, ABC): stderr = body.get("stderr") if stderr: self.set_output("_ERROR", stderr) - return + return self.output() raw_stdout = body.get("stdout", "") parsed_stdout = self._deserialize_stdout(raw_stdout) logging.info(f"[CodeExec]: http://{settings.SANDBOX_HOST}:9385/run -> {parsed_stdout}") self._populate_outputs(parsed_stdout, raw_stdout) else: self.set_output("_ERROR", "There is no response from sandbox") + return self.output() except Exception as e: if self.check_if_canceled("CodeExec execution"): - return + return self.output() self.set_output("_ERROR", "Exception executing code: " + str(e)) @@ -328,6 +331,8 @@ class CodeExec(ToolBase, ABC): if key.startswith("_"): continue val = self._get_by_path(parsed_stdout, key) + if val is None and len(outputs_items) == 1: + val = parsed_stdout coerced = self._coerce_output_value(val, meta.get("type")) logging.info(f"[CodeExec]: populate dict key='{key}' raw='{val}' coerced='{coerced}'") self.set_output(key, coerced) diff --git a/rag/llm/chat_model.py b/rag/llm/chat_model.py index 2eb8ec4fa..3e8e91830 100644 --- a/rag/llm/chat_model.py +++ b/rag/llm/chat_model.py @@ -799,7 +799,8 @@ class SparkChat(Base): base_url = "https://spark-api-open.xf-yun.com/v1" model2version = { "Spark-Max": "generalv3.5", - "Spark-Lite": "general", + "Spark-Max-32K": "max-32k", + "Spark-Lite": "lite", "Spark-Pro": "generalv3", "Spark-Pro-128K": "pro-128k", "Spark-4.0-Ultra": "4.0Ultra",