From 82dcf4a587a18a693ae1fae83cf95be527388cc1 Mon Sep 17 00:00:00 2001 From: NA-Wen Date: Thu, 8 Jan 2026 21:26:00 +0800 Subject: [PATCH 1/4] [fix] support chat interface --- .../node/agent/providers/openai_provider.py | 233 ++++++++++++++++-- runtime/node/executor/agent_executor.py | 1 - 2 files changed, 214 insertions(+), 20 deletions(-) diff --git a/runtime/node/agent/providers/openai_provider.py b/runtime/node/agent/providers/openai_provider.py index b5be52b3..87cb7823 100755 --- a/runtime/node/agent/providers/openai_provider.py +++ b/runtime/node/agent/providers/openai_provider.py @@ -4,7 +4,7 @@ import base64 import binascii import os -from typing import Any, Dict, List, Optional +from typing import Any, Dict, List, Optional, Union from urllib.parse import unquote_to_bytes import openai @@ -46,7 +46,6 @@ class OpenAIProvider(ModelProvider): ) else: return OpenAI( - base_url="https://api.openai.com/v1", api_key=self.api_key, ) @@ -60,26 +59,43 @@ class OpenAIProvider(ModelProvider): ) -> ModelResponse: """ Call the OpenAI model with the given messages and parameters. - - Args: - client: OpenAI client instance - conversation: List of messages in the conversation - tool_specs: Optional tool specifications - **kwargs: Additional parameters for the model call - - Returns: - ModelResponse containing content and potentially tool calls """ + # 1. Determine if we should use Chat Completions directly + is_chat = self._is_chat_completions_mode(client) + + if is_chat: + request_payload = self._build_chat_payload(timeline, tool_specs, kwargs) + response = client.chat.completions.create(**request_payload) + self._track_token_usage(response) + self._append_chat_response_output(timeline, response) + message = self._deserialize_chat_response(response) + return ModelResponse(message=message, raw_response=response) + + # 2. Try Responses API with fallback request_payload = self._build_request_payload(timeline, tool_specs, kwargs) - # print(request_payload) + try: + response = client.responses.create(**request_payload) + self._track_token_usage(response) + self._append_response_output(timeline, response) + message = self._deserialize_response(response) + return ModelResponse(message=message, raw_response=response) + except Exception as e: + new_request_payload = self._build_chat_payload(timeline, tool_specs, kwargs) + response = client.chat.completions.create(**new_request_payload) + self._track_token_usage(response) + self._append_chat_response_output(timeline, response) + message = self._deserialize_chat_response(response) + return ModelResponse(message=message, raw_response=response) - response = client.responses.create(**request_payload) - # print(response) - self._track_token_usage(response) - self._append_response_output(timeline, response) - - message = self._deserialize_response(response) - return ModelResponse(message=message, raw_response=response) + def _is_chat_completions_mode(self, client: Any) -> bool: + """Determine if we should use standard chat completions instead of responses API.""" + protocol = self.params.get("protocol") + if protocol == "chat": + return True + if protocol == "responses": + return False + # Default to Responses API only if it exists on the client + return not hasattr(client, "responses") def extract_token_usage(self, response: Any) -> TokenUsage: """ @@ -208,6 +224,185 @@ class OpenAIProvider(ModelProvider): payload.update(params) return payload + def _build_chat_payload( + self, + timeline: List[Any], + tool_specs: Optional[List[ToolSpec]], + raw_params: Dict[str, Any], + ) -> Dict[str, Any]: + """Construct standard Chat Completions API payload.""" + params = dict(raw_params) + max_output_tokens = params.pop("max_output_tokens", None) + max_tokens = params.pop("max_tokens", None) + if max_tokens is None and max_output_tokens is not None: + max_tokens = max_output_tokens + + messages: List[Any] = [] + for item in timeline: + serialized = self._serialize_timeline_item_for_chat(item) + if serialized is not None: + messages.append(serialized) + + if not messages: + messages = [{"role": "user", "content": ""}] + + payload: Dict[str, Any] = { + "model": self.model_name, + "messages": messages, + "temperature": params.pop("temperature", 0.7), + } + if max_tokens is not None: + payload["max_tokens"] = max_tokens + elif self.params.get("max_tokens"): + payload["max_tokens"] = self.params["max_tokens"] + + user_tools = params.pop("tools", None) + merged_tools: List[Any] = [] + if isinstance(user_tools, list): + merged_tools.extend(user_tools) + + if tool_specs: + for spec in tool_specs: + merged_tools.append({ + "type": "function", + "function": { + "name": spec.name, + "description": spec.description, + "parameters": spec.parameters or {"type": "object", "properties": {}}, + } + }) + + if merged_tools: + payload["tools"] = merged_tools + + tool_choice = params.pop("tool_choice", None) + if tool_choice is not None: + payload["tool_choice"] = tool_choice + elif tool_specs: + payload.setdefault("tool_choice", "auto") + + payload.update(params) + return payload + + def _serialize_timeline_item_for_chat(self, item: Any) -> Optional[Any]: + if isinstance(item, Message): + return self._serialize_message_for_chat(item) + if isinstance(item, FunctionCallOutputEvent): + return self._serialize_function_call_output_event_for_chat(item) + if isinstance(item, dict): + # basic conversion if it looks like a Responses output + role = item.get("role") + content = item.get("content") + tool_calls = item.get("tool_calls") + if role and (content or tool_calls): + return { + "role": role, + "content": self._transform_blocks_for_chat(content) if isinstance(content, list) else content, + "tool_calls": tool_calls + } + return None + + def _serialize_message_for_chat(self, message: Message) -> Dict[str, Any]: + """Convert internal Message to standard Chat Completions schema.""" + role_value = message.role.value + blocks = message.blocks() + if not blocks: + content = message.text_content() + else: + content = self._transform_blocks_for_chat(self._serialize_blocks(blocks, message.role)) + + payload: Dict[str, Any] = { + "role": role_value, + "content": content, + } + if message.name: + payload["name"] = message.name + if message.tool_call_id: + payload["tool_call_id"] = message.tool_call_id + if message.tool_calls: + payload["tool_calls"] = [tc.to_openai_dict() for tc in message.tool_calls] + return payload + + def _serialize_function_call_output_event_for_chat(self, event: FunctionCallOutputEvent) -> Dict[str, Any]: + """Convert tool result to standard Chat Completions schema.""" + text = event.output_text or "" + if event.output_blocks: + # simple concatenation for tool output in chat mode + text = "\n".join(b.describe() for b in event.output_blocks) + + return { + "role": "tool", + "tool_call_id": event.call_id or "tool_call", + "content": text, + } + + def _transform_blocks_for_chat(self, blocks: List[Dict[str, Any]]) -> Union[str, List[Dict[str, Any]]]: + """Convert Responses block types to Chat block types (e.g., input_text -> text).""" + transformed: List[Dict[str, Any]] = [] + for block in blocks: + b_type = block.get("type", "") + if b_type in ("input_text", "output_text"): + transformed.append({"type": "text", "text": block.get("text", "")}) + elif b_type in ("input_image", "output_image"): + transformed.append({"type": "image_url", "image_url": {"url": block.get("image_url", "")}}) + else: + # Keep as is or drop if complex + transformed.append(block) + + # If only one text block, return as string for better compatibility + if len(transformed) == 1 and transformed[0]["type"] == "text": + return transformed[0]["text"] + return transformed + + def _deserialize_chat_response(self, response: Any) -> Message: + """Convert Chat Completions output to internal Message.""" + choices = self._get_attr(response, "choices") or [] + if not choices: + return Message(role=MessageRole.ASSISTANT, content="") + + choice = choices[0] + msg = self._get_attr(choice, "message") + + tool_calls: List[ToolCallPayload] = [] + tc_data = self._get_attr(msg, "tool_calls") + if tc_data: + for tc in tc_data: + f_data = self._get_attr(tc, "function") or {} + tool_calls.append(ToolCallPayload( + id=self._get_attr(tc, "id"), + function_name=self._get_attr(f_data, "name"), + arguments=self._get_attr(f_data, "arguments"), + type="function" + )) + + return Message( + role=MessageRole.ASSISTANT, + content=self._get_attr(msg, "content") or "", + tool_calls=tool_calls + ) + + def _append_chat_response_output(self, timeline: List[Any], response: Any) -> None: + """Add chat response to timeline, preserving tool_calls (Chat API compatible).""" + msg = response.choices[0].message + assistant_msg = { + "role": "assistant", + "content": msg.content or "" + } + + if getattr(msg, "tool_calls", None): + assistant_msg["tool_calls"] = [] + for tc in msg.tool_calls: + assistant_msg["tool_calls"].append({ + "id": tc.id, + "type": "function", + "function": { + "name": tc.function.name, + "arguments": tc.function.arguments, + }, + }) + + timeline.append(assistant_msg) + def _serialize_timeline_item(self, item: Any) -> Optional[Any]: if isinstance(item, Message): return self._serialize_message_for_responses(item) diff --git a/runtime/node/executor/agent_executor.py b/runtime/node/executor/agent_executor.py index 031274e7..e841f8ae 100755 --- a/runtime/node/executor/agent_executor.py +++ b/runtime/node/executor/agent_executor.py @@ -283,7 +283,6 @@ class AgentNodeExecutor(NodeExecutor): self._record_model_call(node, last_input, None, CallStage.BEFORE) response = self._execute_with_retry(node, retry_policy, _call_provider) self.log_manager.debug(response.str_raw_response()) - # print(timeline) self._record_model_call(node, last_input, response, CallStage.AFTER) return response From 7cef1a37260f62971c76d96dc9af65a1e0fdf9b4 Mon Sep 17 00:00:00 2001 From: NA-Wen Date: Thu, 8 Jan 2026 21:26:36 +0800 Subject: [PATCH 2/4] [fix] support chat interface --- yaml_instance/ChatDev_v1.yaml | 18 +++++++++--------- yaml_instance/data_visualization_basic.yaml | 10 +++++----- yaml_instance/net_example.yaml | 8 ++++---- yaml_instance/teach_video.yaml | 20 ++++++++++---------- 4 files changed, 28 insertions(+), 28 deletions(-) diff --git a/yaml_instance/ChatDev_v1.yaml b/yaml_instance/ChatDev_v1.yaml index bbc20491..87dd9f43 100755 --- a/yaml_instance/ChatDev_v1.yaml +++ b/yaml_instance/ChatDev_v1.yaml @@ -38,7 +38,7 @@ graph: - id: Programmer Code Review type: agent config: - name: gpt-4o + name: qwen-plus role: |- ${COMMON_PROMPT} You are Programmer. we are both working at ChatDev. We share a common interest in collaborating to successfully complete a task assigned by a new customer. @@ -71,7 +71,7 @@ graph: - id: Programmer Test Modification type: agent config: - name: gpt-4o + name: qwen-plus role: |- ${COMMON_PROMPT} You are Programmer. we are both working at ChatDev. We share a common interest in collaborating to successfully complete a task assigned by a new customer. @@ -104,7 +104,7 @@ graph: - id: Chief Executive Officer type: agent config: - name: gpt-4o + name: qwen-plus provider: openai role: |- ${COMMON_PROMPT} @@ -166,7 +166,7 @@ graph: - id: Programmer Code Complete type: agent config: - name: gpt-4o + name: qwen-plus provider: openai role: |- ${COMMON_PROMPT} @@ -214,7 +214,7 @@ graph: - id: Programmer Coding type: agent config: - name: gpt-4o + name: qwen-plus provider: openai role: |- ${COMMON_PROMPT} @@ -265,7 +265,7 @@ graph: - id: Chief Product Officer type: agent config: - name: gpt-4o + name: qwen-plus provider: openai role: |- ${COMMON_PROMPT} @@ -323,7 +323,7 @@ graph: - id: Programmer Test Error Summary type: agent config: - name: gpt-4o + name: qwen-plus provider: openai role: |- ${COMMON_PROMPT} @@ -360,7 +360,7 @@ graph: - id: Code Reviewer type: agent config: - name: gpt-4o + name: qwen-plus provider: openai role: |- ${COMMON_PROMPT} @@ -458,7 +458,7 @@ graph: - id: Software Test Engineer type: agent config: - name: gpt-4o + name: qwen-plus provider: openai role: |- ${COMMON_PROMPT} diff --git a/yaml_instance/data_visualization_basic.yaml b/yaml_instance/data_visualization_basic.yaml index 545f8951..0cf413fd 100644 --- a/yaml_instance/data_visualization_basic.yaml +++ b/yaml_instance/data_visualization_basic.yaml @@ -11,7 +11,7 @@ graph: context_window: -1 config: provider: openai - name: gpt-4o + name: qwen-plus base_url: ${BASE_URL} api_key: ${API_KEY} role: |- @@ -42,7 +42,7 @@ graph: context_window: -1 config: provider: openai - name: gpt-4o + name: qwen-plus base_url: ${BASE_URL} api_key: ${API_KEY} role: |- @@ -75,7 +75,7 @@ graph: context_window: -1 config: provider: openai - name: gpt-4o + name: qwen-plus base_url: ${BASE_URL} api_key: ${API_KEY} role: |- @@ -112,7 +112,7 @@ graph: context_window: 5 config: provider: openai - name: gpt-4o + name: qwen-plus base_url: ${BASE_URL} api_key: ${API_KEY} role: |- @@ -148,7 +148,7 @@ graph: context_window: 5 config: provider: openai - name: gpt-4o + name: qwen-plus base_url: ${BASE_URL} api_key: ${API_KEY} role: |- diff --git a/yaml_instance/net_example.yaml b/yaml_instance/net_example.yaml index e0bc25dc..d4e33d57 100755 --- a/yaml_instance/net_example.yaml +++ b/yaml_instance/net_example.yaml @@ -19,7 +19,7 @@ graph: base_url: ${BASE_URL} api_key: ${API_KEY} input_mode: messages - name: gpt-4o + name: qwen-plus role: | 你是一位作家,擅长根据用户输入的一个词句生成一整篇文章。 用户会输入一个词语或一个短句,你需要据此生成一篇不少于 2000 字的文章,要求含有多个段落。 @@ -33,7 +33,7 @@ graph: base_url: ${BASE_URL} api_key: ${API_KEY} input_mode: messages - name: gpt-4o + name: qwen-plus role: | 你是一位编辑,请你根据输入的文章与诗词,进行结合,文章最后应当附上诗词。 params: @@ -48,7 +48,7 @@ graph: - id: Editor 2 type: agent config: - name: gpt-4o + name: qwen-plus provider: openai role: | 你是一位编辑,擅长对文章进行整合和润色。 @@ -67,7 +67,7 @@ graph: - id: Poet type: agent config: - name: gpt-4o + name: qwen-plus provider: openai role: | 你是一位诗人,擅长根据用户输入的一个词句生成一首古体诗。 diff --git a/yaml_instance/teach_video.yaml b/yaml_instance/teach_video.yaml index 9ae3e773..7dc02e6a 100755 --- a/yaml_instance/teach_video.yaml +++ b/yaml_instance/teach_video.yaml @@ -16,8 +16,8 @@ graph: - id: Video Concat type: agent config: - name: gemini-3-flash-preview - provider: gemini + name: qwen-plus + provider: open ai role: 请先调用 describe_available_files,检查当前目录中的.mp4文件的路径;不同mp4文件的名称代表了他们的内容,请你根据他们的名称排序,并调用concat_videos工具对其进行拼接。注意,concat_videos工具需要的参数是排好序的绝对路径构成的列表 base_url: ${BASE_URL} api_key: ${API_KEY} @@ -38,8 +38,8 @@ graph: - id: Content Composer type: agent config: - name: gemini-3-flash-preview - provider: gemini + name: qwen-plus + provider: openai role: |- 你是一名严谨的课程内容助教,请对你收到的内容生成一份教学大纲。 @@ -59,8 +59,8 @@ graph: - id: Code Generator type: agent config: - name: gemini-3-flash-preview - provider: gemini + name: qwen-plus + provider: openai role: |- 你是一名 **Manim 动画生成 Agent**,具备自动规划、代码生成与执行能力。 你将接收一段题目信息(Markdown 格式),以及该内容在整套课程中的上下文位置信息。 @@ -152,8 +152,8 @@ graph: - id: Concluder type: agent config: - name: gemini-3-flash-preview - provider: gemini + name: qwen-plus + provider: openai role: |- 请先调用 describe_available_files,检查当前目录中的.py脚本文件的路径;之后直接使用render_manim工具进行渲染,此工具的参数只需要{script_path}(脚本路径(绝对路径));如果有多个py文件,则需要对每个py文件均运行render_manim工具进行渲染 如果你在render_manim中发现出现问题,请你将具体的报错输出,同时输出“ERROR” @@ -176,8 +176,8 @@ graph: - id: Paginator type: agent config: - name: gemini-3-flash-preview - provider: gemini + name: qwen-plus + provider: openai role: |- 你是一位专业的文档格式处理专家,擅长为教学文档添加合适的分页标记。 From 5e959cc1f577bb662596d53d7a5437f6d3d32c0d Mon Sep 17 00:00:00 2001 From: NA-Wen Date: Thu, 8 Jan 2026 21:30:06 +0800 Subject: [PATCH 3/4] [fix] support chat interface --- yaml_instance/ChatDev_v1.yaml | 18 +++++++++--------- yaml_instance/data_visualization_basic.yaml | 10 +++++----- yaml_instance/net_example.yaml | 8 ++++---- yaml_instance/teach_video.yaml | 20 ++++++++++---------- 4 files changed, 28 insertions(+), 28 deletions(-) diff --git a/yaml_instance/ChatDev_v1.yaml b/yaml_instance/ChatDev_v1.yaml index 87dd9f43..bbc20491 100755 --- a/yaml_instance/ChatDev_v1.yaml +++ b/yaml_instance/ChatDev_v1.yaml @@ -38,7 +38,7 @@ graph: - id: Programmer Code Review type: agent config: - name: qwen-plus + name: gpt-4o role: |- ${COMMON_PROMPT} You are Programmer. we are both working at ChatDev. We share a common interest in collaborating to successfully complete a task assigned by a new customer. @@ -71,7 +71,7 @@ graph: - id: Programmer Test Modification type: agent config: - name: qwen-plus + name: gpt-4o role: |- ${COMMON_PROMPT} You are Programmer. we are both working at ChatDev. We share a common interest in collaborating to successfully complete a task assigned by a new customer. @@ -104,7 +104,7 @@ graph: - id: Chief Executive Officer type: agent config: - name: qwen-plus + name: gpt-4o provider: openai role: |- ${COMMON_PROMPT} @@ -166,7 +166,7 @@ graph: - id: Programmer Code Complete type: agent config: - name: qwen-plus + name: gpt-4o provider: openai role: |- ${COMMON_PROMPT} @@ -214,7 +214,7 @@ graph: - id: Programmer Coding type: agent config: - name: qwen-plus + name: gpt-4o provider: openai role: |- ${COMMON_PROMPT} @@ -265,7 +265,7 @@ graph: - id: Chief Product Officer type: agent config: - name: qwen-plus + name: gpt-4o provider: openai role: |- ${COMMON_PROMPT} @@ -323,7 +323,7 @@ graph: - id: Programmer Test Error Summary type: agent config: - name: qwen-plus + name: gpt-4o provider: openai role: |- ${COMMON_PROMPT} @@ -360,7 +360,7 @@ graph: - id: Code Reviewer type: agent config: - name: qwen-plus + name: gpt-4o provider: openai role: |- ${COMMON_PROMPT} @@ -458,7 +458,7 @@ graph: - id: Software Test Engineer type: agent config: - name: qwen-plus + name: gpt-4o provider: openai role: |- ${COMMON_PROMPT} diff --git a/yaml_instance/data_visualization_basic.yaml b/yaml_instance/data_visualization_basic.yaml index 0cf413fd..545f8951 100644 --- a/yaml_instance/data_visualization_basic.yaml +++ b/yaml_instance/data_visualization_basic.yaml @@ -11,7 +11,7 @@ graph: context_window: -1 config: provider: openai - name: qwen-plus + name: gpt-4o base_url: ${BASE_URL} api_key: ${API_KEY} role: |- @@ -42,7 +42,7 @@ graph: context_window: -1 config: provider: openai - name: qwen-plus + name: gpt-4o base_url: ${BASE_URL} api_key: ${API_KEY} role: |- @@ -75,7 +75,7 @@ graph: context_window: -1 config: provider: openai - name: qwen-plus + name: gpt-4o base_url: ${BASE_URL} api_key: ${API_KEY} role: |- @@ -112,7 +112,7 @@ graph: context_window: 5 config: provider: openai - name: qwen-plus + name: gpt-4o base_url: ${BASE_URL} api_key: ${API_KEY} role: |- @@ -148,7 +148,7 @@ graph: context_window: 5 config: provider: openai - name: qwen-plus + name: gpt-4o base_url: ${BASE_URL} api_key: ${API_KEY} role: |- diff --git a/yaml_instance/net_example.yaml b/yaml_instance/net_example.yaml index d4e33d57..e0bc25dc 100755 --- a/yaml_instance/net_example.yaml +++ b/yaml_instance/net_example.yaml @@ -19,7 +19,7 @@ graph: base_url: ${BASE_URL} api_key: ${API_KEY} input_mode: messages - name: qwen-plus + name: gpt-4o role: | 你是一位作家,擅长根据用户输入的一个词句生成一整篇文章。 用户会输入一个词语或一个短句,你需要据此生成一篇不少于 2000 字的文章,要求含有多个段落。 @@ -33,7 +33,7 @@ graph: base_url: ${BASE_URL} api_key: ${API_KEY} input_mode: messages - name: qwen-plus + name: gpt-4o role: | 你是一位编辑,请你根据输入的文章与诗词,进行结合,文章最后应当附上诗词。 params: @@ -48,7 +48,7 @@ graph: - id: Editor 2 type: agent config: - name: qwen-plus + name: gpt-4o provider: openai role: | 你是一位编辑,擅长对文章进行整合和润色。 @@ -67,7 +67,7 @@ graph: - id: Poet type: agent config: - name: qwen-plus + name: gpt-4o provider: openai role: | 你是一位诗人,擅长根据用户输入的一个词句生成一首古体诗。 diff --git a/yaml_instance/teach_video.yaml b/yaml_instance/teach_video.yaml index 7dc02e6a..eda4c688 100755 --- a/yaml_instance/teach_video.yaml +++ b/yaml_instance/teach_video.yaml @@ -16,8 +16,8 @@ graph: - id: Video Concat type: agent config: - name: qwen-plus - provider: open ai + name: gemini-3-flash + provider: gemini role: 请先调用 describe_available_files,检查当前目录中的.mp4文件的路径;不同mp4文件的名称代表了他们的内容,请你根据他们的名称排序,并调用concat_videos工具对其进行拼接。注意,concat_videos工具需要的参数是排好序的绝对路径构成的列表 base_url: ${BASE_URL} api_key: ${API_KEY} @@ -38,8 +38,8 @@ graph: - id: Content Composer type: agent config: - name: qwen-plus - provider: openai + name: gemini-3-flash + provider: gemini role: |- 你是一名严谨的课程内容助教,请对你收到的内容生成一份教学大纲。 @@ -59,8 +59,8 @@ graph: - id: Code Generator type: agent config: - name: qwen-plus - provider: openai + name: gemini-3-flash + provider: gemini role: |- 你是一名 **Manim 动画生成 Agent**,具备自动规划、代码生成与执行能力。 你将接收一段题目信息(Markdown 格式),以及该内容在整套课程中的上下文位置信息。 @@ -152,8 +152,8 @@ graph: - id: Concluder type: agent config: - name: qwen-plus - provider: openai + name: gemini-3-flash + provider: gemini role: |- 请先调用 describe_available_files,检查当前目录中的.py脚本文件的路径;之后直接使用render_manim工具进行渲染,此工具的参数只需要{script_path}(脚本路径(绝对路径));如果有多个py文件,则需要对每个py文件均运行render_manim工具进行渲染 如果你在render_manim中发现出现问题,请你将具体的报错输出,同时输出“ERROR” @@ -176,8 +176,8 @@ graph: - id: Paginator type: agent config: - name: qwen-plus - provider: openai + name: gemini-3-flash + provider: gemini role: |- 你是一位专业的文档格式处理专家,擅长为教学文档添加合适的分页标记。 From 29cd12a0acc11c04fc9d6d4188e6904d61ce8692 Mon Sep 17 00:00:00 2001 From: NA-Wen Date: Thu, 8 Jan 2026 21:30:51 +0800 Subject: [PATCH 4/4] [fix] support chat interface --- yaml_instance/teach_video.yaml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/yaml_instance/teach_video.yaml b/yaml_instance/teach_video.yaml index eda4c688..9ae3e773 100755 --- a/yaml_instance/teach_video.yaml +++ b/yaml_instance/teach_video.yaml @@ -16,7 +16,7 @@ graph: - id: Video Concat type: agent config: - name: gemini-3-flash + name: gemini-3-flash-preview provider: gemini role: 请先调用 describe_available_files,检查当前目录中的.mp4文件的路径;不同mp4文件的名称代表了他们的内容,请你根据他们的名称排序,并调用concat_videos工具对其进行拼接。注意,concat_videos工具需要的参数是排好序的绝对路径构成的列表 base_url: ${BASE_URL} @@ -38,7 +38,7 @@ graph: - id: Content Composer type: agent config: - name: gemini-3-flash + name: gemini-3-flash-preview provider: gemini role: |- 你是一名严谨的课程内容助教,请对你收到的内容生成一份教学大纲。 @@ -59,7 +59,7 @@ graph: - id: Code Generator type: agent config: - name: gemini-3-flash + name: gemini-3-flash-preview provider: gemini role: |- 你是一名 **Manim 动画生成 Agent**,具备自动规划、代码生成与执行能力。 @@ -152,7 +152,7 @@ graph: - id: Concluder type: agent config: - name: gemini-3-flash + name: gemini-3-flash-preview provider: gemini role: |- 请先调用 describe_available_files,检查当前目录中的.py脚本文件的路径;之后直接使用render_manim工具进行渲染,此工具的参数只需要{script_path}(脚本路径(绝对路径));如果有多个py文件,则需要对每个py文件均运行render_manim工具进行渲染 @@ -176,7 +176,7 @@ graph: - id: Paginator type: agent config: - name: gemini-3-flash + name: gemini-3-flash-preview provider: gemini role: |- 你是一位专业的文档格式处理专家,擅长为教学文档添加合适的分页标记。