diff --git a/index.bs b/index.bs
index f1bcd63..a472c28 100644
--- a/index.bs
+++ b/index.bs
@@ -561,28 +561,105 @@ dictionary ModelContextRegisterToolOptions {
ModelContextClient Interface
-The {{ModelContextClient}} interface represents an [=agent=] executing a tool provided by the site through the {{ModelContext}} API.
+The {{ModelContextClient}} interface represents an [=agent=] executing a tool provided by the site
+through the {{ModelContext}} API.
[Exposed=Window, SecureContext]
interface ModelContextClient {
- Promise requestUserInteraction(UserInteractionCallback callback);
+ Promise requestUserInput(
+ ModelContextUserInputOptions options,
+ optional ModelContextInteractiveCallback callback);
};
-callback UserInteractionCallback = Promise ();
+callback ModelContextInteractiveCallback = Promise ();
+
+enum ModelContextUserInputMode { "interactive", "form", "url" };
+
+enum ModelContextUserInputAction { "accept", "decline", "cancel" };
+
+dictionary ModelContextUserInputOptions {
+ required ModelContextUserInputMode mode;
+ USVString message;
+ object requestedSchema;
+ USVString url;
+ AbortSignal signal;
+};
+
+dictionary ModelContextUserInputResult {
+ required ModelContextUserInputAction action;
+ object content;
+};
- client.{{ModelContextClient/requestUserInteraction(callback)}}
+ result = await client.{{ModelContextClient/requestUserInput(options, callback)|requestUserInput}}({ mode: "interactive" }, callback)
+ -
+
Requests user input using an interactive in-page flow. If the [=agent=] currently has
+ exclusive control of the page (e.g. keyboard and mouse input are locked), then it yields control
+ so the user can interact with the page directly. The callback is invoked to perform the
+ interaction, and the promise resolves with the result of the callback wrapped in a
+ {{ModelContextUserInputResult}}.
+
+
+ result = await client.{{ModelContextClient/requestUserInput(options, callback)|requestUserInput}}({ mode: "form", requestedSchema: { ... } })
-
-
Asynchronously requests user input during the execution of a tool.
+
Requests structured input from the user via a form. The {{ModelContextUserInputOptions/requestedSchema}}
+ describes the data the tool needs as a JSON Schema [[!JSON-SCHEMA]] object. The [=agent=]
+ presents a form to the user through its own user interface, collects the information, and returns it to the tool.
+
- The callback function is invoked to perform the user interaction (e.g., showing a confirmation dialog), and the promise resolves with the result of the callback.
+
result = await client.{{ModelContextClient/requestUserInput(options, callback)|requestUserInput}}({ mode: "url", url: "https://example.com/authenticate" })
+ -
+
Requests the user navigate to a URL for an out-of-band interaction. The [=agent=] presents
+ the URL to the user and the promise resolves with a {{ModelContextUserInputResult}} indicating whether the
+ user accepted, declined, or canceled the navigation prompt. This mode is intended for sensitive
+ flows (e.g., authentication, payment) where user-provided data must not flow through the
+ [=agent=]. The tool detects completion and retrieves data through out-of-band means (e.g., a site
+ backend callback).
+The {{ModelContextUserInputOptions}} dictionary configures the elicitation request:
+
+
+ : mode
+ :: The elicitation mode. One of "{{ModelContextUserInputMode/interactive}}", "{{ModelContextUserInputMode/form}}", or
+ "{{ModelContextUserInputMode/url}}".
+
+ : message
+ :: A human-readable message explaining why the interaction is needed. The [=agent=] may surface
+ this to the user, or provide a reasonable default if omitted (e.g., "example.com needs your input").
+
+ : requestedSchema
+ :: A JSON Schema [[!JSON-SCHEMA]] object describing the structure of the expected response. Only
+ used in "{{ModelContextUserInputMode/form}}" mode. The schema is restricted to flat objects with primitive
+ properties (string, number, integer, boolean, and enum) to simplify form rendering.
+
+ : url
+ :: The URL the user should navigate to. Required for "{{ModelContextUserInputMode/url}}" mode.
+
+ : signal
+ :: An {{AbortSignal}} that aborts the pending request when triggered.
+
+
+The {{ModelContextUserInputResult}} dictionary describes the outcome of a user input request:
+
+
+ : action
+ :: The user's response action:
+ - "{{ModelContextUserInputAction/accept}}": The user provided the requested input.
+ - "{{ModelContextUserInputAction/decline}}": The user explicitly declined the request.
+ - "{{ModelContextUserInputAction/cancel}}": The request was dismissed or timed out.
+
+ : content
+ :: The user-provided data. Present when {{ModelContextUserInputResult/action}} is "{{ModelContextUserInputAction/accept}}"
+ and the mode is "{{ModelContextUserInputMode/interactive}}" or "{{ModelContextUserInputMode/form}}". For
+ "{{ModelContextUserInputMode/url}}" mode, data is exchanged out-of-band and this field is not used.
+
+
-The requestUserInteraction(callback) method steps are:
+The requestUserInput(options, callback) method steps are:
1. TODO: fill this out.