Writing Assistance APIs

Draft Community Group Report ,

More details about this document
This version:
https://webmachinelearning.github.io/writing-assistance-apis
Issue Tracking:
GitHub
Editor:
Domenic Denicola ( Google )
Not Ready For Implementation

This spec is not yet ready for implementation. It exists in this repository to record the ideas and promote discussion.

Before attempting to implement this spec, please contact the editors.


Abstract

The summarizer, writer, and rewriter APIs provide high-level interfaces to call on a browser or operating system’s built-in language model to help with writing tasks.

Status of this document

This specification was published by the Web Machine Learning Community Group . It is not a W3C Standard nor is it on the W3C Standards Track. Please note that under the W3C Community Contributor License Agreement (CLA) there is a limited opt-out and other conditions apply. Learn more about W3C Community and Business Groups .

1. Introduction

For now, see the explainer .

2. Shared AI APIs and infrastructure

partial interface WindowOrWorkerGlobalScope {
  [Replaceable, SecureContext] readonly attribute AI ai;
};
[Exposed=(Window,Worker), SecureContext]
interface AI {};
[Exposed=(Window,Worker), SecureContext]
interface AICreateMonitor : EventTarget {
  attribute EventHandler ondownloadprogress;
};
callback AICreateMonitorCallback = undefined (AICreateMonitor monitor);
enum AIAvailability {
  "unavailable",
  "downloadable",
  "downloading",
  "available"
};
The
minimum
availability
given
a
list
of
AIAvailability

-or-null
values
availabilities
is:
If
availabilities
contains
null,
then
return
null.
If
availabilities
contains
"
unavailable
",
then
return
"
unavailable
".
If
availabilities
contains
"
downloading
",
then
return
"
downloading
".
If
availabilities
contains
"
downloadable
",
then
return
"
downloadable
".
Return
"
available
".

interface mixin AIDestroyable {
  undefined destroy();
};

Each Every WindowOrWorkerGlobalScope has an AI namespace , an AI object. Upon creation of the WindowOrWorkerGlobalScope object, its AI namespace must be set to a new AI object created in the WindowOrWorkerGlobalScope object’s relevant realm .

The ai getter steps are to return this ’s AI namespace .


Tasks queued by this specification use the AI task source . The following are the event handlers (and their corresponding event handler event types ) that must be supported, as event handler IDL attributes , by all AICreateMonitor objects:

Event handler Event handler event type
ondownloadprogress downloadprogress

Every interface including the AIDestroyable interface mixin has a destruction abort controller , an AbortController , set by the initialize as a destroyable algorithm.

The destruction abort controller is only used internally, as a way of tracking calls to destroy() . Since it is easy to combine multiple AbortSignal s using create a dependent abort signal , this lets us centralize handling of any AbortSignal the web developer provides to specific method calls, with any calls to destroy() .

To initialize as a destroyable an AIDestroyable object destroyable :
  1. Let controller be a new AbortController created in destroyable ’s relevant realm .

  2. Set controller ’s signal to a new AbortSignal created in destroyable ’s relevant realm .

  3. Set destroyable ’s destruction abort controller to controller .

The destroy() method steps are to destroy this given a new " AbortError " DOMException .

To destroy an AIDestroyable destroyable , given a JavaScript value reason :
  1. Signal abort given destroyable ’s destruction abort controller and reason .

  2. The user agent should release any resources associated with destroyable , such as AI models loaded to support its operation, as long as those resources are not needed for other ongoing operations.

3. The summarizer API

partial interface AI {
  readonly attribute AISummarizerFactory summarizer;
};
[Exposed=(Window,Worker), SecureContext]
interface AISummarizerFactory {
  Promise<AISummarizer> create(optional AISummarizerCreateOptions options = {});
   = {});

  Promise<AIAvailability> availability(optional AISummarizerCreateCoreOptions options = {});
};
[Exposed=(Window,Worker), SecureContext]
interface AISummarizer {
  Promise<DOMString> summarize(
    DOMString input,
    optional AISummarizerSummarizeOptions options = {}
  );
  ReadableStream summarizeStreaming(
    DOMString input,
    optional AISummarizerSummarizeOptions options = {}
  );
  readonly attribute DOMString sharedContext;
  readonly attribute AISummarizerType type;
  readonly attribute AISummarizerFormat format;
  readonly attribute AISummarizerLength length;
  readonly attribute FrozenArray<DOMString>? expectedInputLanguages;
  readonly attribute FrozenArray<DOMString>? expectedContextLanguages;
  readonly attribute DOMString? outputLanguage;
  ();

};
AISummarizer includes AIDestroyable;
dictionary AISummarizerCreateCoreOptions {
  AISummarizerType type = "key-points";
  AISummarizerFormat format = "markdown";
  AISummarizerLength length = "short";
  sequence<DOMString> expectedInputLanguages;
  sequence<DOMString> expectedContextLanguages;
  DOMString outputLanguage;
};
dictionary AISummarizerCreateOptions : AISummarizerCreateCoreOptions {
  ;

  AbortSignal signal;
  AICreateMonitorCallback monitor;
  DOMString sharedContext;
};
dictionary AISummarizerSummarizeOptions {
  ;

  AbortSignal signal;
  DOMString context;
};
enum AISummarizerType { "tl;dr", "teaser", "key-points", "headline" };
enum AISummarizerFormat { "plain-text", "markdown" };
enum AISummarizerLength { "short", "medium", "long" };

Each Every AI has an summarizer factory , an AISummarizerFactory object. Upon creation of the AI object, its summarizer factory must be set to a new AISummarizerFactory object created in the AI object’s relevant realm .

The summarizer getter steps are to return this ’s summarizer factory .

3.1. Creation

The create( options ) method steps are:
  1. If this ’s relevant global object is a Window whose associated Document is not fully active , then return a promise rejected with an " InvalidStateError " DOMException .

  2. If options [" signal "] exists and is aborted , then return a promise rejected with options [" signal "]'s abort reason .

  3. Validate and canonicalize language tags summarizer options given options . If this throws an exception e , catch it, and return a promise rejected with e .

    This can mutate options .

  4. Let fireProgressEvent be Return the result of creating an algorithm taking two arguments that does nothing. If options [" monitor "] exists , then: Let monitor be a new AICreateMonitor AI model object created in given this ’s relevant realm . Invoke , options [" monitor "] with « monitor » and " rethrow ". If this throws an exception e , catch it, computing summarizer options availability , download the summarization model , initialize the summarization model , and return create a promise rejected with e . Set fireProgressEvent to an algorithm taking argument loaded , which performs the following steps: Assert : this algorithm is running in parallel summarizer object .

    Queue a global task on the AI task source
To validate and canonicalize summarizer options given this ’s relevant global object to perform the following steps: Fire an event named downloadprogress AISummarizerCreateCoreOptions at monitor options , using ProgressEvent , with perform the loaded attribute initialized to following steps. They mutate loaded , the total attribute initialized options in place to 1, canonicalize and the lengthComputable attribute initialized to true. This assumes whatwg/xhr#394 is merged so that passing non-integer values for deduplicate language tags, and throw a loaded TypeError works as expected. Let abortedDuringDownload be false. This variable will be written to from the event loop , but read from in parallel . if any are invalid.
  1. If options [" signal "] exists , then add the following abort steps Validate and canonicalize language tags to given options [" and " signal expectedInputLanguages "]: Set abortedDuringDownload to true. Let promise be a new promise created in this ’s relevant realm . ".

  2. In parallel : Let availability be the result of computing summarizer options availability Validate and canonicalize language tags given options . This can mutate options . Switch on availability : null Reject promise with an and " UnknownError expectedContextLanguages " DOMException . Abort these steps. ".

    " unavailable "
  3. Reject Validate and canonicalize language tags given promise options with a and " NotSupportedError outputLanguage " DOMException . Abort these steps. ".

" available " If initializing
To download the summarization model given promise and options returns false, then abort these steps. Perform fireProgressEvent given 0. Perform fireProgressEvent given 1. Finalize summarizer creation , given promise and options . " downloading " " an downloadable AISummarizerCreateCoreOptions " options :
  1. If availability is " downloadable ", then initiate Assert : these steps are running in parallel .

  2. Initiate the download process for everything the user agent needs to summarize text according to options . Run the following steps, but abort when abortedDuringDownload becomes true: Wait This could include a base AI model, fine-tunings for the total number of bytes to be downloaded to become determined, and let that number be totalBytes . Let lastProgressTime be the monotonic clock ’s unsafe current time . Perform fireProgressEvent given 0. While true: If one or more bytes have been downloaded, then: If the monotonic clock ’s unsafe current time minus lastProgressTime is greater than 50 ms, then: Let bytesSoFar be the number of bytes downloaded so far. Assert : bytesSoFar is greater than 0 and less than specific languages or equal to totalBytes . Let rawProgressFraction be bytesSoFar divided by totalBytes . Let progressFraction be floor ( rawProgressFraction × 65,536) ÷ 65,536. Perform fireProgressEvent given progressFraction . We use a fraction, instead of firing a progress event with the number of bytes downloaded, to avoid giving precise information about the size of the model option values, or other material being downloaded. progressFraction is calculated from rawProgressFraction to give a precision of one part in 2 16 . This ensures that over most internet speeds and with most model sizes, the loaded value will be different from the previous one that was fired ~50 milliseconds ago. Full calculation Assume a 5 GiB download size, and a 20 Mbps download speed (chosen as a number on the lower range from this source ). Then, downloading 5 GiB will take: 5  GiB × 2 30  bytes GiB × 8  bits bytes ÷ 20 × 10 6  bits s × 1000  ms s ÷ 50  ms interval = 49,950  intervals Rounding up to the nearest power of two gives a conservative estimate of 65,536 fifty millisecond intervals, so we want to give progress to 1 part in 2 16 . resources.

  3. If bytesSoFar equals totalBytes , then break . Since this is the only exit condition for the loop, we are guaranteed to fire a downloadprogress event for the 100% mark. Set lastProgressTime to the monotonic clock ’s unsafe current time . Otherwise, if downloading has failed and download process cannot continue, then: Queue a global task on the AI task source given this ’s relevant global object to reject promise with a " NetworkError " DOMException . Abort these steps. If aborted , then: Queue a global task on the AI task source given this ’s relevant global object to perform the following steps: Assert : options [" signal "]'s is aborted . Reject promise with options [" signal "]'s abort reason . Abort these steps. If initializing the summarization model given promise and options returns false, be started for any reason, then abort these steps. Finalize summarizer creation given promise and options . return false.

  4. Return promise . true.

To initialize the summarization model , given a Promise promise and an AISummarizerCreateOptions options :
  1. Assert : these steps are running in parallel .

  2. Perform any necessary initialization operations for the AI model backing the user agent ’s agent’s summarization capabilities.

    This could include loading the model into memory, loading options [" sharedContext "] into the model’s context window, or loading any fine-tunings necessary to support the other options expressed by options .

  3. If initialization failed for any reason, then: Queue a global task on the AI task source given promise ’s relevant global object to reject promise with an " OperationError " DOMException . Return then return false.

  4. Return true.

To finalize create a summarizer creation object , given a Promise realm promise realm and an AISummarizerCreateOptions options :
  1. Assert : these steps are running in parallel . Queue a global task on the AI task source given promise realm ’s relevant global object to perform the following steps: If options [" signal "] exists and is aborted , then: Reject promise with options [" signal surrounding agent "]'s abort reason . Abort these steps. This check is necessary in case any code running on the ’s event loop caused the AbortSignal to become aborted before this task ran. .

  2. Let summarizer be Return a new AISummarizer object, created in promise ’s relevant realm , , with

    shared context

    options [" sharedContext "] if it exists ; otherwise null

    summary type

    options [" type "]

    summary format

    options [" format "]

    summary length

    options [" length "]

    expected input languages

    the result of creating a frozen array given options [" expectedInputLanguages "] if it is not empty ; otherwise null

    expected context languages

    the result of creating a frozen array given options [" expectedContextLanguages "] if it is not empty ; otherwise null

    output language

    options [" outputLanguage "] if it exists ; otherwise null

    If options [" signal "] exists , then add the following abort steps to options [" signal "]: Destroy summarizer with options [" signal "]'s abort reason . Resolve promise with summarizer . To validate and canonicalize language tags given an AISummarizerCreateCoreOptions options , perform the following steps. They mutate options in place to canonicalize and deduplicate language tags, and throw a TypeError if any are invalid. Let expectedInputLanguages be an empty ordered set . If options [" expectedInputLanguages "] exists , then for each languageTag of options [" expectedInputLanguages "]: If IsStructurallyValidLanguageTag ( languageTag ) is false, then throw a TypeError . Append CanonicalizeUnicodeLocaleId ( languageTag ) to expectedInputLanguages . Set options [" expectedInputLanguages "] to expectedInputLanguages . Let expectedContextLanguages be an empty ordered set . If options [" expectedContextLanguages "] exists , then for each languageTag of options [" expectedContextLanguages "]: If IsStructurallyValidLanguageTag ( languageTag ) is false, then throw a TypeError . Append CanonicalizeUnicodeLocaleId ( languageTag ) to expectedContextLanguages . Set options [" expectedContextLanguages "] to expectedContextLanguages . If options [" outputLanguage "] exists , then: If IsStructurallyValidLanguageTag ( options [" outputLanguage "]) is false, then throw a TypeError . Set options [" outputLanguage "] to CanonicalizeUnicodeLocaleId ( options [" outputLanguage "]).

3.2. Availability

The availability( options ) method steps are:
  1. If this ’s relevant global object is a Window whose associated Document is not fully active , then return a promise rejected with an " InvalidStateError " DOMException .

  2. Validate and canonicalize language tags summarizer options given options .

  3. Let promise be a new promise created in this ’s relevant realm .

  4. In parallel :

    1. Let availability be the result of computing summarizer options availability given options .

    2. Queue a global task on the AI task source given this ’s relevant global object to perform the following steps:

      1. If availability is null, then reject promise with an " UnknownError " DOMException .

      2. Otherwise, resolve promise with availability .

To compute summarizer options availability given an AISummarizerCreateCoreOptions options , perform the following steps. They return either an AIAvailability value or null, and they mutate options in place to update language tags to their best-fit matches.
  1. Assert : this algorithm is running in parallel .

  2. Let availability be the summarizer non-language options availability given options [" type "], options [" format "], and options [" length "].

  3. Let languageAvailabilities be the summarizer language availabilities .

  4. Let inputLanguageAvailability be the result of computing summarizer language availability given options [" expectedInputLanguages "] and languageAvailabilities ’s input languages .

  5. Let contextLanguagesAvailability be the result of computing summarizer language availability given options [" expectedContextLanguages "] and languageAvailabilities ’s context languages .

  6. Let outputLanguagesList be « options [" outputLanguage "] ».

  7. Let outputLanguageAvailability be the result of computing summarizer language availability given outputLanguagesList and languageAvailabilities ’s output languages .

  8. Set options [" outputLanguage "] to outputLanguagesList [0].

  9. Return the minimum availability given « availability , inputLanguageAvailability , contextLanguagesAvailability , outputLanguageAvailability ».

To compute summarizer language availability given an ordered set of strings requestedLanguages and a map from AIAvailability values to sets of strings availabilities , perform the following steps. They return an AIAvailability value, and they mutate requestedLanguages in place to update language tags to their best-fit matches.
  1. For each languageTag of requestedLanguages :

    1. For each availabilityToCheck of « " available ", " downloading ", " downloadable " »:

      1. Let bestMatch be LookupMatchingLocaleByBestFit ( availabilities [ availabilityToCheck ], languageTag ).

      2. If bestMatch is not undefined, then:

        1. Replace languageTag with bestMatch .[[locale]] in requestedLanguages .

        2. Return availabilityToCheck .

    2. Return " unavailable ".

The summarizer non-language options availability , given a AISummarizerType type , AISummarizerFormat format , and an AISummarizerLength length , is given by the following steps. They return an AIAvailability value or null.
  1. Assert : this algorithm is running in parallel .

  2. If there is some error attempting to determine whether the user agent supports summarizing text, which the user agent believes to be transient (such that re-querying the summarizer non-language options availability could stop producing such an error), then return null.

  3. If the user agent supports summarizing text into the type of summary described by type , in the format described by format , and with the length guidance given by length without performing any downloading operations, then return " available ".

  4. If the user agent believes it can summarize text according to type , format , and length , but only after finishing a download (e.g., of an AI model or fine-tuning) that is already ongoing, then return " downloadable ".

  5. If the user agent believes it can summarize text according to type , format , and length , but only after performing a download (e.g., of an AI model or fine-tuning), then return " downloadable ".

  6. Otherwise, return " unavailable ".

A language availabilities is a struct with the following items :

All of these items are maps from AIAvailability values to sets of strings representing Unicode canonicalized locale identifiers , initially empty maps. Their keys will always be one of " downloading ", " downloadable ", or " available " (i.e., they will never be " unavailable "). [ECMA-402]

The summarizer language availabilities are given by the following steps. They return a language availabilities or null.
  1. Assert : this algorithm is running in parallel .

  2. If there is some error attempting to determine whether the user agent supports summarizing text, which the user agent believes to be transient (such that re-querying the summarizer language availabilities could stop producing such an error), then return null.

  3. Let availabilities be a language availabilities .

  4. Fill language availabilities given availabilities ’s input languages and the purpose of summarizing text written in that language.

  5. Fill language availabilities given availabilities ’s context languages and the purpose of summarizing text using web-developer provided context information written in that language.

  6. Fill language availabilities given availabilities ’s output languages and the purpose of producing text summaries in that language.

  7. Return availabilities .

To fill language availabilities given a map languagesMap and a description of the purpose for which we’re checking language availability, perform the following steps: availability:
  1. Set languagesMap [" available "], languagesMap [" downloading "], and languagesMap [" downloadable "] to empty sets .

  2. For each human language languageTag , represented as a Unicode canonicalized locale identifier , for which the user agent supports purpose , without performing any downloading operations:

    1. Append languageTag to languagesMap [" available "].

  3. For each human language languageTag , represented as a Unicode canonicalized locale identifier , for which the user agent is currently downloading material (e.g., an AI model or fine-tuning) to support purpose :

    1. Append languageTag to languagesMap [" downloading "].

  4. For each human language languageTag , represented as a Unicode canonicalized locale identifier , for which the user agent believes it can support purpose , but only after performing a not-currently-ongoing download (e.g., of an AI model or fine-tuning):

    1. Append languageTag to languagesMap [" downloadable "].

  5. Assert : languagesMap [" available "], languagesMap [" downloading "], and languagesMap [" downloadable "] are disjoint.

  6. If the union of languagesMap [" available "], languagesMap [" downloading "], and languagesMap [" downloadable "] does not meet the language tag set completeness rules , then:

    1. Let missingLanguageTags be the set of missing language tags necessary to meet the language tag set completeness rules .

    2. For each languageTag of missingLanguageTags :

      1. Append languageTag to one of the three sets. Which of the sets to append to is implementation-defined , and should be guided by considerations similar to that of LookupMatchingLocaleByBestFit in terms of keeping "best fallback languages" together.

The language tag set completeness rules state that for every item languageTag , if languageTag has more than one subtag, then the set must also contain a less narrow language tag with the same language subtag and a strict subset of the same following subtags (i.e., omitting one or more).

This definition is intended to align with that of [[AvailableLocales]] in ECMAScript Internationalization API Specification . [ECMA-402]

This means that if an implementation supports summarization of " de-DE " input text, it will also count as supporting " de " input text.

The converse direction is supported not by the language tag set completeness rules , but instead by the use of LookupMatchingLocaleByBestFit , which ensures that if an implementation supports summarizing " de " input text, it also counts as supporting summarization of " de-CH ", " de-Latn-CH ", etc.

A common setup seen in today’s software is to support two types of written Chinese: "traditional Chinese" and "simplified Chinese". Let’s suppose that the user agent supports summarizing text written in traditional Chinese with no downloads, and simplified Chinese after a download.

One way this could be implemented would be for summarizer language availabilities to return that " zh-Hant " is in the input languages [" available "] set, and " zh " and " zh-Hans " are in the input languages [" downloadable "] set. This return value conforms to the requirements of the language tag set completeness rules , in ensuring that " zh " is present. Per the "should"-level guidance , the implementation has determined that " zh " belongs in the set of downloadable input languages, with " zh-Hans ", instead of in the set of available input languages, with " zh-Hant ".

Combined with the use of LookupMatchingLocaleByBestFit , this means availability() will give the following answers:

function a(languageTag) {
  return ai.summarizer.availability({
    expectedInputLanguages: [languageTag]
  });
}
inputLangAvailability
inputLangAvailability
inputLangAvailability

await a("zh") === "downloadable";
await a("zh-Hant") === "available";
await a("zh-Hans") === "downloadable";
inputLangAvailability
inputLangAvailability
inputLangAvailability

await a("zh-TW") === "available";      // zh-TW will best-fit to zh-Hant
await a("zh-HK") === "available";      // zh-HK will best-fit to zh-Hant
await a("zh-CN") === "downloadable";   // zh-CN will best-fit to zh-Hans
inputLangAvailability
inputLangAvailability

await a("zh-BR") === "downloadable";   // zh-BR will best-fit to zh
await a("zh-Kana") === "downloadable"; // zh-Kana will best-fit to zh

3.3. The AISummarizer class

Every AISummarizer has a shared context , a string -or-null, set during creation.

Every AISummarizer has a summary type , an AISummarizerType , set during creation.

Every AISummarizer has a summary format , an AISummarizerFormat , set during creation.

Every AISummarizer has a summary length , an AISummarizerLength , set during creation.

Every AISummarizer has an expected input languages , a FrozenArray < DOMString > or null, set during creation.

Every AISummarizer has an expected context languages , a FrozenArray < DOMString > or null, set during creation.

Every AISummarizer has an output language , a string or null, set during creation.

Every AISummarizer has a destruction reason , a JavaScript value, initially undefined. Every AISummarizer has a destroyed boolean, initially false. This value is separate from the destruction reason so that it can be read from in parallel during the summarization process.

The sharedContext getter steps are to return this ’s shared context .

The type getter steps are to return this ’s summary type .

The format getter steps are to return this ’s summary format .

The length getter steps are to return this ’s summary length .

The expectedInputLanguages getter steps are to return this ’s expected input languages .

The expectedContextLanguages getter steps are to return this ’s expected context languages .

The outputLanguage getter steps are to return this ’s output language .


The summarize( input , options ) method steps are:
  1. If this ’s relevant global object is a Window whose associated Document is not fully active , then return a promise rejected with an " InvalidStateError " DOMException . If this ’s destroyed is true, then return a promise rejected with this ’s destruction reason . If options [" signal "] exists and is aborted , then return a promise rejected with options [" signal "]'s abort reason . Let abortedDuringSummarization be false. This variable will be written to from the event loop , but read from in parallel . If options [" signal "] exists , then add the following abort steps to options [" signal "]: Set abortedDuringSummarization to true. Let promise be a new promise created in this ’s relevant realm . Let context be options [" context "] if it exists ; otherwise null.

  2. In parallel : Let summary operation be the empty string. Let an algorithm step which takes arguments chunkProduced be the following steps given a string chunk : Queue a global task on the AI task source given this ’s relevant global object to perform the following steps: If abortedDuringSummarization is true, then: Reject promise with options [" signal "]'s abort reason . Abort these steps. If this ’s destroyed is true, then: Reject promise with this ’s destruction reason . Abort these steps. Append chunk to summary . Let , done be the following steps: Queue a global task on the AI task source given this ’s relevant global object to perform the following steps: If abortedDuringSummarization is true, then: Reject promise with options [" signal "]'s abort reason . Abort these steps. If this ’s destroyed is true, then: Reject promise with this ’s destruction reason . Abort these steps. Resolve promise with summary . Let error be the following steps given summarization error information errorInfo : Queue a global task on the AI task source given this ’s relevant global object to perform the following steps: If abortedDuringSummarization is true, then: Reject promise with options [" signal "]'s abort reason . Abort these steps. Let exception be the result of creating a DOMException with name given by errorInfo ’s error name , using , errorInfo ’s error information to populate the message appropriately. Reject promise with exception . Let , and stopProducing be the following steps: Return abortedDuringSummarization . , and Summarize summarizes input given this ’s shared context , context , this ’s summary type , this ’s summary format , this ’s summary length , this ’s output language , chunkProduced , done , error , and stopProducing .

  3. Return the result of getting an aggregated AI model result given this , promise options , and operation .

The summarizeStreaming( input , options ) method steps are:
  1. If this ’s relevant global object is a Window whose associated Document is not fully active , then throw an " InvalidStateError " DOMException . If this ’s destroyed is true, then throw this ’s destruction reason . If options [" signal "] exists and is aborted , then throw options [" signal "]'s abort reason . Let abortedDuringSummarization be false. This variable tracks web developer aborts via the options [" signal "] AbortSignal , which are surfaced as errors. It will be written to from the event loop , but sometimes read from in parallel . If options [" signal "] exists , then add the following abort steps to options [" signal "]: Set abortedDuringSummarization to true. Let stream be a new ReadableStream created in this ’s relevant realm . Let canceledDuringSummarization be false. This variable tracks web developer stream cancelations via stream.cancel() , which are not surfaced as errors. It will be written to from the event loop , but sometimes read from in parallel . Set up stream with cancelAlgorithm set to the following steps (ignoring the reason argument): Set canceledDuringSummarization to true. Let context be options [" context "] if it exists ; otherwise null.

  2. In parallel : Let chunkProduced operation be the following steps given a string chunk : Queue a global task on the AI task source given this ’s relevant global object to perform the following steps: If abortedDuringSummarization is true, then: Error stream with options [" signal "]'s abort reason . Abort these steps. If this ’s destroyed is true, then: Error stream with this ’s destruction reason . Abort these steps. Enqueue chunk into an algorithm step which takes arguments stream . Let chunkProduced , done be the following steps: Queue a global task on the AI task source given this ’s relevant global object to perform the following steps: If abortedDuringSummarization is true, then: Error stream with options [" signal "]'s abort reason . Abort these steps. If this ’s destroyed is true, then: Error stream with this ’s destruction reason . Abort these steps. Close stream . Let error be the following steps given summarization error information errorInfo : Queue a global task on the AI task source given this ’s relevant global object to perform the following steps: If abortedDuringSummarization is true, then: Error stream with options [" signal "]'s abort reason . Abort these steps. If this ’s destroyed is true, then: Error stream with this ’s destruction reason . Abort these steps. Let exception be the result of creating a DOMException with name given by errorInfo ’s error name , using , errorInfo ’s error information to populate the message appropriately. Error stream with exception . Let stopProducing be the following steps: If any of abortedDuringSummarization , and canceledDuringSummarization stopProducing , or this ’s destroyed are true, then return true. Return false. and Summarize summarizes input given this ’s shared context , context , this ’s summary type , this ’s summary format , this ’s summary length , this ’s output language , chunkProduced , done , error , and stopProducing .

  3. Return the result of getting a streaming AI model result given this , stream options , and operation .

3.4. Summarization

3.4.1. The algorithm

To summarize given:

perform the following steps:

  1. Assert : this algorithm is running in parallel .

  2. In an implementation-defined manner, subject to the following guidelines, begin the processs of summarizing input into a string.

    If they are non-null, sharedContext and context should be used to aid in the summarization by providing context on how the web developer wishes the input to be summarized.

    If input is the empty string, or otherwise consists of no summarizable content (e.g., only contains whitespace, or control characters), then the resulting summary should be the empty string. In such cases, sharedContext , context , type , format , length , and outputLanguage should be ignored.

    The summarization should conform to the guidance given by type , format , and length , in the definitions of each of their enumeration values.

    If outputLanguage is non-null, the summarization should be in that language. Otherwise, it should be in the language of input (which might not match that of context or sharedContext ). If input contains multiple languages, or the language of input cannot be detected, then either the output language is implementation-defined , or the implementation may treat this as an error, per the guidance in § 3.5 § 3.4.3 Errors .

  3. While true:

    1. Wait for the next chunk of summarization data to be produced, for the summarization process to finish, or for the result of calling stopProducing to become true.

    2. If such a chunk is successfully produced:

      1. Let it be represented as a string chunk .

      2. Perform chunkProduced given chunk .

    3. Otherwise, if the summarization process has finished:

      1. Perform done .

      2. Break .

    4. Otherwise, if stopProducing returns true, then break .

      The caller will handle signaling cancelation or aborting as necessary.
    5. Otherwise, if an error occurred during summarization:

      1. Let the error be represented as summarization error information errorInfo according to the guidance in § 3.5 § 3.4.3 Errors .

      2. Perform error given errorInfo .

      3. Break .

The destroy() method steps are to destroy this given a new " AbortError " DOMException . To destroy an AISummarizer summarizer , given a JavaScript value reason : Set summarizer ’s destroyed to true. Set summarizer ’s destruction reason to reason . The user agent should release any resources associated with summarizer , such as AI models loaded during initialize the summarization model , as long as those resources are not needed for other ongoing operations.

3.4. 3.4.2. Options

The summarize algorithm’s details are implementation-defined , as they are expected to be powered by an AI model. However, it is intended to be controllable by the web developer through the AISummarizerType , AISummarizerFormat , and AISummarizerLength enumerations.

This section gives normative guidance on how the implementation of summarize should use each enumeration value to guide the summarization process.

AISummarizerType values
Value Meaning
" tl;dr "

The summary should be short and to the point, providing a quick overview of the input, suitable for a busy reader.

" teaser "

The summary should focus on the most interesting or intriguing parts of the input, designed to draw the reader in to read more.

" key-points "

The summary should extract the most important points from the input, presented as a bulleted list.

" headline "

The summary should effectively contain the main point of the input in a single sentence, in the format of an article headline.

AISummarizerLength values
Value Meaning
" short "

The guidance is dependent on the value of AISummarizerType :

" tl;dr "
" teaser "

The summary should fit within 1 sentence.

" key-points "

The summary should consist of no more than 3 bullet points.

" headline "

The summary should use no more than 12 words.

" medium "

The guidance is dependent on the value of AISummarizerType :

" tl;dr "
" teaser "

The summary should fit within 1 short paragraph.

" key-points "

The summary should consist of no more than 5 bullet points.

" headline "

The summary should use no more than 17 words.

" long "

The guidance is dependent on the value of AISummarizerType :

" tl;dr "
" teaser "

The summary should fit within 1 paragraph.

" key-points "

The summary should consist of no more than 7 bullet points.

" headline "

The summary should use no more than 22 words.

As with all " should "-level guidance, user agents might not conform perfectly to these. Especially in the case of counting words, it’s expected that language models might not conform perfectly.

AISummarizerFormat values
Value Meaning
" plain-text "

The summary should not contain any formatting or markup language.

" markdown "

The summary should be formatted using the Markdown markup language, ideally as valid CommonMark. [COMMONMARK]

3.5. 3.4.3. Errors A summarization error information is a struct with the following items : error name a string that will be used for the DOMException ’s name . error information other information necessary to create a useful DOMException for the web developer. (Typically, just an exception message.)

When summarization fails, the following possible reasons may be surfaced to the web developer. This table lists the possible DOMException names and the cases in which an implementation should use them:

DOMException name Scenarios
" NotAllowedError "

Summarization is disabled by user choice or user agent policy.

" NotReadableError "

The summarization output was filtered by the user agent, e.g., because it was detected to be harmful, inaccurate, or nonsensical.

" NotSupportedError "

The input to be summarized, or the context to be provided, was in a language that the user agent does not support, or was not provided properly in the call to create() .

The summarization output ended up being in a language that the user agent does not support (e.g., because the user agent has not performed sufficient quality control tests on that output language), or was not provided properly in the call to create() .

The outputLanguage option was not set, and the language of the input text could not be determined, so the user agent did not have a good output language default available.

" QuotaExceededError "

The input to be summarized was too large for the user agent to handle.

" UnknownError "

All other scenarios, or if the user agent would prefer not to disclose the failure reason.

This table does not give the complete list of exceptions that can be surfaced by summarizer.summarize() and summarizer.summarizeStreaming() . It only contains those which can come from the implementation-defined summarize algorithm.

4. The writer API

Just IDL for now; full spec coming!

[Exposed=(Window,Worker), SecureContext]
interface AIWriterFactory {
   = {});
   = {});

  Promise<AIWriter> create(optional AIWriterCreateOptions options = {});
  Promise<AIAvailability> availability(optional AIWriterCreateCoreOptions options = {});
};
[Exposed=(Window,Worker), SecureContext]
interface AIWriter {
   = {});
   = {});

  Promise<DOMString> write(DOMString writingTask, optional AIWriterWriteOptions options = {});
  ReadableStream writeStreaming(DOMString writingTask, optional AIWriterWriteOptions options = {});
  readonly attribute DOMString sharedContext;
  readonly attribute AIWriterTone tone;
  readonly attribute AIWriterFormat format;
  readonly attribute AIWriterLength length;
  readonly attribute FrozenArray<DOMString>? expectedInputLanguages;
  readonly attribute FrozenArray<DOMString>? expectedContextLanguages;
  readonly attribute DOMString? outputLanguage;
  ();

};
AIWriter includes AIDestroyable;
dictionary AIWriterCreateCoreOptions {
  AIWriterTone tone = "neutral";
  AIWriterFormat format = "markdown";
  AIWriterLength length = "short";
  sequence<DOMString> expectedInputLanguages;
  sequence<DOMString> expectedContextLanguages;
  DOMString outputLanguage;
};
dictionary AIWriterCreateOptions : AIWriterCreateCoreOptions {
  ;

  AbortSignal signal;
  AICreateMonitorCallback monitor;
  DOMString sharedContext;
};
dictionary AIWriterWriteOptions {
  DOMString context;
  ;

  AbortSignal signal;
};
enum AIWriterTone { "formal", "neutral", "casual" };
enum AIWriterFormat { "plain-text", "markdown" };
enum AIWriterLength { "short", "medium", "long" };

5. The rewriter API

Just IDL for now; full spec coming!

[Exposed=(Window,Worker), SecureContext]
interface AIRewriterFactory {
   = {});
   = {});

  Promise<AIRewriter> create(optional AIRewriterCreateOptions options = {});
  Promise<AIAvailability> availability(optional AIRewriterCreateCoreOptions options = {});
};
[Exposed=(Window,Worker), SecureContext]
interface AIRewriter {
   = {});
   = {});

  Promise<DOMString> rewrite(DOMString input, optional AIRewriterRewriteOptions options = {});
  ReadableStream rewriteStreaming(DOMString input, optional AIRewriterRewriteOptions options = {});
  readonly attribute DOMString sharedContext;
  readonly attribute AIRewriterTone tone;
  readonly attribute AIRewriterFormat format;
  readonly attribute AIRewriterLength length;
  readonly attribute FrozenArray<DOMString>? expectedInputLanguages;
  readonly attribute FrozenArray<DOMString>? expectedContextLanguages;
  readonly attribute DOMString? outputLanguage;
  ();

};
AIRewriter includes AIDestroyable;
dictionary AIRewriterCreateCoreOptions {
  AIRewriterTone tone = "as-is";
  AIRewriterFormat format = "as-is";
  AIRewriterLength length = "as-is";
  sequence<DOMString> expectedInputLanguages;
  sequence<DOMString> expectedContextLanguages;
  DOMString outputLanguage;
};
dictionary AIRewriterCreateOptions : AIRewriterCreateCoreOptions {
  ;

  AbortSignal signal;
  AICreateMonitorCallback monitor;
  DOMString sharedContext;
};
dictionary AIRewriterRewriteOptions {
  DOMString context;
  ;

  AbortSignal signal;
};
enum AIRewriterTone { "as-is", "more-formal", "more-casual" };
enum AIRewriterFormat { "as-is", "plain-text", "markdown" };
enum AIRewriterLength { "as-is", "shorter", "longer" };

6. Shared infrastructure

6.1. Creation

To create an AI model object given:

perform the following steps:

  1. Let fireProgressEvent be an algorithm taking two arguments that does nothing.

  2. If options [" monitor "] exists , then:

    1. Let monitor be a new AICreateMonitor created in realm .

    2. Invoke options [" monitor "] with « monitor » and " rethrow ".

      If this throws an exception e , catch it, and return a promise rejected with e .

    3. Set fireProgressEvent to an algorithm taking argument loaded , which performs the following steps:

      1. Assert : this algorithm is running in parallel .

      2. Queue a global task on the AI task source given realm ’s global object to perform the following steps:

        1. Fire an event named downloadprogress at monitor , using ProgressEvent , with the loaded attribute initialized to loaded , the total attribute initialized to 1, and the lengthComputable attribute initialized to true.

          This assumes whatwg/xhr#394 is merged so that passing non-integer values for loaded works as expected.

  3. Let abortedDuringDownload be false.

    This variable will be written to from the event loop , but read from in parallel .

  4. If options [" signal "] exists , then add the following abort steps to options [" signal "]:

    1. Set abortedDuringDownload to true.

  5. Let promise be a new promise created in realm .

  6. In parallel :

    1. Let availability be the result of performing getAvailability given options .

      This can mutate options .

    2. Switch on availability :

    null
    1. Reject promise with an " UnknownError " DOMException .

    2. Abort these steps.

    " unavailable "
    1. Reject promise with a " NotSupportedError " DOMException .

    2. Abort these steps.

    " available "
    1. Initialize and return an AI model object given promise , options , fireProgressEvent , initialize , and create .

    " downloading "
    " downloadable "
    1. If availability is " downloadable ", then let startDownloadResult be the result of performing startDownload given options .

    2. If startDownloadResult is false, then:

      1. Queue a global task on the AI task source given realm ’s global object to reject promise with a " NetworkError " DOMException .

      2. Abort these steps.

    3. Run the following steps, but abort when abortedDuringDownload becomes true:

      1. Wait for the total number of bytes to be downloaded to become determined, and let that number be totalBytes .

      2. Let lastProgressTime be the monotonic clock ’s unsafe current time .

      3. Perform fireProgressEvent given 0.

      4. While true:

        1. If one or more bytes have been downloaded, then:

          1. If the monotonic clock ’s unsafe current time minus lastProgressTime is greater than 50 ms, then:

            1. Let bytesSoFar be the number of bytes downloaded so far.

            2. Assert : bytesSoFar is greater than 0 and less than or equal to totalBytes .

            3. Let rawProgressFraction be bytesSoFar divided by totalBytes .

            4. Let progressFraction be floor ( rawProgressFraction × 65,536) ÷ 65,536.

            5. Perform fireProgressEvent given progressFraction .

              We use a fraction, instead of firing a progress event with the number of bytes downloaded, to avoid giving precise information about the size of the model or other material being downloaded.

              progressFraction is calculated from rawProgressFraction to give a precision of one part in 2 16 . This ensures that over most internet speeds and with most model sizes, the loaded value will be different from the previous one that was fired ~50 milliseconds ago.

              Full calculation

              Assume a 5 GiB download size, and a 20 Mbps download speed (chosen as a number on the lower range from this source ). Then, downloading 5 GiB will take:

              5  GiB × 2 30  bytes GiB × 8  bits bytes ÷ 20 × 10 6  bits s × 1000  ms s ÷ 50  ms interval = 49,950  intervals

              Rounding up to the nearest power of two gives a conservative estimate of 65,536 fifty millisecond intervals, so we want to give progress to 1 part in 2 16 .

            6. If bytesSoFar equals totalBytes , then break .

              Since this is the only exit condition for the loop, we are guaranteed to fire a downloadprogress event for the 100% mark.

            7. Set lastProgressTime to the monotonic clock ’s unsafe current time .

        2. Otherwise, if downloading has failed and cannot continue, then:

          1. Queue a global task on the AI task source given realm ’s global object to reject promise with a " NetworkError " DOMException .

          2. Abort these steps.

    4. If aborted , then:

      1. Queue a global task on the AI task source given realm ’s global object to perform the following steps:

        1. Assert : options [" signal "] is aborted .

        2. Reject promise with options [" signal "]'s abort reason .

      2. Abort these steps.

    5. Initialize and return an AI model object given promise , options , a no-op algorithm, initialize , and create .

  7. Return promise .

To initialize and return an AI model object given a Promise promise , an ordered map options , and algorithms fireProgressEvent , initialize , and create :
  1. Assert : these steps are running in parallel .

  2. Perform fireProgressEvent given 0.

  3. Perform fireProgressEvent given 1.

  4. If performing initialize given options returns false, then:

    1. Queue a global task on the AI task source given promise ’s relevant global object to reject promise with an " OperationError " DOMException .

    2. Return.

  5. Queue a global task on the AI task source given promise ’s relevant global object to perform the following steps:

    1. If options [" signal "] exists and is aborted , then:

      1. Reject promise with options [" signal "]'s abort reason .

      2. Abort these steps.

      This check is necessary in case any code running on the event loop caused the AbortSignal to become aborted before this task ran.

    2. Let model be the result of performing create given promise ’s relevant global object and options .

    3. Assert : model implements an interface that includes AIDestroyable .

    4. Initialize as a destroyable model .

    5. If options [" signal "] exists , then add the following abort steps to options [" signal "]:

      1. Destroy model given options [" signal "]'s abort reason .

    6. Resolve promise with model .

6.2. Obtaining results

An error information is a struct used to communicate error information from in parallel to the event loop . It has the following items :

error name

a string that will be used for the DOMException ’s name .

error information

other information necessary to create a useful DOMException for the web developer. (Typically, just an exception message.)

To get an aggregated AI model result given an AIDestroyable modelObject , an ordered map options , and an algorithm operation :
  1. If modelObject’s relevant global object is a Window whose associated Document is not fully active , then return a promise rejected with an " InvalidStateError " DOMException .

  2. Let signals be « modelObject ’s destruction abort controller ’s signal ».

  3. If options [" signal "] exists , then append it to signals .

  4. Let compositeSignal be the result of creating a dependent abort signal given signals using AbortSignal and modelObject ’s relevant realm .

  5. If compositeSignal is aborted , then return a promise rejected with compositeSignal ’s abort reason .

  6. Let abortedDuringOperation be false.

    This variable will be written to from the event loop , but read from in parallel .

  7. Add the following abort steps to compositeSignal :

    1. Set abortedDuringOperation to true.

  8. Let promise be a new promise created in modelObject ’s relevant realm .

  9. In parallel :

    1. Let result be the empty string.

    2. Let chunkProduced be the following steps given a string chunk :

      1. Queue a global task on the AI task source given modelObject ’s relevant global object to perform the following steps:

        1. If abortedDuringOperation is true, then reject promise with compositeSignal ’s abort reason .

        2. Otherwise, append chunk to result .

    3. Let done be the following steps:

      1. Queue a global task on the AI task source given modelObject ’s relevant global object to perform the following steps:

        1. If abortedDuringOperation is true, then reject promise with compositeSignal ’s abort reason .

        2. Otherwise, resolve promise with result .

    4. Let error be the following steps given error information errorInfo :

      1. Queue a global task on the AI task source given modelObject ’s relevant global object to perform the following steps:

        1. If abortedDuringOperation is true, then reject promise with compositeSignal ’s abort reason .

        2. Otherwise, reject promise with the result of creating a DOMException with name given by errorInfo ’s error name , using errorInfo ’s error information to populate the message appropriately.

    5. Let stopProducing be the following steps:

      1. Return abortedDuringOperation .

    6. Perform operation given chunkProduced , done , error , and stopProducing .

  10. Return promise .

To get a streaming AI model result given an AIDestroyable modelObject , an ordered map options , and an algorithm operation :
  1. If modelObject ’s relevant global object is a Window whose associated Document is not fully active , then throw an " InvalidStateError " DOMException .

  2. Let signals be « modelObject ’s destruction abort controller ’s signal ».

  3. If options [" signal "] exists , then append it to signals .

  4. Let compositeSignal be the result of creating a dependent abort signal given signals using AbortSignal and modelObject ’s relevant realm .

  5. If compositeSignal is aborted , then return a promise rejected with compositeSignal ’s abort reason .

  6. Let abortedDuringOperation be false.

    This variable will be written to from the event loop , but read from in parallel .

  7. Add the following abort steps to compositeSignal :

    1. Set abortedDuringOperation to true.

  8. Let stream be a new ReadableStream created in this ’s relevant realm .

  9. Let canceledDuringOperation be false.

    This variable tracks web developer stream cancelations via stream.cancel() , which are not surfaced as errors. It will be written to from the event loop , but sometimes read from in parallel .

  10. Set up stream with cancelAlgorithm set to the following steps (ignoring the reason argument):

    1. Set canceledDuringOperation to true.

  11. In parallel :

    1. Let chunkProduced be the following steps given a string chunk :

      1. Queue a global task on the AI task source given this ’s relevant global object to perform the following steps:

        1. If abortedDuringOperation is true, then error stream with compositeSignal ’s abort reason .

        2. Otherwise, enqueue chunk into stream .

    2. Let done be the following steps:

      1. Queue a global task on the AI task source given this ’s relevant global object to perform the following steps:

        1. If abortedDuringOperation is true, then error stream with compositeSignal ’s abort reason .

        2. Otherwise, close stream .

    3. Let error be the following steps given error information errorInfo :

      1. Queue a global task on the AI task source given this ’s relevant global object to perform the following steps:

        1. If abortedDuringOperation is true, then error stream with compositeSignal ’s abort reason .

        2. Otherwise, error stream with the result of creating a DOMException with name given by errorInfo ’s error name , using errorInfo ’s error information to populate the message appropriately.

    4. Let stopProducing be the following steps:

      1. If either abortedDuringOperation or canceledDuringOperation are true, then return true.

      2. Return false.

    5. Perform operation given chunkProduced , done , error , and stopProducing .

  12. Return stream .

6.3. Language tags

To validate and canonicalize language tags given a ordered map options and a string key , perform the following steps. They mutate options in place to canonicalize and deduplicate language tags found in options [ key ], and throw a TypeError if any are invalid.
  1. Assert : options [ key ] exists .

  2. If options [ key ] is a string , then set options [ key ] to the result of validating and canonicalizing a single language tag given options [ key ].

  3. Otherwise:

    1. Assert : options [ key ] either does not exist , or it is a list of strings .

    2. Let languageTags be an empty ordered set .

    3. If options [ key ] exists , then for each languageTag of options [ key ]:

      1. If IsStructurallyValidLanguageTag ( languageTag ) is false, then throw a TypeError .

      2. Append the result of validating and canonicalizing a single language tag to languageTags .

    4. Set options [ key ] to languageTags .

To validate and canonicalize a single language tag given a string potentialLanguageTag :
  1. If IsStructurallyValidLanguageTag ( potentialLanguageTag ) is false, then throw a TypeError .

  2. Return CanonicalizeUnicodeLocaleId ( potentialLanguageTag ).

6.4. Availability

The minimum availability given a list of AIAvailability -or-null values availabilities is:
  1. If availabilities contains null, then return null.

  2. If availabilities contains " unavailable ", then return " unavailable ".

  3. If availabilities contains " downloading ", then return " downloading ".

  4. If availabilities contains " downloadable ", then return " downloadable ".

  5. Return " available ".

6.5. Task source

Tasks queued by this specification use the AI task source .

Index

Terms defined by this specification

Terms defined by reference

References

Normative References

[COMMONMARK]
CommonMark Spec . URL: https://spec.commonmark.org/
[DOM]
Anne van Kesteren. DOM Standard . Living Standard. URL: https://dom.spec.whatwg.org/
[ECMA-402]
ECMAScript Internationalization API Specification . URL: https://tc39.es/ecma402/
[ECMASCRIPT]
ECMAScript Language Specification . URL: https://tc39.es/ecma262/multipage/
[HR-TIME-3]
Yoav Weiss. High Resolution Time . URL: https://w3c.github.io/hr-time/
[HTML]
Anne van Kesteren; et al. HTML Standard . Living Standard. URL: https://html.spec.whatwg.org/multipage/
[INFRA]
Anne van Kesteren; Domenic Denicola. Infra Standard . Living Standard. URL: https://infra.spec.whatwg.org/
[STREAMS]
Adam Rice; et al. Streams Standard . Living Standard. URL: https://streams.spec.whatwg.org/
[WEBIDL]
Edgar Chen; Timothy Gu. Web IDL Standard . Living Standard. URL: https://webidl.spec.whatwg.org/
[XHR]
Anne van Kesteren. XMLHttpRequest Standard . Living Standard. URL: https://xhr.spec.whatwg.org/

IDL Index

partial interface WindowOrWorkerGlobalScope {
  [Replaceable, SecureContext] readonly attribute AI ai;
};
[Exposed=(Window,Worker), SecureContext]
interface AI {};
[Exposed=(Window,Worker), SecureContext]
interface AICreateMonitor : EventTarget {
  attribute EventHandler ondownloadprogress;
};
callback AICreateMonitorCallback = undefined (AICreateMonitor monitor);
enum AIAvailability {
  "unavailable",
  "downloadable",
  "downloading",
  "available"
};
interface mixin AIDestroyable {
  undefined destroy();
};

partial interface AI {
  readonly attribute AISummarizerFactory summarizer;
};
[Exposed=(Window,Worker), SecureContext]
interface AISummarizerFactory {
  Promise<AISummarizer> create(optional AISummarizerCreateOptions options = {});
  Promise<AIAvailability> availability(optional AISummarizerCreateCoreOptions options = {});
};
[Exposed=(Window,Worker), SecureContext]
interface AISummarizer {
  Promise<DOMString> summarize(
    DOMString input,
    optional AISummarizerSummarizeOptions options = {}
  );
  ReadableStream summarizeStreaming(
    DOMString input,
    optional AISummarizerSummarizeOptions options = {}
  );
  readonly attribute DOMString sharedContext;
  readonly attribute AISummarizerType type;
  readonly attribute AISummarizerFormat format;
  readonly attribute AISummarizerLength length;
  readonly attribute FrozenArray<DOMString>? expectedInputLanguages;
  readonly attribute FrozenArray<DOMString>? expectedContextLanguages;
  readonly attribute DOMString? outputLanguage;
  ();

};
AISummarizer includes AIDestroyable;
dictionary AISummarizerCreateCoreOptions {
  AISummarizerType type = "key-points";
  AISummarizerFormat format = "markdown";
  AISummarizerLength length = "short";
  sequence<DOMString> expectedInputLanguages;
  sequence<DOMString> expectedContextLanguages;
  DOMString outputLanguage;
};
dictionary AISummarizerCreateOptions : AISummarizerCreateCoreOptions {
  AbortSignal signal;
  AICreateMonitorCallback monitor;
  DOMString sharedContext;
};
dictionary AISummarizerSummarizeOptions {
  AbortSignal signal;
  DOMString context;
};
enum AISummarizerType { "tl;dr", "teaser", "key-points", "headline" };
enum AISummarizerFormat { "plain-text", "markdown" };
enum AISummarizerLength { "short", "medium", "long" };
[Exposed=(Window,Worker), SecureContext]
interface AIWriterFactory {
  Promise<AIWriter> create(optional AIWriterCreateOptions options = {});
  Promise<AIAvailability> availability(optional AIWriterCreateCoreOptions options = {});
};
[Exposed=(Window,Worker), SecureContext]
interface AIWriter {
  Promise<DOMString> write(DOMString writingTask, optional AIWriterWriteOptions options = {});
  ReadableStream writeStreaming(DOMString writingTask, optional AIWriterWriteOptions options = {});
  readonly attribute DOMString sharedContext;
  readonly attribute AIWriterTone tone;
  readonly attribute AIWriterFormat format;
  readonly attribute AIWriterLength length;
  readonly attribute FrozenArray<DOMString>? expectedInputLanguages;
  readonly attribute FrozenArray<DOMString>? expectedContextLanguages;
  readonly attribute DOMString? outputLanguage;
  ();

};
AIWriter includes AIDestroyable;
dictionary AIWriterCreateCoreOptions {
  AIWriterTone tone = "neutral";
  AIWriterFormat format = "markdown";
  AIWriterLength length = "short";
  sequence<DOMString> expectedInputLanguages;
  sequence<DOMString> expectedContextLanguages;
  DOMString outputLanguage;
};
dictionary AIWriterCreateOptions : AIWriterCreateCoreOptions {
  AbortSignal signal;
  AICreateMonitorCallback monitor;
  DOMString sharedContext;
};
dictionary AIWriterWriteOptions {
  DOMString context;
  AbortSignal signal;
};
enum AIWriterTone { "formal", "neutral", "casual" };
enum AIWriterFormat { "plain-text", "markdown" };
enum AIWriterLength { "short", "medium", "long" };
[Exposed=(Window,Worker), SecureContext]
interface AIRewriterFactory {
  Promise<AIRewriter> create(optional AIRewriterCreateOptions options = {});
  Promise<AIAvailability> availability(optional AIRewriterCreateCoreOptions options = {});
};
[Exposed=(Window,Worker), SecureContext]
interface AIRewriter {
  Promise<DOMString> rewrite(DOMString input, optional AIRewriterRewriteOptions options = {});
  ReadableStream rewriteStreaming(DOMString input, optional AIRewriterRewriteOptions options = {});
  readonly attribute DOMString sharedContext;
  readonly attribute AIRewriterTone tone;
  readonly attribute AIRewriterFormat format;
  readonly attribute AIRewriterLength length;
  readonly attribute FrozenArray<DOMString>? expectedInputLanguages;
  readonly attribute FrozenArray<DOMString>? expectedContextLanguages;
  readonly attribute DOMString? outputLanguage;
  ();

};
AIRewriter includes AIDestroyable;
dictionary AIRewriterCreateCoreOptions {
  AIRewriterTone tone = "as-is";
  AIRewriterFormat format = "as-is";
  AIRewriterLength length = "as-is";
  sequence<DOMString> expectedInputLanguages;
  sequence<DOMString> expectedContextLanguages;
  DOMString outputLanguage;
};
dictionary AIRewriterCreateOptions : AIRewriterCreateCoreOptions {
  AbortSignal signal;
  AICreateMonitorCallback monitor;
  DOMString sharedContext;
};
dictionary AIRewriterRewriteOptions {
  DOMString context;
  AbortSignal signal;
};
enum AIRewriterTone { "as-is", "more-formal", "more-casual" };
enum AIRewriterFormat { "as-is", "plain-text", "markdown" };
enum AIRewriterLength { "as-is", "shorter", "longer" };