"""
cvc.agent.tools — Agent tool definitions modeled after Claude Code CLI.

Defines all tools the CVC agent can use:
  - File operations: read_file, write_file, edit_file, patch_file
  - Shell: bash (cross-platform)
  - Search: glob, grep, list_dir
  - Web: web_search
  - CVC Time Machine: cvc_status, cvc_log, cvc_commit, cvc_branch,
    cvc_restore, cvc_merge, cvc_search, cvc_diff
"""

from __future__ import annotations

from typing import Any


# Tools that only read / inspect and never modify state.
# Used by Plan Mode to restrict the agent to analysis-only.
READ_ONLY_TOOLS = frozenset({
    "read_file", "glob", "grep", "list_dir", "web_search",
    "cvc_status", "cvc_log", "cvc_search", "cvc_smart_search",
    "cvc_diff", "cvc_document_search", "cvc_list_documents",
    "task_get", "task_list", "ask_user", "agent", "save_memory",
    "fetch_docs", "search_docs", "lookup_api",
})


# ---------------------------------------------------------------------------
# Tool definitions in OpenAI function-calling schema
# ---------------------------------------------------------------------------

AGENT_TOOLS: list[dict[str, Any]] = [
    # ── File Operations ───────────────────────────────────────────────────
    {
        "type": "function",
        "function": {
            "name": "read_file",
            "description": (
                "Read the contents of a file at the given path. "
                "Returns the file content as text. For large files, use "
                "start_line and end_line to read a specific range."
            ),
            "parameters": {
                "type": "object",
                "properties": {
                    "path": {
                        "type": "string",
                        "description": "Relative or absolute file path to read.",
                    },
                    "start_line": {
                        "type": "integer",
                        "description": "Start line number (1-based). Omit to read from beginning.",
                    },
                    "end_line": {
                        "type": "integer",
                        "description": "End line number (1-based, inclusive). Omit to read to end.",
                    },
                },
                "required": ["path"],
            },
        },
    },
    {
        "type": "function",
        "function": {
            "name": "write_file",
            "description": (
                "Create a new file or overwrite an existing file with the given content. "
                "Parent directories are created automatically if they don't exist."
            ),
            "parameters": {
                "type": "object",
                "properties": {
                    "path": {
                        "type": "string",
                        "description": "File path to write to.",
                    },
                    "content": {
                        "type": "string",
                        "description": "The full content to write to the file.",
                    },
                },
                "required": ["path", "content"],
            },
        },
    },
    {
        "type": "function",
        "function": {
            "name": "edit_file",
            "description": (
                "Edit a file by finding and replacing an exact string. "
                "The old_string must match exactly (including whitespace and indentation). "
                "Include enough context lines to make the match unique."
            ),
            "parameters": {
                "type": "object",
                "properties": {
                    "path": {
                        "type": "string",
                        "description": "File path to edit.",
                    },
                    "old_string": {
                        "type": "string",
                        "description": "The exact text to find in the file. Must match exactly.",
                    },
                    "new_string": {
                        "type": "string",
                        "description": "The replacement text.",
                    },
                },
                "required": ["path", "old_string", "new_string"],
            },
        },
    },

    # ── Shell Execution ───────────────────────────────────────────────────
    {
        "type": "function",
        "function": {
            "name": "patch_file",
            "description": (
                "Apply a unified diff patch to a file. More forgiving than edit_file — "
                "handles whitespace differences and multi-hunk edits. Use standard "
                "unified diff format with @@ -line,count +line,count @@ headers."
            ),
            "parameters": {
                "type": "object",
                "properties": {
                    "path": {
                        "type": "string",
                        "description": "File path to patch.",
                    },
                    "diff": {
                        "type": "string",
                        "description": (
                            "Unified diff content. Lines starting with '-' are removed, "
                            "'+' are added, ' ' (space) are context. Must include @@ headers."
                        ),
                    },
                },
                "required": ["path", "diff"],
            },
        },
    },
    {
        "type": "function",
        "function": {
            "name": "bash",
            "description": (
                "Execute a shell command and return stdout/stderr. "
                "Uses PowerShell on Windows, bash on macOS/Linux. "
                "Use for running tests, installing packages, git commands, "
                "build tools, and any CLI operations. "
                "Commands run in the workspace root directory."
            ),
            "parameters": {
                "type": "object",
                "properties": {
                    "command": {
                        "type": "string",
                        "description": "The shell command to execute.",
                    },
                    "timeout": {
                        "type": "integer",
                        "description": "Timeout in seconds (default: 120).",
                    },
                },
                "required": ["command"],
            },
        },
    },

    # ── Search & Discovery ────────────────────────────────────────────────
    {
        "type": "function",
        "function": {
            "name": "glob",
            "description": (
                "Find files matching a glob pattern. "
                "Returns a list of matching file paths relative to the search root."
            ),
            "parameters": {
                "type": "object",
                "properties": {
                    "pattern": {
                        "type": "string",
                        "description": "Glob pattern, e.g. '**/*.py', 'src/**/*.ts', '*.md'.",
                    },
                    "path": {
                        "type": "string",
                        "description": "Root directory to search from (default: workspace root).",
                    },
                },
                "required": ["pattern"],
            },
        },
    },
    {
        "type": "function",
        "function": {
            "name": "grep",
            "description": (
                "Search for a text pattern across files. "
                "Returns matching lines with file paths and line numbers. "
                "Supports regex patterns."
            ),
            "parameters": {
                "type": "object",
                "properties": {
                    "pattern": {
                        "type": "string",
                        "description": "Search pattern (plain text or regex).",
                    },
                    "path": {
                        "type": "string",
                        "description": "Directory or file to search in (default: workspace root).",
                    },
                    "include": {
                        "type": "string",
                        "description": "Only search files matching this glob (e.g. '*.py').",
                    },
                },
                "required": ["pattern"],
            },
        },
    },
    {
        "type": "function",
        "function": {
            "name": "list_dir",
            "description": (
                "List the contents of a directory. "
                "Returns names with '/' suffix for directories."
            ),
            "parameters": {
                "type": "object",
                "properties": {
                    "path": {
                        "type": "string",
                        "description": "Directory path to list (default: workspace root).",
                    },
                },
            },
        },
    },

    # ── CVC Time Machine Operations ──────────────────────────────────────
    {
        "type": "function",
        "function": {
            "name": "web_search",
            "description": (
                "Search the web for documentation, API references, Stack Overflow answers, "
                "tutorials, or any external information. Returns titles, URLs, and snippets "
                "from search results. Use this when you need to look up library docs, "
                "find solutions to errors, or research APIs."
            ),
            "parameters": {
                "type": "object",
                "properties": {
                    "query": {
                        "type": "string",
                        "description": "The search query — be specific for better results.",
                    },
                    "max_results": {
                        "type": "integer",
                        "description": "Maximum number of results (default: 5).",
                    },
                },
                "required": ["query"],
            },
        },
    },
    {
        "type": "function",
        "function": {
            "name": "cvc_status",
            "description": (
                "Show the current CVC status: active branch, HEAD commit hash, "
                "context window size, and list of all branches."
            ),
            "parameters": {
                "type": "object",
                "properties": {},
            },
        },
    },
    {
        "type": "function",
        "function": {
            "name": "cvc_log",
            "description": (
                "Show the commit history for the active CVC branch. "
                "Each entry includes the short hash, type, and message."
            ),
            "parameters": {
                "type": "object",
                "properties": {
                    "limit": {
                        "type": "integer",
                        "description": "Maximum number of commits to show (default: 20).",
                    },
                },
            },
        },
    },
    {
        "type": "function",
        "function": {
            "name": "cvc_commit",
            "description": (
                "Create a cognitive commit — save the current conversation/context state. "
                "This is like a checkpoint in the Time Machine. You can restore to this "
                "point later."
            ),
            "parameters": {
                "type": "object",
                "properties": {
                    "message": {
                        "type": "string",
                        "description": "A descriptive commit message summarizing the current state.",
                    },
                },
                "required": ["message"],
            },
        },
    },
    {
        "type": "function",
        "function": {
            "name": "cvc_branch",
            "description": (
                "Create a new CVC branch to explore an alternative approach. "
                "The context is reset for isolated exploration. "
                "Use this when you want to try a different strategy without losing progress."
            ),
            "parameters": {
                "type": "object",
                "properties": {
                    "name": {
                        "type": "string",
                        "description": "Branch name (e.g. 'refactor-auth', 'try-redis').",
                    },
                    "description": {
                        "type": "string",
                        "description": "Brief description of what this branch explores.",
                    },
                },
                "required": ["name"],
            },
        },
    },
    {
        "type": "function",
        "function": {
            "name": "cvc_restore",
            "description": (
                "Time-travel: restore the conversation context to a previous commit. "
                "This brings back the AI's memory to that exact point in time. "
                "Use cvc_log first to find the commit hash you want to restore to."
            ),
            "parameters": {
                "type": "object",
                "properties": {
                    "commit_hash": {
                        "type": "string",
                        "description": "The commit hash to restore to (full or short 12-char).",
                    },
                },
                "required": ["commit_hash"],
            },
        },
    },
    {
        "type": "function",
        "function": {
            "name": "cvc_merge",
            "description": (
                "Merge insights from one CVC branch into another. "
                "Performs a semantic three-way merge."
            ),
            "parameters": {
                "type": "object",
                "properties": {
                    "source_branch": {
                        "type": "string",
                        "description": "The branch to merge from.",
                    },
                    "target_branch": {
                        "type": "string",
                        "description": "The branch to merge into (default: active branch).",
                    },
                },
                "required": ["source_branch"],
            },
        },
    },
    {
        "type": "function",
        "function": {
            "name": "cvc_search",
            "description": (
                "Search through CVC commit history to find previous conversations "
                "and context about a specific topic. Use this when the user asks to "
                "'go back to when we discussed X' or 'find the context about Y'. "
                "Returns matching commits with their messages and hashes."
            ),
            "parameters": {
                "type": "object",
                "properties": {
                    "query": {
                        "type": "string",
                        "description": "Natural language search query — what to find in history.",
                    },
                    "limit": {
                        "type": "integer",
                        "description": "Maximum results to return (default: 10).",
                    },
                },
                "required": ["query"],
            },
        },
    },
    {
        "type": "function",
        "function": {
            "name": "cvc_smart_search",
            "description": (
                "Advanced staged hybrid search with metadata pre-filtering. "
                "Use this instead of cvc_search when the user specifies constraints like "
                "date ranges, specific branches, commit types, providers, models, or tags. "
                "Implements 3-stage filtering: (1) metadata pre-filter for high selectivity, "
                "(2) ANN vector search on filtered subset, (3) post-filter refinement. "
                "Much more precise than basic search — prevents retrieving irrelevant context."
            ),
            "parameters": {
                "type": "object",
                "properties": {
                    "query": {
                        "type": "string",
                        "description": "Natural language search query — what to find in history.",
                    },
                    "branch": {
                        "type": "string",
                        "description": "Filter to commits on this branch only.",
                    },
                    "commit_type": {
                        "type": "string",
                        "description": "Filter by commit type: checkpoint, analysis, generation, rollback, merge, anchor.",
                        "enum": ["checkpoint", "analysis", "generation", "rollback", "merge", "anchor"],
                    },
                    "provider": {
                        "type": "string",
                        "description": "Filter to commits made with this LLM provider (anthropic, openai, google, ollama, lmstudio).",
                    },
                    "model": {
                        "type": "string",
                        "description": "Filter to commits made with this specific model.",
                    },
                    "since": {
                        "type": "string",
                        "description": "Only include commits after this date/time (ISO 8601 or relative like '2h', '7d', '30d').",
                    },
                    "until": {
                        "type": "string",
                        "description": "Only include commits before this date/time (ISO 8601 or relative like '2h', '7d').",
                    },
                    "tags": {
                        "type": "array",
                        "items": {"type": "string"},
                        "description": "Filter to commits with any of these tags.",
                    },
                    "contains_keyword": {
                        "type": "string",
                        "description": "Post-filter: only return results whose conversation content contains this keyword.",
                    },
                    "limit": {
                        "type": "integer",
                        "description": "Maximum results to return (default: 10).",
                    },
                },
                "required": ["query"],
            },
        },
    },
    {
        "type": "function",
        "function": {
            "name": "cvc_diff",
            "description": (
                "Show the difference between the current context and a previous commit, "
                "or between two commits. Useful for understanding what changed."
            ),
            "parameters": {
                "type": "object",
                "properties": {
                    "commit_a": {
                        "type": "string",
                        "description": "First commit hash (or 'HEAD' for current).",
                    },
                    "commit_b": {
                        "type": "string",
                        "description": "Second commit hash to compare against.",
                    },
                },
                "required": ["commit_a"],
            },
        },
    },
    # ── Tier 4: PageIndex — Document RAG (CLI agent only) ─────────────
    {
        "type": "function",
        "function": {
            "name": "cvc_ingest_document",
            "description": (
                "Ingest an external document (PDF, Markdown, text, code file) into "
                "CVC's Tier 4 PageIndex. Uses the real PageIndex architecture: "
                "extracts the document's natural Table-of-Contents structure, builds "
                "a page-indexed hierarchical tree, and generates LLM summaries for "
                "each node — no arbitrary chunking. "
                "Use when the user wants to add reference material, research papers, "
                "large docs, or databases to the CVC agent's knowledge. "
                "Requires the same LLM API key already in use — no extra keys needed."
            ),
            "parameters": {
                "type": "object",
                "properties": {
                    "path": {
                        "type": "string",
                        "description": "Path to the document to ingest (PDF, .md, .txt, .py, etc.).",
                    },
                },
                "required": ["path"],
            },
        },
    },
    {
        "type": "function",
        "function": {
            "name": "cvc_document_search",
            "description": (
                "Search through documents previously ingested via cvc_ingest_document. "
                "Uses LLM-powered hierarchical tree navigation (PageIndex) to find the "
                "most relevant sections. The LLM reads node summaries at each level "
                "and selects the most relevant branches, recursing down to leaf nodes. "
                "Unlike cvc_search (which searches CVC commits), this searches "
                "external documents like PDFs, research papers, and codebases."
            ),
            "parameters": {
                "type": "object",
                "properties": {
                    "query": {
                        "type": "string",
                        "description": "Natural language query to search for in indexed documents.",
                    },
                    "doc_id": {
                        "type": "string",
                        "description": "Optional: search only this document (short hash prefix or full ID). If omitted, searches all indexed docs.",
                    },
                    "max_results": {
                        "type": "integer",
                        "description": "Maximum chunks to return (default: 5).",
                    },
                },
                "required": ["query"],
            },
        },
    },
    {
        "type": "function",
        "function": {
            "name": "cvc_list_documents",
            "description": (
                "List all documents currently indexed in CVC's PageIndex (Tier 4). "
                "Shows document name, type (PDF/Markdown/Text), node count, and a "
                "short LLM-generated description for each indexed document."
            ),
            "parameters": {
                "type": "object",
                "properties": {},
            },
        },
    },

    # ── Sub-agent + Task Management ───────────────────────────────────────
    {
        "type": "function",
        "function": {
            "name": "agent",
            "description": (
                "Spawn a sub-agent to perform a task in an isolated context. "
                "The sub-agent has its own conversation history and restricted tools. "
                "Built-in agents: 'Explore' (fast read-only codebase search), "
                "'Plan' (analyze and plan without modifying files), "
                "'Security' (vulnerability scanning and code security audit), "
                "'AI' (AI/ML engineering and Python AI development), "
                "'UI' (UI/UX design and frontend engineering), "
                "'Data' (data analytics, SQL, ETL, visualization), "
                "'Orchestrator' (coordinates other agents for complex multi-domain tasks). "
                "Custom agents can be defined in .cvc/agents/<name>/agent.md. "
                "Use this when you need to research something without polluting "
                "your main context window, or to delegate subtasks."
            ),
            "parameters": {
                "type": "object",
                "properties": {
                    "name": {
                        "type": "string",
                        "description": "Name of the sub-agent to use: 'Explore', 'Plan', 'Security', 'AI', 'UI', 'Data', 'Orchestrator', or a custom agent name.",
                    },
                    "prompt": {
                        "type": "string",
                        "description": "The task or question for the sub-agent.",
                    },
                },
                "required": ["name", "prompt"],
            },
        },
    },
    {
        "type": "function",
        "function": {
            "name": "task_create",
            "description": (
                "Start a shell command as a background task. Returns a task ID "
                "that you can use to check status and retrieve output later. "
                "Use this for long-running commands (builds, tests, servers) "
                "so you can continue working while they run."
            ),
            "parameters": {
                "type": "object",
                "properties": {
                    "command": {
                        "type": "string",
                        "description": "The shell command to run in the background.",
                    },
                },
                "required": ["command"],
            },
        },
    },
    {
        "type": "function",
        "function": {
            "name": "task_get",
            "description": (
                "Check the status and output of a background task by its ID."
            ),
            "parameters": {
                "type": "object",
                "properties": {
                    "task_id": {
                        "type": "string",
                        "description": "The task ID returned by task_create.",
                    },
                },
                "required": ["task_id"],
            },
        },
    },
    {
        "type": "function",
        "function": {
            "name": "task_list",
            "description": "List all background tasks with their current status.",
            "parameters": {
                "type": "object",
                "properties": {},
            },
        },
    },
    {
        "type": "function",
        "function": {
            "name": "task_kill",
            "description": "Terminate a running background task.",
            "parameters": {
                "type": "object",
                "properties": {
                    "task_id": {
                        "type": "string",
                        "description": "The task ID to terminate.",
                    },
                },
                "required": ["task_id"],
            },
        },
    },
    {
        "type": "function",
        "function": {
            "name": "ask_user",
            "description": (
                "Ask the user a question and wait for their response. Use this when "
                "you need clarification, confirmation, or the user's preference "
                "before proceeding. You can optionally provide a list of choices."
            ),
            "parameters": {
                "type": "object",
                "properties": {
                    "question": {
                        "type": "string",
                        "description": "The question to ask the user.",
                    },
                    "options": {
                        "type": "array",
                        "items": {"type": "string"},
                        "description": "Optional list of choices (e.g. ['Option A', 'Option B']). If provided, the user picks one.",
                    },
                },
                "required": ["question"],
            },
        },
    },
    {
        "type": "function",
        "function": {
            "name": "save_memory",
            "description": (
                "Save a note to topic-based auto-memory. Use this to remember important "
                "facts, user preferences, project conventions, debugging insights, or "
                "anything that should persist across sessions. Each topic is a separate "
                "file (e.g. 'preferences', 'conventions', 'debugging')."
            ),
            "parameters": {
                "type": "object",
                "properties": {
                    "topic": {
                        "type": "string",
                        "description": "The topic/category name (e.g. 'preferences', 'conventions', 'architecture').",
                    },
                    "content": {
                        "type": "string",
                        "description": "The note content to save. Keep it concise — use bullet points or single-line facts.",
                    },
                },
                "required": ["topic", "content"],
            },
        },
    },
    # ── Input Grounding (Anti-Hallucination) ───────────────────────────
    {
        "type": "function",
        "function": {
            "name": "fetch_docs",
            "description": (
                "Fetch current API documentation for a library or SDK BEFORE writing code "
                "that uses it. This prevents hallucinating API shapes from training data. "
                "Always prefer this over guessing API signatures. Returns the real, current "
                "documentation with any saved annotations (gotchas, tips). "
                "Example IDs: 'openai/chat', 'stripe/api', 'anthropic/sdk', 'firebase/admin'."
            ),
            "parameters": {
                "type": "object",
                "properties": {
                    "doc_id": {
                        "type": "string",
                        "description": "Documentation ID (e.g. 'openai/chat', 'stripe/api'). Use search_docs to find available IDs.",
                    },
                    "language": {
                        "type": "string",
                        "description": "Language variant: 'python', 'javascript', 'typescript', etc.",
                    },
                    "section": {
                        "type": "string",
                        "description": "Optional: fetch only a specific section (e.g. 'Streaming', 'Authentication').",
                    },
                },
                "required": ["doc_id"],
            },
        },
    },
    {
        "type": "function",
        "function": {
            "name": "search_docs",
            "description": (
                "Search for available API documentation by keyword. "
                "Use this to find the correct doc ID before calling fetch_docs. "
                "Searches local cache and Context Hub (if installed)."
            ),
            "parameters": {
                "type": "object",
                "properties": {
                    "query": {
                        "type": "string",
                        "description": "Search query (e.g. 'stripe payments', 'openai', 'firebase auth').",
                    },
                },
                "required": ["query"],
            },
        },
    },
    {
        "type": "function",
        "function": {
            "name": "lookup_api",
            "description": (
                "Check if an API symbol (module, class, function) exists in the project's "
                "installed packages or standard library. Use this BEFORE referencing an "
                "unfamiliar API to verify it's real and not hallucinated. "
                "Returns whether the symbol exists and its source."
            ),
            "parameters": {
                "type": "object",
                "properties": {
                    "symbol": {
                        "type": "string",
                        "description": "The API symbol to look up (e.g. 'openai.OpenAI', 'stripe.Webhook', 'fastapi.FastAPI').",
                    },
                    "language": {
                        "type": "string",
                        "description": "Programming language: 'python', 'javascript', 'typescript'.",
                    },
                },
                "required": ["symbol"],
            },
        },
    },
    {
        "type": "function",
        "function": {
            "name": "annotate_doc",
            "description": (
                "Save a note (gotcha, tip, workaround) about an API doc that you discovered "
                "during coding. Annotations persist across sessions and auto-appear on future "
                "doc fetches. Use this after encountering an undocumented behavior, version quirk, "
                "or project-specific detail."
            ),
            "parameters": {
                "type": "object",
                "properties": {
                    "doc_id": {
                        "type": "string",
                        "description": "Documentation ID to annotate (e.g. 'openai/chat', 'stripe/api').",
                    },
                    "note": {
                        "type": "string",
                        "description": "The annotation text. Keep it concise and actionable.",
                    },
                },
                "required": ["doc_id", "note"],
            },
        },
    },
    # ── Workspace Management ──────────────────────────────────────────
    {
        "type": "function",
        "function": {
            "name": "cvc_switch_workspace",
            "description": (
                "Switch CVC to a different workspace/project folder. Automatically "
                "initializes .cvc/ if it doesn't exist, and loads that workspace's "
                "isolated four-tier memory (SQLite, CAS blobs, ChromaDB, PageIndex). "
                "Use when the user says 'go to folder X', 'switch to project Y', or "
                "'work on this other project'. All subsequent CVC operations will "
                "operate on the new workspace. Previous workspace state is preserved."
            ),
            "parameters": {
                "type": "object",
                "properties": {
                    "path": {
                        "type": "string",
                        "description": "Absolute path to the workspace/project directory to switch to.",
                    },
                },
                "required": ["path"],
            },
        },
    },
]


def get_tool_names() -> list[str]:
    """Return a list of all agent tool names."""
    return [t["function"]["name"] for t in AGENT_TOOLS]


def get_tools_for_provider(provider: str) -> list[dict[str, Any]]:
    """
    Return tool definitions formatted for a specific provider.

    - OpenAI / Ollama: Use the defs as-is (OpenAI function calling format)
    - Anthropic: Convert to Anthropic's tool format
    - Google: Convert to Google's function declarations format
    """
    if provider == "anthropic":
        return _to_anthropic_tools(AGENT_TOOLS)
    elif provider == "google":
        return _to_google_tools(AGENT_TOOLS)
    else:
        return AGENT_TOOLS  # OpenAI / Ollama


def _to_anthropic_tools(tools: list[dict]) -> list[dict]:
    """Convert OpenAI tool defs to Anthropic format."""
    converted = []
    for t in tools:
        fn = t["function"]
        converted.append({
            "name": fn["name"],
            "description": fn["description"],
            "input_schema": fn["parameters"],
        })
    return converted


def _to_google_tools(tools: list[dict]) -> list[dict]:
    """Convert OpenAI tool defs to Google Gemini function declarations."""
    declarations = []
    for t in tools:
        fn = t["function"]
        declarations.append({
            "name": fn["name"],
            "description": fn["description"],
            "parameters": fn["parameters"],
        })
    return [{"functionDeclarations": declarations}]


# ---------------------------------------------------------------------------
# Model catalog — shared between CLI setup and in-agent /model switching
# ---------------------------------------------------------------------------

MODEL_CATALOG_AGENT: dict[str, list[tuple[str, str, str]]] = {
    "anthropic": [
        ("claude-opus-4-6", "Most intelligent — agents & coding (Feb 2026)", "$5/$25 per MTok"),
        ("claude-sonnet-4-6", "Best speed/intelligence balance (Feb 2026)", "$3/$15 per MTok"),
        ("claude-opus-4-5", "Previous flagship — excellent reasoning", "$5/$25 per MTok"),
        ("claude-sonnet-4-5", "Previous Sonnet — still great", "$3/$15 per MTok"),
        ("claude-haiku-4-5", "Fastest & cheapest", "$1/$5 per MTok"),
    ],
    "openai": [
        ("gpt-5.3", "Newest flagship — best reasoning & coding", "Frontier"),
        ("gpt-5.2", "Previous flagship — coding & agentic tasks", "Frontier"),
        ("gpt-5.2-codex", "Optimized for agentic coding", "Frontier"),
        ("gpt-5-mini", "Fast & cost-efficient GPT-5", "Mid-tier"),
        ("gpt-4.1", "Instruction following & tool calling (1M ctx)", "Mid-tier"),
    ],
    "google": [
        ("gemini-3-flash-preview", "Gemini 3 Flash — fast thinking (recommended)", "Standard"),
        ("gemini-3-pro-preview", "Gemini 3 Pro — deep reasoning", "Premium"),
        ("gemini-3.1-pro-preview", "Gemini 3.1 Pro — refined thinking & agentic (newest)", "Premium"),
    ],
    "ollama": [
        # All models below carry the Ollama 'tools' badge — confirmed to support
        # function/tool calling with the native /api/chat endpoint as of Feb 2026.
        ("qwen2.5-coder:7b", "Best 7B coding — 11M+ pulls, tools ✓", "~4 GB"),
        ("qwen3:14b", "Qwen3 — thinking + non-thinking modes, tools ✓", "~9 GB"),
        ("qwen3-coder:30b", "Agentic coder — MoE (3.3B active), 256K ctx, tools ✓", "~19 GB"),
        ("devstral:24b", "Mistral best open-source coding agent, tools ✓", "~14 GB"),
        ("deepseek-r1:8b", "DeepSeek-R1 — reasoning + tool calling", "~5 GB"),
        ("mistral-small3.2:24b", "Improved function calling + vision, tools ✓", "~15 GB"),
        ("qwq:32b", "QwQ — deep reasoning + tool calling (chain-of-thought)", "~20 GB"),
        ("llama3.3:70b", "Meta Llama 3.3 — powerful general model, tools ✓", "~40 GB"),
    ],
    "lmstudio": [
        # Model IDs should match what LM Studio shows in Developer → Server tab.
        # All listed models support tool calling (native or via LM Studio's prompt injection).
        ("qwen2.5-coder-32b-instruct", "Best local coding — Qwen 2.5, native tools", "~18 GB"),
        ("qwen3-14b", "Qwen3 14B — thinking mode + tool calling", "~9 GB"),
        ("devstral-small-2505", "Mistral agentic coding model, tool calling", "~14 GB"),
        ("deepseek-r1-distill-qwen-32b", "Reasoning + coding, chain-of-thought", "~18 GB"),
        ("gemma-3-27b-it", "Google Gemma 3 27B instruction tuned", "~15 GB"),
        ("mistral-small-3.2-24b-instruct", "Improved function calling over 3.1", "~13 GB"),
    ],
}
