import { z } from 'zod';
import { defineTool, } from '../toolDefinition.js';
import { AgentToolNames } from './agentToolNames.js';
export const executeJavascriptArgumentsSchema = z.object({
    description: z.string().max(100).describe('A brief description of what this step does (max 100 characters)'),
    reasoning: z
        .string()
        .optional()
        .describe('Brief explanation of why this action is being taken and what it aims to achieve'),
    snippet_name: z.string().describe('A short descriptive name for this snippet'),
    snippet_description: z.string().describe('Description of what this snippet does and why'),
    snippet_body: z
        .string()
        .describe('The full snippet function body. Must follow the format: function mablJavaScriptStep(mablInputs, callback) { ... callback(result); }'),
    parameters: z
        .record(z.string(), z.string())
        .optional()
        .describe('Optional input parameters for the snippet as a JSON object. Keys are parameter names and values are existing test variables that will be passed into the snippet. The snippet can access these via mablInputs. Values can reference variables using {{@variableName}} syntax.'),
    save_result_to_variable: z
        .string()
        .optional()
        .describe('Optional variable name to save the snippet result to. Variable names should only contain alphanumeric characters and underscores.'),
    record_step: z
        .boolean()
        .optional()
        .describe('Whether to save this snippet as a step in the test. Defaults to true. ' +
        'Set to false to run the snippet WITHOUT adding a step: it executes against ' +
        'the live page and its return value comes back in `result`, but nothing is ' +
        'persisted to the test. Use this to inspect the page or compute a value you ' +
        "need to make a decision (e.g. read an element's outerHTML to choose a robust " +
        'selector) instead of creating a snippet step and deleting it afterward. When ' +
        'record_step is false, do not set save_result_to_variable (there is no step to ' +
        'attach a variable to; read the value from `result`). Only meaningful during ' +
        'test authoring.'),
});
export const executeJavascriptResponseSchema = z.object({
    success: z.boolean().describe('Whether the snippet executed successfully'),
    message: z.string().optional().describe('Any message or error from the snippet execution'),
    result: z.any().optional().describe('The return value from the snippet, if any'),
    new_screenshot: z.string().optional().describe('Base64-encoded PNG screenshot of the page after snippet execution'),
    current_url: z.string().optional().describe('The current URL after snippet execution'),
    variable_name: z
        .string()
        .optional()
        .describe('The name of the variable that was created (if save_result_to_variable was specified)'),
    variable_value: z.string().optional().describe('The actual value saved to the variable'),
});
export const ExecuteJavascriptToolDefinition = defineTool({
    name: AgentToolNames.ExecuteJavascript,
    description: `Execute a JavaScript snippet in the browser. The snippet can be used to fix state issues during test recovery or to perform custom actions during test authoring.

The snippet_body must be a JavaScript function with the following signature:
  function mablJavaScriptStep(mablInputs, callback) {
    // Your code here
    callback(result);
  }

Rules:
- The function MUST be named mablJavaScriptStep
- The function MUST call callback(result) with a return value, or throw an error. The value passed to callback() is what is returned as the result of the snippet execution.
- The snippet runs in the browser context (ECMAScript 8) with access to the DOM and browser APIs
- If there is no meaningful return value, call callback(true)
- Do not use require() or import statements
- NEVER create a snippet that simply reads a variable from mablInputs and returns it via callback — this is a no-op. The variable already exists and can be referenced directly with {{@variableName}} syntax in other steps. Snippets must perform real work (DOM manipulation, computation, API calls, etc.).
- When using the parameters argument, those values are passed directly as named function arguments after callback. List them in the function signature and use them directly — do NOT re-declare or re-initialize them inside the function body. Example: function mablJavaScriptStep(mablInputs, callback, userId, itemCount) { ... }

mablInputs:
mablInputs is a read-only object containing variables available in the test. Variable values accessed through mablInputs retain their original type (e.g. an API response body will still be an object, not a string).

Common mablInputs paths:
- mablInputs.variables.user.variable_name - Test-generated variables, data-driven variables, and environment variables
- mablInputs.variables.web.runtime.flow_run_ordinal_index - The loop index
- mablInputs.variables.web.test_run_id - The test run ID
- mablInputs.variables.web.defaults.credentials.username - mabl credentials username
- mablInputs.variables.web.defaults.credentials.password - mabl credentials password

Common use cases:
- Refresh the page: window.location.reload() then callback(true)
- Clear local storage: localStorage.clear() then callback(true)
- Read DOM elements
- Access mabl test variables via mablInputs

Saving Results:
- If the snippet returns a value, you can save it to a variable for later use
- Use save_result_to_variable to specify the variable name
- The variable can then be referenced in subsequent steps using {{@variableName}} syntax

Inspecting without recording a step (test authoring):
- When you only need to READ the page or compute a value to decide what to do next
  (not perform a real test action), set record_step: false.
- The snippet runs and its return value is returned in the 'result' field, but NO step
  is added to the test. This is the right tool for inspection — do not create a snippet
  step and then delete it.
- Example: to read an element's HTML before choosing a robust selector,
  call execute_javascript with record_step: false and a snippet whose callback returns
  document.querySelector('a.edit').outerHTML, then read the 'result' field.
- Do not combine record_step: false with save_result_to_variable. Read the value from
  'result' instead; to persist a value as a variable, use record_step: true.

Example snippet_body:
function mablJavaScriptStep(mablInputs, callback) {
  localStorage.clear();
  sessionStorage.clear();
  window.location.reload();
  callback(true);
}

The client will return a new screenshot after execution to show the updated page state.`,
    argumentsSchema: executeJavascriptArgumentsSchema,
    responseSchema: executeJavascriptResponseSchema,
    // The snippet result is user-written JavaScript returning `z.any()` — it is
    // unbounded and can easily dump the full DOM (a `querySelectorAll('*')` +
    // `innerText` scan captures inline <script>/<style> source of every
    // ancestor). Cap the tool output at ~500 tokens so the model is forced to
    // aggregate on the client (counts, filtered summaries) rather than return
    // raw DOM/text.
    maxOutputChars: 2_000,
});
//# sourceMappingURL=ExecuteJavascriptDefinition.js.map