diff --git a/extensions/python/system_prompt/_11_tools_prompt.py b/extensions/python/system_prompt/_11_tools_prompt.py index 6349a862c5..bb6de55e69 100644 --- a/extensions/python/system_prompt/_11_tools_prompt.py +++ b/extensions/python/system_prompt/_11_tools_prompt.py @@ -51,10 +51,13 @@ async def build_prompt(agent: Agent) -> str: prompt = agent.read_prompt("agent.system.tools.md", tools=tools_str) # vision support - from plugins._model_config.helpers.model_config import get_chat_model_config + from plugins._model_config.helpers.model_config import ( + get_chat_model_config, + get_vision_model_config, + ) chat_cfg = get_chat_model_config(agent) - if chat_cfg.get("vision", False): + if get_vision_model_config(agent) or chat_cfg.get("vision", False): prompt += "\n\n" + agent.read_prompt("agent.system.tools_vision.md") return prompt diff --git a/helpers/parallel_tools.py b/helpers/parallel_tools.py index 9e9a4cbc14..dbc79ef9f6 100644 --- a/helpers/parallel_tools.py +++ b/helpers/parallel_tools.py @@ -477,10 +477,15 @@ async def _run_direct_tool_job(parent_context_id: str, job: ParallelJob) -> str: worker_context.set_data(PARALLEL_WORKER_PARENT_CONTEXT_KEY, parent_context_id) worker_context.set_data(PARALLEL_WORKER_JOB_KEY, job.id) worker_context.set_data(PARALLEL_WORKER_KIND_KEY, job.kind) + worker_context.set_data( + "chat_model_override", + parent_context.get_data("chat_model_override"), + ) job.worker_context_id = worker_context.id _copy_project(parent_context, worker_context) worker_agent = worker_context.agent0 + worker_agent.last_user_message = parent_context.agent0.last_user_message worker_agent.loop_data = LoopData() return await execute_tool_call( worker_agent, diff --git a/helpers/parallel_tools.py.dox.md b/helpers/parallel_tools.py.dox.md index a015553daa..9fb3f6b5f5 100644 --- a/helpers/parallel_tools.py.dox.md +++ b/helpers/parallel_tools.py.dox.md @@ -32,6 +32,7 @@ - Subordinate child chats are tagged with job metadata, remain outside the scheduler task list, and may use normal child-chat tools including `parallel`. - Nested parallel jobs started by a parallel subordinate are registered as child `DeferredTask` instances so stopping the ancestor also stops its descendants. - Direct tool jobs run in isolated background contexts and are blocked from recursively invoking `parallel`. +- Direct tool jobs inherit the parent's active per-chat model override and current user message. - Direct tool background context cleanup removes both the in-memory context and any transient chat folder left on disk. - Parent-visible child log items are created for each wrapped call so the WebUI can inspect concurrent children separately while the wrapper result remains model-history-only. - Child tool logs mirror normal tool-call visible args; job ids remain available through wrapper results and prompt extras rather than visible process-step args. diff --git a/helpers/responses_tools.py b/helpers/responses_tools.py index 93778d652b..ffe570773f 100644 --- a/helpers/responses_tools.py +++ b/helpers/responses_tools.py @@ -114,9 +114,15 @@ def _local_tool_prompts(agent: Any) -> list[tuple[str, str]]: def _vision_tool_prompt(agent: Any) -> str: try: - from plugins._model_config.helpers.model_config import get_chat_model_config + from plugins._model_config.helpers.model_config import ( + get_chat_model_config, + get_vision_model_config, + ) - if not get_chat_model_config(agent).get("vision", False): + if not ( + get_vision_model_config(agent) + or get_chat_model_config(agent).get("vision", False) + ): return "" return agent.read_prompt("agent.system.tools_vision.md") except Exception: diff --git a/helpers/responses_tools.py.dox.md b/helpers/responses_tools.py.dox.md index 7c2631867a..3a7edc4aa5 100644 --- a/helpers/responses_tools.py.dox.md +++ b/helpers/responses_tools.py.dox.md @@ -12,7 +12,7 @@ ## Local Contracts -- Build local function tools from enabled `agent.system.tool.*.md` prompt files and include `vision_load` only when the active chat model enables the matching vision prompt. +- Build local function tools from enabled `agent.system.tool.*.md` prompt files and include `vision_load` when either Main native vision or the effective preset's Vision Model enables the canonical vision prompt. - Discover local prompt files through `helpers.subagents.get_paths`; this module owns the Responses-specific prompt-name compatibility rules. - Local prompt-derived function names use existing bullet declarations that pair a backticked name with `arg` or `args` for multi-tool prompt files, otherwise prefer explicit `"tool_name"` examples, then the first prompt heading, and finally the prompt filename. @@ -25,8 +25,8 @@ - Preserve original Agent Zero tool names through the native Responses name map. - Keep MCP tool schemas merged after local prompt-derived tools. - Apply `helpers.tool_policy` before emitting local or MCP schemas; a blocked - capability is absent from provider-native tool definitions. Vision remains - controlled solely by the active chat model configuration. + capability is absent from provider-native tool definitions. Vision routing + is controlled by the effective model preset rather than Agent Editor. - Connector remote tools are advertised only when `_a0_connector` runtime metadata says the matching connected CLI capability is currently available. ## Work Guidance diff --git a/plugins/_model_config/AGENTS.md b/plugins/_model_config/AGENTS.md index f3ba7d5297..f6350ea11b 100644 --- a/plugins/_model_config/AGENTS.md +++ b/plugins/_model_config/AGENTS.md @@ -14,7 +14,7 @@ ## Local Contracts -- `Default` is the first global preset and cannot be deleted or renamed. It owns the complete main, utility, and embedding baseline. +- `Default` is the first global preset and cannot be deleted or renamed. It owns the complete main, utility, and embedding baseline; its Vision Model slot is optional. - Preset definitions are global. Global, project, agent-profile, and project/profile plugin configs persist only `model_preset`; chats may persist a preset reference as their explicit override. - Preserve scoped plugin resolution order and fall back invalid or missing scope/chat references to `Default`. - Project Settings `llm` payloads are owned here through the generic `helpers.projects` project extension-data hooks; keep project helper code agnostic to `_model_config` paths, presets, and inheritance rules. @@ -22,7 +22,12 @@ - Check API-key readiness only for the effective model configuration; unused global presets must not produce Welcome-screen warnings. - Coordinate OAuth-backed providers with `_oauth` instead of hardcoding provider-specific auth here. - `model_config_get` exposes `model_configured` as a derived chat-model readiness flag from provider, model name, and API-key availability. -- Non-default presets may inherit omitted slots or durable tuning from `Default`, but must replace or clear per-slot `kwargs` so provider-specific extra params never leak across model providers. +- Non-default presets may inherit omitted main, utility, or embedding slots and durable tuning from `Default`, but must replace or clear per-slot `kwargs` so provider-specific extra params never leak across model providers. +- The optional `vision` slot is strictly per preset and never inherited from `Default`; an empty slot disables the separate Vision Model for that preset. +- Main native vision wins by default. A configured Vision Model handles `vision_load` when Main lacks vision, or when that preset explicitly enables `override_main`. +- Keep the optional Vision provider/model selector inside the Main Model card and flush with Main's field alignment, without a nested left inset. Show it only while Main vision is disabled or `override_main` is enabled; do not render a standalone Vision Model card. +- Show `Use separate Vision Model` immediately below `Supports Vision` while Main vision is enabled, not inside Advanced Settings; describe the disabled state as using Main's native vision. +- In model overviews, render the effective Vision Model as a text-only `Vision override / Provider / Model` child aligned with Main's provider column, not as an icon-bearing peer row. - Changing a model provider in the settings UI must clear `api_base` and `kwargs` because both may be provider-specific. - Repair provider-specific model-config aliases at the model-config read/build boundary; keep provider-specific repairs out of provider-agnostic core wrappers such as `models.py`. - `modelConfig.createPresetEditor()` owns local preset drafts, row actions, and stable UI-only row keys so deletion or renaming cannot rebind nested model fields. diff --git a/plugins/_model_config/extensions/webui/chat-input-progress-start/model-switcher.html b/plugins/_model_config/extensions/webui/chat-input-progress-start/model-switcher.html index 460bdfe727..0940d547f4 100644 --- a/plugins/_model_config/extensions/webui/chat-input-progress-start/model-switcher.html +++ b/plugins/_model_config/extensions/webui/chat-input-progress-start/model-switcher.html @@ -65,6 +65,16 @@ + + + -