/**
 * @license
 * Copyright 2025 Google LLC
 * SPDX-License-Identifier: Apache-2.0
 */

/**
 * Full tool manifest for Gemini 3 models.
 * Allows model-specific optimizations of descriptions and schemas.
 */

import type { CoreToolSet } from '../types.js';
import {
  GLOB_TOOL_NAME,
  GREP_TOOL_NAME,
  LS_TOOL_NAME,
  READ_FILE_TOOL_NAME,
  WRITE_FILE_TOOL_NAME,
  EDIT_TOOL_NAME,
  WEB_SEARCH_TOOL_NAME,
  WRITE_TODOS_TOOL_NAME,
  WEB_FETCH_TOOL_NAME,
  READ_MANY_FILES_TOOL_NAME,
  MEMORY_TOOL_NAME,
  GET_INTERNAL_DOCS_TOOL_NAME,
  ASK_USER_TOOL_NAME,
  ENTER_PLAN_MODE_TOOL_NAME,
  // Shared parameter names
  PARAM_FILE_PATH,
  PARAM_DIR_PATH,
  PARAM_PATTERN,
  PARAM_CASE_SENSITIVE,
  PARAM_RESPECT_GIT_IGNORE,
  PARAM_RESPECT_GEMINI_IGNORE,
  PARAM_FILE_FILTERING_OPTIONS,
  // Tool-specific parameter names
  READ_FILE_PARAM_START_LINE,
  READ_FILE_PARAM_END_LINE,
  WRITE_FILE_PARAM_CONTENT,
  GREP_PARAM_INCLUDE_PATTERN,
  GREP_PARAM_EXCLUDE_PATTERN,
  GREP_PARAM_NAMES_ONLY,
  GREP_PARAM_MAX_MATCHES_PER_FILE,
  GREP_PARAM_TOTAL_MAX_MATCHES,
  GREP_PARAM_FIXED_STRINGS,
  GREP_PARAM_CONTEXT,
  GREP_PARAM_AFTER,
  GREP_PARAM_BEFORE,
  GREP_PARAM_NO_IGNORE,
  EDIT_PARAM_INSTRUCTION,
  EDIT_PARAM_OLD_STRING,
  EDIT_PARAM_NEW_STRING,
  EDIT_PARAM_ALLOW_MULTIPLE,
  LS_PARAM_IGNORE,
  WEB_SEARCH_PARAM_QUERY,
  WEB_FETCH_PARAM_PROMPT,
  READ_MANY_PARAM_INCLUDE,
  READ_MANY_PARAM_EXCLUDE,
  READ_MANY_PARAM_RECURSIVE,
  READ_MANY_PARAM_USE_DEFAULT_EXCLUDES,
  MEMORY_PARAM_FACT,
  TODOS_PARAM_TODOS,
  TODOS_ITEM_PARAM_DESCRIPTION,
  TODOS_ITEM_PARAM_STATUS,
  DOCS_PARAM_PATH,
  ASK_USER_PARAM_QUESTIONS,
  ASK_USER_QUESTION_PARAM_QUESTION,
  ASK_USER_QUESTION_PARAM_HEADER,
  ASK_USER_QUESTION_PARAM_TYPE,
  ASK_USER_QUESTION_PARAM_OPTIONS,
  ASK_USER_QUESTION_PARAM_MULTI_SELECT,
  ASK_USER_QUESTION_PARAM_PLACEHOLDER,
  ASK_USER_OPTION_PARAM_LABEL,
  ASK_USER_OPTION_PARAM_DESCRIPTION,
  PLAN_MODE_PARAM_REASON,
} from '../base-declarations.js';
import {
  getShellDeclaration,
  getExitPlanModeDeclaration,
  getActivateSkillDeclaration,
  getUpdateTopicDeclaration,
} from '../dynamic-declaration-helpers.js';
import {
  DEFAULT_MAX_LINES_TEXT_FILE,
  MAX_LINE_LENGTH_TEXT_FILE,
  MAX_FILE_SIZE_MB,
} from '../../../utils/constants.js';

/**
 * Gemini 3 tool set. Initially a copy of the default legacy set.
 */
export const GEMINI_3_SET: CoreToolSet = {
  read_file: {
    name: READ_FILE_TOOL_NAME,
    description: `Reads and returns the content of a specified file. To maintain context efficiency, you MUST use 'start_line' and 'end_line' for targeted, surgical reads of specific sections. For your safety, the tool will automatically truncate output exceeding ${DEFAULT_MAX_LINES_TEXT_FILE} lines, ${MAX_LINE_LENGTH_TEXT_FILE} characters per line, or ${MAX_FILE_SIZE_MB}MB in size; however, triggering these limits is considered token-inefficient. Always retrieve only the minimum content necessary for your next step. Handles text, images (PNG, JPG, GIF, WEBP, SVG, BMP), audio files (MP3, WAV, AIFF, AAC, OGG, FLAC), and PDF files.`,
    parametersJsonSchema: {
      type: 'object',
      properties: {
        [PARAM_FILE_PATH]: {
          description: 'The path to the file to read.',
          type: 'string',
        },
        [READ_FILE_PARAM_START_LINE]: {
          description:
            'Optional: The 1-based line number to start reading from.',
          type: 'number',
        },
        [READ_FILE_PARAM_END_LINE]: {
          description:
            'Optional: The 1-based line number to end reading at (inclusive).',
          type: 'number',
        },
      },
      required: [PARAM_FILE_PATH],
    },
  },

  write_file: {
    name: WRITE_FILE_TOOL_NAME,
    description: `Writes the complete content to a file, automatically creating missing parent directories. Overwrites existing files. The user has the ability to modify 'content' before it is saved. Best for new or small files; use '${EDIT_TOOL_NAME}' for targeted edits to large files.`,
    parametersJsonSchema: {
      type: 'object',
      properties: {
        [PARAM_FILE_PATH]: {
          description: 'Path to the file.',
          type: 'string',
        },
        [WRITE_FILE_PARAM_CONTENT]: {
          description:
            "The complete content to write. Provide the full file; do not use placeholders like '// ... rest of code'.",
          type: 'string',
        },
      },
      required: [PARAM_FILE_PATH, WRITE_FILE_PARAM_CONTENT],
    },
  },

  grep_search: {
    name: GREP_TOOL_NAME,
    description:
      'Searches for a regular expression pattern within file contents. Max 100 matches.',
    parametersJsonSchema: {
      type: 'object',
      properties: {
        [PARAM_PATTERN]: {
          description: `The regular expression (regex) pattern to search for within file contents (e.g., 'function\\s+myFunction', 'import\\s+\\{.*\\}\\s+from\\s+.*').`,
          type: 'string',
        },
        [PARAM_DIR_PATH]: {
          description:
            'Optional: The absolute path to the directory to search within. If omitted, searches the current working directory.',
          type: 'string',
        },
        [GREP_PARAM_INCLUDE_PATTERN]: {
          description: `Optional: A glob pattern to filter which files are searched (e.g., '*.js', '*.{ts,tsx}', 'src/**'). If omitted, searches all files (respecting potential global ignores).`,
          type: 'string',
        },
        [GREP_PARAM_EXCLUDE_PATTERN]: {
          description:
            'Optional: A regular expression pattern to exclude from the search results. If a line matches both the pattern and the exclude_pattern, it will be omitted.',
          type: 'string',
        },
        [GREP_PARAM_NAMES_ONLY]: {
          description:
            'Optional: If true, only the file paths of the matches will be returned, without the line content or line numbers. This is useful for gathering a list of files.',
          type: 'boolean',
        },
        [GREP_PARAM_MAX_MATCHES_PER_FILE]: {
          description:
            'Optional: Maximum number of matches to return per file. Use this to prevent being overwhelmed by repetitive matches in large files.',
          type: 'integer',
          minimum: 1,
        },
        [GREP_PARAM_TOTAL_MAX_MATCHES]: {
          description:
            'Optional: Maximum number of total matches to return. Use this to limit the overall size of the response. Defaults to 100 if omitted.',
          type: 'integer',
          minimum: 1,
        },
      },
      required: [PARAM_PATTERN],
    },
  },

  grep_search_ripgrep: {
    name: GREP_TOOL_NAME,
    description:
      'Searches for a regular expression pattern within file contents. This tool is FAST and optimized, powered by ripgrep. PREFERRED over standard `run_shell_command("grep ...")` due to better performance and automatic output limiting (defaults to 100 matches, but can be increased via `total_max_matches`).',
    parametersJsonSchema: {
      type: 'object',
      properties: {
        [PARAM_PATTERN]: {
          description: `The pattern to search for. By default, treated as a Rust-flavored regular expression. Use '\\b' for precise symbol matching (e.g., '\\bMatchMe\\b').`,
          type: 'string',
        },
        [PARAM_DIR_PATH]: {
          description:
            "Directory or file to search. Directories are searched recursively. Relative paths are resolved against current working directory. Defaults to current working directory ('.') if omitted.",
          type: 'string',
        },
        [GREP_PARAM_INCLUDE_PATTERN]: {
          description:
            "Glob pattern to filter files (e.g., '*.ts', 'src/**'). Recommended for large repositories to reduce noise. Defaults to all files if omitted.",
          type: 'string',
        },
        [GREP_PARAM_EXCLUDE_PATTERN]: {
          description:
            'Optional: A regular expression pattern to exclude from the search results. If a line matches both the pattern and the exclude_pattern, it will be omitted.',
          type: 'string',
        },
        [GREP_PARAM_NAMES_ONLY]: {
          description:
            'Optional: If true, only the file paths of the matches will be returned, without the line content or line numbers. This is useful for gathering a list of files.',
          type: 'boolean',
        },
        [PARAM_CASE_SENSITIVE]: {
          description:
            'If true, search is case-sensitive. Defaults to false (ignore case) if omitted.',
          type: 'boolean',
        },
        [GREP_PARAM_FIXED_STRINGS]: {
          description:
            'If true, treats the `pattern` as a literal string instead of a regular expression. Defaults to false (basic regex) if omitted.',
          type: 'boolean',
        },
        [GREP_PARAM_CONTEXT]: {
          description:
            'Show this many lines of context around each match (equivalent to grep -C). Defaults to 0 if omitted.',
          type: 'integer',
        },
        [GREP_PARAM_AFTER]: {
          description:
            'Show this many lines after each match (equivalent to grep -A). Defaults to 0 if omitted.',
          type: 'integer',
          minimum: 0,
        },
        [GREP_PARAM_BEFORE]: {
          description:
            'Show this many lines before each match (equivalent to grep -B). Defaults to 0 if omitted.',
          type: 'integer',
          minimum: 0,
        },
        [GREP_PARAM_NO_IGNORE]: {
          description:
            'If true, searches all files including those usually ignored (like in .gitignore, build/, dist/, etc). Defaults to false if omitted.',
          type: 'boolean',
        },
        [GREP_PARAM_MAX_MATCHES_PER_FILE]: {
          description:
            'Optional: Maximum number of matches to return per file. Use this to prevent being overwhelmed by repetitive matches in large files.',
          type: 'integer',
          minimum: 1,
        },
        [GREP_PARAM_TOTAL_MAX_MATCHES]: {
          description:
            'Optional: Maximum number of total matches to return. Use this to limit the overall size of the response. Defaults to 100 if omitted.',
          type: 'integer',
          minimum: 1,
        },
      },
      required: [PARAM_PATTERN],
    },
  },

  glob: {
    name: GLOB_TOOL_NAME,
    description:
      'Efficiently finds files matching specific glob patterns (e.g., `src/**/*.ts`, `**/*.md`), returning absolute paths sorted by modification time (newest first). Ideal for quickly locating files based on their name or path structure, especially in large codebases.',
    parametersJsonSchema: {
      type: 'object',
      properties: {
        [PARAM_PATTERN]: {
          description:
            "The glob pattern to match against (e.g., '**/*.py', 'docs/*.md').",
          type: 'string',
        },
        [PARAM_DIR_PATH]: {
          description:
            'Optional: The absolute path to the directory to search within. If omitted, searches the root directory.',
          type: 'string',
        },
        [PARAM_CASE_SENSITIVE]: {
          description:
            'Optional: Whether the search should be case-sensitive. Defaults to false.',
          type: 'boolean',
        },
        [PARAM_RESPECT_GIT_IGNORE]: {
          description:
            'Optional: Whether to respect .gitignore patterns when finding files. Only available in git repositories. Defaults to true.',
          type: 'boolean',
        },
        [PARAM_RESPECT_GEMINI_IGNORE]: {
          description:
            'Optional: Whether to respect .geminiignore patterns when finding files. Defaults to true.',
          type: 'boolean',
        },
      },
      required: [PARAM_PATTERN],
    },
  },

  list_directory: {
    name: LS_TOOL_NAME,
    description:
      'Lists the names of files and subdirectories directly within a specified directory path. Can optionally ignore entries matching provided glob patterns.',
    parametersJsonSchema: {
      type: 'object',
      properties: {
        [PARAM_DIR_PATH]: {
          description: 'The path to the directory to list',
          type: 'string',
        },
        [LS_PARAM_IGNORE]: {
          description: 'List of glob patterns to ignore',
          items: {
            type: 'string',
          },
          type: 'array',
        },
        [PARAM_FILE_FILTERING_OPTIONS]: {
          description:
            'Optional: Whether to respect ignore patterns from .gitignore or .geminiignore',
          type: 'object',
          properties: {
            [PARAM_RESPECT_GIT_IGNORE]: {
              description:
                'Optional: Whether to respect .gitignore patterns when listing files. Only available in git repositories. Defaults to true.',
              type: 'boolean',
            },
            [PARAM_RESPECT_GEMINI_IGNORE]: {
              description:
                'Optional: Whether to respect .geminiignore patterns when listing files. Defaults to true.',
              type: 'boolean',
            },
          },
        },
      },
      required: [PARAM_DIR_PATH],
    },
  },

  run_shell_command: (
    enableInteractiveShell,
    enableEfficiency,
    enableToolSandboxing,
  ) =>
    getShellDeclaration(
      enableInteractiveShell,
      enableEfficiency,
      enableToolSandboxing,
    ),

  replace: {
    name: EDIT_TOOL_NAME,
    description: `Replaces text within a file. By default, the tool expects to find and replace exactly ONE occurrence of \`old_string\`. If you want to replace multiple occurrences of the exact same string, set \`allow_multiple\` to true. This tool requires providing significant context around the change to ensure precise targeting.
The user has the ability to modify the \`new_string\` content. If modified, this will be stated in the response.`,
    parametersJsonSchema: {
      type: 'object',
      properties: {
        [PARAM_FILE_PATH]: {
          description: 'The path to the file to modify.',
          type: 'string',
        },
        [EDIT_PARAM_INSTRUCTION]: {
          description: `A clear, semantic instruction for the code change, acting as a high-quality prompt for an expert LLM assistant. It must be self-contained and explain the goal of the change.`,
          type: 'string',
        },
        [EDIT_PARAM_OLD_STRING]: {
          description:
            'The exact literal text to replace, unescaped. If this string is not the exact literal text (i.e. you escaped it) or does not match exactly, the tool will fail.',
          type: 'string',
        },
        [EDIT_PARAM_NEW_STRING]: {
          description:
            "The exact literal text to replace `old_string` with, unescaped. Provide the EXACT text. Ensure the resulting code is correct and idiomatic. Do not use omission placeholders like '(rest of methods ...)', '...', or 'unchanged code'; provide exact literal code.",
          type: 'string',
        },
        [EDIT_PARAM_ALLOW_MULTIPLE]: {
          type: 'boolean',
          description:
            'If true, the tool will replace all occurrences of `old_string`. If false (default), it will only succeed if exactly one occurrence is found.',
        },
      },
      required: [
        PARAM_FILE_PATH,
        EDIT_PARAM_INSTRUCTION,
        EDIT_PARAM_OLD_STRING,
        EDIT_PARAM_NEW_STRING,
      ],
    },
  },

  google_web_search: {
    name: WEB_SEARCH_TOOL_NAME,
    description: `Performs a grounded Google Search to find information across the internet. Returns a synthesized answer with citations (e.g., [1]) and source URIs. Best for finding up-to-date documentation, troubleshooting obscure errors, or broad research. Use this when you don't have a specific URL. If a search result requires deeper analysis, follow up by using '${WEB_FETCH_TOOL_NAME}' on the provided URI.`,
    parametersJsonSchema: {
      type: 'object',
      properties: {
        [WEB_SEARCH_PARAM_QUERY]: {
          type: 'string',
          description:
            "The search query. Supports natural language questions (e.g., 'Latest breaking changes in React 19') or specific technical queries.",
        },
      },
      required: [WEB_SEARCH_PARAM_QUERY],
    },
  },

  web_fetch: {
    name: WEB_FETCH_TOOL_NAME,
    description:
      "Analyzes and extracts information from up to 20 URLs. Ideal for documentation review, technical research, or reading raw code from GitHub. You can provide specific, complex instructions for the extraction (e.g., 'Summarize the breaking changes'). Provides cited answers based on the content. GitHub 'blob' URLs are automatically converted to raw versions for better processing. Supports HTTP/HTTPS only.",
    parametersJsonSchema: {
      type: 'object',
      properties: {
        [WEB_FETCH_PARAM_PROMPT]: {
          description:
            'A string containing the URL(s) and your specific analysis instructions. Be clear about what information you want to find or summarize. Supports up to 20 URLs.',
          type: 'string',
        },
      },
      required: [WEB_FETCH_PARAM_PROMPT],
    },
  },

  read_many_files: {
    name: READ_MANY_FILES_TOOL_NAME,
    description: `Reads content from multiple files specified by glob patterns within a configured target directory. For text files, it concatenates their content into a single string. It is primarily designed for text-based files. However, it can also process image (e.g., .png, .jpg), audio (e.g., .mp3, .wav), and PDF (.pdf) files if their file names or extensions are explicitly included in the 'include' argument. For these explicitly requested non-text files, their data is read and included in a format suitable for model consumption (e.g., base64 encoded).

This tool is useful when you need to understand or analyze a collection of files, such as:
- Getting an overview of a codebase or parts of it (e.g., all TypeScript files in the 'src' directory).
- Finding where specific functionality is implemented if the user asks broad questions about code.
- Reviewing documentation files (e.g., all Markdown files in the 'docs' directory).
- Gathering context from multiple configuration files.
- When the user asks to "read all files in X directory" or "show me the content of all Y files".

Use this tool when the user's query implies needing the content of several files simultaneously for context, analysis, or summarization. For text files, it uses default UTF-8 encoding and a '--- {filePath} ---' separator between file contents. The tool inserts a '--- End of content ---' after the last file. Ensure glob patterns are relative to the target directory. Glob patterns like 'src/**/*.js' are supported. Avoid using for single files if a more specific single-file reading tool is available, unless the user specifically requests to process a list containing just one file via this tool. Other binary files (not explicitly requested as image/audio/PDF) are generally skipped. Default excludes apply to common non-text files (except for explicitly requested images/audio/PDFs) and large dependency directories unless 'useDefaultExcludes' is false.`,
    parametersJsonSchema: {
      type: 'object',
      properties: {
        [READ_MANY_PARAM_INCLUDE]: {
          type: 'array',
          items: {
            type: 'string',
            minLength: 1,
          },
          minItems: 1,
          description:
            'An array of glob patterns or paths. Examples: ["src/**/*.ts"], ["README.md", "docs/"]',
        },
        [READ_MANY_PARAM_EXCLUDE]: {
          type: 'array',
          items: {
            type: 'string',
            minLength: 1,
          },
          description:
            'Optional. Glob patterns for files/directories to exclude. Added to default excludes if useDefaultExcludes is true. Example: "**/*.log", "temp/"',
          default: [],
        },
        [READ_MANY_PARAM_RECURSIVE]: {
          type: 'boolean',
          description:
            'Optional. Whether to search recursively (primarily controlled by `**` in glob patterns). Defaults to true.',
          default: true,
        },

        [READ_MANY_PARAM_USE_DEFAULT_EXCLUDES]: {
          type: 'boolean',
          description:
            'Optional. Whether to apply a list of default exclusion patterns (e.g., node_modules, .git, binary files). Defaults to true.',
          default: true,
        },
        [PARAM_FILE_FILTERING_OPTIONS]: {
          description:
            'Whether to respect ignore patterns from .gitignore or .geminiignore',
          type: 'object',
          properties: {
            [PARAM_RESPECT_GIT_IGNORE]: {
              description:
                'Optional: Whether to respect .gitignore patterns when listing files. Only available in git repositories. Defaults to true.',
              type: 'boolean',
            },
            [PARAM_RESPECT_GEMINI_IGNORE]: {
              description:
                'Optional: Whether to respect .geminiignore patterns when listing files. Defaults to true.',
              type: 'boolean',
            },
          },
        },
      },
      required: [READ_MANY_PARAM_INCLUDE],
    },
  },

  save_memory: {
    name: MEMORY_TOOL_NAME,
    description: `Persists global preferences or facts across ALL future sessions. Use this for recurring instructions like coding styles or tool aliases. Unlike '${WRITE_FILE_TOOL_NAME}', which is for project-specific files, this appends to a global memory file loaded in every workspace. If you are unsure whether a fact should be remembered globally, ask the user first. CRITICAL: Do not use for session-specific context or temporary data.`,
    parametersJsonSchema: {
      type: 'object',
      properties: {
        [MEMORY_PARAM_FACT]: {
          type: 'string',
          description:
            "A concise, global fact or preference (e.g., 'I prefer using tabs'). Do not include local paths or project-specific names.",
        },
      },
      required: [MEMORY_PARAM_FACT],
      additionalProperties: false,
    },
  },

  write_todos: {
    name: WRITE_TODOS_TOOL_NAME,
    description: `This tool can help you list out the current subtasks that are required to be completed for a given user request. The list of subtasks helps you keep track of the current task, organize complex queries and help ensure that you don't miss any steps. With this list, the user can also see the current progress you are making in executing a given task.

Depending on the task complexity, you should first divide a given task into subtasks and then use this tool to list out the subtasks that are required to be completed for a given user request.
Each of the subtasks should be clear and distinct. 

Use this tool for complex queries that require multiple steps. If you find that the request is actually complex after you have started executing the user task, create a todo list and use it. If execution of the user task requires multiple steps, planning and generally is higher complexity than a simple Q&A, use this tool.

DO NOT use this tool for simple tasks that can be completed in less than 2 steps. If the user query is simple and straightforward, do not use the tool. If you can respond with an answer in a single turn then this tool is not required.

## Task state definitions

- pending: Work has not begun on a given subtask.
- in_progress: Marked just prior to beginning work on a given subtask. You should only have one subtask as in_progress at a time.
- completed: Subtask was successfully completed with no errors or issues. If the subtask required more steps to complete, update the todo list with the subtasks. All steps should be identified as completed only when they are completed.
- cancelled: As you update the todo list, some tasks are not required anymore due to the dynamic nature of the task. In this case, mark the subtasks as cancelled.
- blocked: Subtask is blocked and cannot be completed at this time.


## Methodology for using this tool
1. Use this todo list as soon as you receive a user request based on the complexity of the task.
2. Keep track of every subtask that you update the list with.
3. Mark a subtask as in_progress before you begin working on it. You should only have one subtask as in_progress at a time.
4. Update the subtask list as you proceed in executing the task. The subtask list is not static and should reflect your progress and current plans, which may evolve as you acquire new information.
5. Mark a subtask as completed when you have completed it.
6. Mark a subtask as cancelled if the subtask is no longer needed.
7. You must update the todo list as soon as you start, stop or cancel a subtask. Don't batch or wait to update the todo list.


## Examples of When to Use the Todo List

<example>
User request: Create a website with a React for creating fancy logos using gemini-2.5-flash-image

ToDo list created by the agent:
1. Initialize a new React project environment (e.g., using Vite).
2. Design and build the core UI components: a text input (prompt field) for the logo description, selection controls for style parameters (if the API supports them), and an image preview area.
3. Implement state management (e.g., React Context or Zustand) to manage the user's input prompt, the API loading status (pending, success, error), and the resulting image data.
4. Create an API service module within the React app (using "fetch" or "axios") to securely format and send the prompt data via an HTTP POST request to the specified "gemini-2.5-flash-image" (Gemini model) endpoint.
5. Implement asynchronous logic to handle the API call: show a loading indicator while the request is pending, retrieve the generated image (e.g., as a URL or base64 string) upon success, and display any errors.
6. Display the returned "fancy logo" from the API response in the preview area component.
7. Add functionality (e.g., a "Download" button) to allow the user to save the generated image file.
8. Deploy the application to a web server or hosting platform.

<reasoning>
The agent used the todo list to break the task into distinct, manageable steps:
1. Building an entire interactive web application from scratch is a highly complex, multi-stage process involving setup, UI development, logic integration, and deployment.
2. The agent inferred the core functionality required for a "logo creator," such as UI controls for customization (Task 3) and an export feature (Task 7), which must be tracked as distinct goals.
3. The agent rightly inferred the requirement of an API service model for interacting with the image model endpoint.
</reasoning>
</example>


## Examples of When NOT to Use the Todo List

<example>
User request: Ensure that the test <test file> passes.

Agent:
<Goes into a loop of running the test, identifying errors, and updating the code until the test passes.>

<reasoning>
The agent did not use the todo list because this task could be completed by a tight loop of execute test->edit->execute test.
</reasoning>
</example>`,
    parametersJsonSchema: {
      type: 'object',
      properties: {
        [TODOS_PARAM_TODOS]: {
          type: 'array',
          description:
            'The complete list of todo items. This will replace the existing list.',
          items: {
            type: 'object',
            description: 'A single todo item.',
            properties: {
              [TODOS_ITEM_PARAM_DESCRIPTION]: {
                type: 'string',
                description: 'The description of the task.',
              },
              [TODOS_ITEM_PARAM_STATUS]: {
                type: 'string',
                description: 'The current status of the task.',
                enum: [
                  'pending',
                  'in_progress',
                  'completed',
                  'cancelled',
                  'blocked',
                ],
              },
            },
            required: [TODOS_ITEM_PARAM_DESCRIPTION, TODOS_ITEM_PARAM_STATUS],
            additionalProperties: false,
          },
        },
      },
      required: [TODOS_PARAM_TODOS],
      additionalProperties: false,
    },
  },

  get_internal_docs: {
    name: GET_INTERNAL_DOCS_TOOL_NAME,
    description:
      'Returns the content of Gemini CLI internal documentation files. If no path is provided, returns a list of all available documentation paths.',
    parametersJsonSchema: {
      type: 'object',
      properties: {
        [DOCS_PARAM_PATH]: {
          description:
            "The relative path to the documentation file (e.g., 'cli/commands.md'). If omitted, lists all available documentation.",
          type: 'string',
        },
      },
    },
  },

  ask_user: {
    name: ASK_USER_TOOL_NAME,
    description:
      'Ask the user one or more questions to gather preferences, clarify requirements, or make decisions. When using this tool, prefer providing multiple-choice options with detailed descriptions and enable multi-select where appropriate to provide maximum flexibility.',
    parametersJsonSchema: {
      type: 'object',
      required: [ASK_USER_PARAM_QUESTIONS],
      properties: {
        [ASK_USER_PARAM_QUESTIONS]: {
          type: 'array',
          minItems: 1,
          maxItems: 4,
          items: {
            type: 'object',
            required: [
              ASK_USER_QUESTION_PARAM_QUESTION,
              ASK_USER_QUESTION_PARAM_HEADER,
              ASK_USER_QUESTION_PARAM_TYPE,
            ],
            properties: {
              [ASK_USER_QUESTION_PARAM_QUESTION]: {
                type: 'string',
                description:
                  'The complete question to ask the user. Should be clear, specific, and end with a question mark.',
              },
              [ASK_USER_QUESTION_PARAM_HEADER]: {
                type: 'string',
                description:
                  'Very short label displayed as a chip/tag. Use abbreviations: "Auth" not "Authentication", "Config" not "Configuration". Examples: "Auth method", "Library", "Approach", "Database".',
              },
              [ASK_USER_QUESTION_PARAM_TYPE]: {
                type: 'string',
                enum: ['choice', 'text', 'yesno'],
                default: 'choice',
                description:
                  "Question type: 'choice' (default) for multiple-choice with options, 'text' for free-form input, 'yesno' for Yes/No confirmation.",
              },
              [ASK_USER_QUESTION_PARAM_OPTIONS]: {
                type: 'array',
                description:
                  "The selectable choices for 'choice' type questions. Provide 2-4 options. An 'Other' option is automatically added. Not needed for 'text' or 'yesno' types.",
                items: {
                  type: 'object',
                  required: [
                    ASK_USER_OPTION_PARAM_LABEL,
                    ASK_USER_OPTION_PARAM_DESCRIPTION,
                  ],
                  properties: {
                    [ASK_USER_OPTION_PARAM_LABEL]: {
                      type: 'string',
                      description:
                        'The display text for this option (1-5 words). Example: "OAuth 2.0"',
                    },
                    [ASK_USER_OPTION_PARAM_DESCRIPTION]: {
                      type: 'string',
                      description:
                        'Brief explanation of this option. Example: "Industry standard, supports SSO"',
                    },
                  },
                },
              },
              [ASK_USER_QUESTION_PARAM_MULTI_SELECT]: {
                type: 'boolean',
                description:
                  "Only applies when type='choice'. Set to true to allow selecting multiple options.",
              },
              [ASK_USER_QUESTION_PARAM_PLACEHOLDER]: {
                type: 'string',
                description:
                  "Hint text shown in the input field. For type='text', shown in the main input. For type='choice', shown in the 'Other' custom input.",
              },
            },
          },
        },
      },
    },
  },

  enter_plan_mode: {
    name: ENTER_PLAN_MODE_TOOL_NAME,
    description:
      'Switch to Plan Mode to safely research, design, and plan complex changes using read-only tools.',
    parametersJsonSchema: {
      type: 'object',
      properties: {
        [PLAN_MODE_PARAM_REASON]: {
          type: 'string',
          description:
            'Short reason explaining why you are entering plan mode.',
        },
      },
    },
  },

  exit_plan_mode: () => getExitPlanModeDeclaration(),
  activate_skill: (skillNames) => getActivateSkillDeclaration(skillNames),
  update_topic: getUpdateTopicDeclaration(),
};
