// Copyright 2025 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

module blink.mojom;

import "third_party/blink/public/mojom/tokens/tokens.mojom";
import "url/mojom/origin.mojom";
import "mojo/public/mojom/base/unguessable_token.mojom";

// See ToolAnnotations in model_context_tool.idl for details of this
// data structure.
struct ScriptToolAnnotations {
  bool read_only;
  bool untrusted_content;
  bool consequential;
};

// See ModelContextTool in model_context_tool.idl for details of
// this data structure.
struct ScriptTool {
  // These directly map to the corresponding fields in the web API.
  string name;
  // The optional title for the tool. This can be null if the tool is registered
  // without a title — either imperatively (where the `title` property of
  // `ModelContextTool` is omitted) or declaratively (where the `<form>` lacks
  // a `tooltitle` attribute).
  string? title;
  string description;
  string? input_schema;
  ScriptToolAnnotations? annotations;
  // See the documentation in `model_context.idl` for more about this member.
  array<url.mojom.Origin> exposed_origins;

  // The token of the frame that registered this tool.
  blink.mojom.FrameToken tool_owner_frame_token;
  // The origin of the frame that registered this tool. This can be an opaque
  // origin, however it would only have access to tools on its own origin, as no
  // other document would be able to express its origin in `exposed_origins`
  // above.
  url.mojom.Origin origin;
};

// Interface for the renderer to request actions from the browser related to
// script tools.
interface ScriptToolHost {
  // Pauses the execution of the agent.
  PauseExecution();
};

// Interface implemented by `content::ModelContextUserData` (1:1 with Document),
// for the renderer to request actions from the browser related to WebMCP. See
// https://github.com/webmachinelearning/webmcp.
interface ModelContextHost {
  // Binds the receiver for the browser to notify the renderer about changes in
  // tools.
  BindModelContext(pending_remote<ModelContext> model_context);

  // Registers a WebMCP script tool hosted in the caller document. The
  // registration goes to the browser process, so it can alert other relevant
  // frames in the tree about the new tool.
  RegisterScriptTool(ScriptTool tool) => ();

  // Unregisters a previously-declared tool. When this is called, `name` is
  // guaranteed to match an existing tool; if this invariant is not upheld, the
  // renderer process is killed.
  UnregisterScriptTool(string name);

  // Returns all script tools visible to the caller document, optionally filtered
  // by `from_origins`. If `from_origins` is empty, it defaults to returning
  // only tools that are same-origin with the caller document.
  GetScriptTools(array<url.mojom.Origin> from_origins) => (array<ScriptTool> tools);

  // Executes a ScriptTool hosted in another Document. The tool can be located
  // based on the unique combination of (`tool_owner_frame_token`, `name`), but
  // we pass `expected_target_origin` too, since it is possible that
  // `tool_owner_frame_token` points to a remote frame whose frame tree node's
  // host has changed since tool registration.
  //
  // Note that `success` generally
  // controls whether the caller's Promise resolves or rejects:
  //   - When the Promise returned by the remote tool resolves, then `success`
  //     will be true, and the caller's Promise resolves.
  //   - The same is true in the inverse, for rejection.
  // ... but note that `success` can be false even before the remote tool's
  // response is obtained, e.g., if the browser process failed to locate the
  // tool, or if it was unregistered mid-execution.
  //
  // TODO(https://crbug.com/509555636): Consider making `success` more granular
  // in the error case, perhaps by using `ScriptToolErrorCode`.
  ExecuteRemoteScriptTool(mojo_base.mojom.UnguessableToken invocation_id,
                          blink.mojom.FrameToken tool_owner_frame_token,
                          url.mojom.Origin expected_target_origin,
                          string name,
                          string input_arguments) => (string? result, bool success);

  // Cancels a pending execution of a remote script tool.
  CancelRemoteScriptTool(mojo_base.mojom.UnguessableToken invocation_id);
};

// Interface implemented by `blink::ModelContext` for the browser to notify the
// renderer about changes in tools.
interface ModelContext {
  // Fires the `toolchange` event against the `blink::ModelContext` object.
  NotifyToolChange();

  // Executes a ScriptTool by the name of `name`, hosted in this Document. This
  // invokes JavaScript and obtains a Promise representing the tool result. The
  // tool result is always a string for now; but see https://crbug.com/508306795
  // which tracks the task of changing this.
  //
  // Resolution of the JavaScript Promise results in the callback being called
  // with `success=true`, while rejection results in `success=false`.
  ExecuteScriptTool(mojo_base.mojom.UnguessableToken invocation_id,
                    string name, string input_arguments)
      => (string? result, bool success);

  // Cancels a pending execution of a script tool in this Document.
  CancelScriptTool(mojo_base.mojom.UnguessableToken invocation_id);
};
