diff --git a/docs/image-generation.md b/docs/image-generation.md index a7d0f2b4..79ac87f8 100644 --- a/docs/image-generation.md +++ b/docs/image-generation.md @@ -1,6 +1,6 @@ # Image Generation -nanobot can generate and edit images through the `generate_image` tool. In the WebUI, users can enable **Image Generation** from the composer, choose an aspect ratio, and keep iterating on generated images inside the same chat. +nanobot can generate and edit images through the `generate_image` tool. Enable the tool in WebUI Settings, then ask for an image normally in chat; the agent decides when to call it and can keep iterating on generated images in the same conversation. The feature is disabled by default. Enable it in `~/.nanobot/config.json`, configure a supported image provider, then restart the gateway. @@ -32,11 +32,9 @@ See [Provider Notes](#provider-notes) for Custom, AIHubMix, MiniMax, Gemini, Oll ## WebUI Usage -In the WebUI composer: - -1. Click **Image Generation**. -2. Choose an aspect ratio: `Auto`, `1:1`, `3:4`, `9:16`, `4:3`, or `16:9`. -3. Describe the image or the edit you want. +1. Open Settings and enable **Image Generation** with a configured provider and model. +2. Describe the image or edit you want in chat. +3. Include an aspect ratio or size in the request when the configured defaults are not suitable. 4. Attach reference images when editing an existing image. Generated images are rendered as assistant media in the chat. Follow-up prompts such as "make it warmer", "change the background", or "try a 16:9 version" can reuse the most recent generated artifact. diff --git a/nanobot/agent/tools/mcp.py b/nanobot/agent/tools/mcp.py index a6d65e69..7919b9ad 100644 --- a/nanobot/agent/tools/mcp.py +++ b/nanobot/agent/tools/mcp.py @@ -1121,63 +1121,6 @@ def session_extra(metadata: Mapping[str, Any] | None) -> dict[str, Any]: return {"mcp_presets": mcp_presets} if isinstance(mcp_presets, list) and mcp_presets else {} -def runtime_lines( - message: Any, - *, - available_server_names: set[str] | None = None, - configured_server_names: set[str] | None = None, - connected_server_names: set[str] | None = None, - skip: bool = False, -) -> list[str]: - """Return model-visible MCP preset annotations for the current turn.""" - if skip: - return [] - if configured_server_names is None: - configured_server_names = available_server_names - if connected_server_names is None: - connected_server_names = available_server_names - metadata = message.metadata if isinstance(getattr(message, "metadata", None), Mapping) else None - structured = metadata.get("mcp_presets") if isinstance(metadata, Mapping) else None - if not isinstance(structured, list): - return [] - - lines: list[str] = [] - for item in structured[:8]: - if not isinstance(item, Mapping): - continue - raw_name = str(item.get("name") or "").strip().lower() - if not raw_name: - continue - display = str(item.get("display_name") or raw_name).strip() or raw_name - transport = str(item.get("transport") or "mcp").strip() or "mcp" - prefix = f"mcp_{raw_name}_" - if configured_server_names is not None and raw_name not in configured_server_names: - lines.append( - "MCP Preset Attachment: " - f"@{raw_name} ({display}; transport={transport}) is configured in WebUI Settings, " - "but this gateway has not loaded the latest MCP settings yet. " - f"Tools with prefix `{prefix}` may not be available yet; if they are missing, " - "tell the user to restart nanobot." - ) - continue - if connected_server_names is not None and raw_name not in connected_server_names: - lines.append( - "MCP Preset Attachment: " - f"@{raw_name} ({display}; transport={transport}) is configured, " - "but its MCP connection is not currently live. " - f"Tools with prefix `{prefix}` may be unavailable; tell the user to open Settings, " - "run the preset test, and restart nanobot only if hot reload is unavailable." - ) - continue - lines.append( - "MCP Preset Attachment: " - f"@{raw_name} ({display}; transport={transport}; tool_prefix={prefix}). " - f"Prefer available tools whose names start with `{prefix}` for this request; " - "do not substitute shell commands for this MCP integration unless the user asks." - ) - return lines - - async def connect_missing_servers(state: Any, registry: ToolRegistry) -> None: """Connect configured MCP servers that are not currently live.""" async with _reload_lock(state): diff --git a/nanobot/webui/mcp_presets_runtime.py b/nanobot/webui/mcp_presets_runtime.py index 1294ccc8..0ebffd1f 100644 --- a/nanobot/webui/mcp_presets_runtime.py +++ b/nanobot/webui/mcp_presets_runtime.py @@ -1,5 +1,5 @@ -"""Compatibility exports for WebUI-attached MCP preset annotations.""" +"""Compatibility export for persisted WebUI MCP preset metadata.""" -from nanobot.agent.tools.mcp import runtime_lines, session_extra +from nanobot.agent.tools.mcp import session_extra -__all__ = ["runtime_lines", "session_extra"] +__all__ = ["session_extra"] diff --git a/tests/webui/test_mcp_presets_runtime.py b/tests/webui/test_mcp_presets_runtime.py index 6abef66f..2b75e39e 100644 --- a/tests/webui/test_mcp_presets_runtime.py +++ b/tests/webui/test_mcp_presets_runtime.py @@ -1,78 +1,8 @@ from __future__ import annotations -from types import SimpleNamespace - from nanobot.webui import mcp_presets_runtime -def test_mcp_preset_runtime_lines_describe_tool_prefix() -> None: - msg = SimpleNamespace( - content="use @browserbase", - metadata={ - "mcp_presets": [{ - "name": "browserbase", - "display_name": "Browserbase", - "transport": "streamableHttp", - }], - }, - ) - - lines = mcp_presets_runtime.runtime_lines( - msg, - configured_server_names={"browserbase"}, - connected_server_names={"browserbase"}, - ) - - assert lines - assert "@browserbase" in lines[0] - assert "mcp_browserbase_" in lines[0] - assert "shell commands" in lines[0] - - -def test_mcp_preset_runtime_lines_warn_when_restart_needed() -> None: - msg = SimpleNamespace( - content="use @browserbase", - metadata={ - "mcp_presets": [{ - "name": "browserbase", - "display_name": "Browserbase", - "transport": "streamableHttp", - }], - }, - ) - - lines = mcp_presets_runtime.runtime_lines( - msg, - configured_server_names=set(), - connected_server_names=set(), - ) - - assert lines - assert "has not loaded the latest MCP settings" in lines[0] - - -def test_mcp_preset_runtime_lines_warn_when_connection_not_live() -> None: - msg = SimpleNamespace( - content="use @browserbase", - metadata={ - "mcp_presets": [{ - "name": "browserbase", - "display_name": "Browserbase", - "transport": "streamableHttp", - }], - }, - ) - - lines = mcp_presets_runtime.runtime_lines( - msg, - configured_server_names={"browserbase"}, - connected_server_names=set(), - ) - - assert lines - assert "connection is not currently live" in lines[0] - - def test_mcp_preset_session_extra_only_persists_structured_mentions() -> None: assert mcp_presets_runtime.session_extra({}) == {} assert mcp_presets_runtime.session_extra({