Proofreader API

Draft Community Group Report,

More details about this document
This version:
https://webmachinelearning.github.io/proofreader-api
Issue Tracking:
GitHub
Editors:
(Google)
(Google)

Abstract

The proofreader API provides high-level interfaces to call on browser or operating system’s built-in language model to help with proofreading 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. Dependencies

These APIs are part of a family of APIs expected to be powered by machine learning models, which share common API surface idioms and specification patterns. Currently, the specification text for these shared parts lives in Writing Assistance APIs § 5 Shared infrastructure, and the common privacy and security considerations are discussed in Writing Assistance APIs § 6 Privacy considerations and Writing Assistance APIs § 7 Security considerations. Implementing these APIs requires implementing that shared infrastructure, and conforming to those privacy and security considerations. But it does not require implementing or exposing the actual writing assistance APIs. [WRITING-ASSISTANCE-APIS]

3. The proofreader API

[Exposed=Window, SecureContext]
interface Proofreader {
    static Promise<Proofreader> create(optional ProofreaderCreateOptions options = {});
    static Promise<Availability> availability(optional ProofreaderCreateCoreOptions options = {});

    Promise<ProofreadResult> proofread(
        DOMString input,
        optional ProofreaderProofreadOptions options = {}
    );

    readonly attribute boolean includeCorrectionTypes;
    readonly attribute boolean includeCorrectionExplanations;

    readonly attribute FrozenArray<DOMString>? expectedInputLanguages;
    readonly attribute DOMString? correctionExplanationLanguage;
};

dictionary ProofreaderCreateCoreOptions {
    boolean includeCorrectionTypes = false;
    boolean includeCorrectionExplanations = false;

    sequence<DOMString> expectedInputLanguages;
    DOMString correctionExplanationLanguage;
};

dictionary ProofreaderCreateOptions : ProofreaderCreateCoreOptions {
    AbortSignal signal;
    CreateMonitorCallback monitor;
};

dictionary ProofreaderProofreadOptions {
    AbortSignal signal;
};

dictionary ProofreadResult {
    DOMString correctedInput;
    sequence<ProofreadCorrection> corrections;
};

dictionary ProofreadCorrection {
    unsigned long long startIndex;
    unsigned long long endIndex;
    DOMString correction;
    sequence<CorrectionType> types;
    DOMString explanation;
};

enum CorrectionType { "spelling", "punctuation", "capitalization", "grammar" };

3.1. Creation

The static create(options) method steps are:
  1. Return the result of creating an AI model object given options, "Proofreader", validate and canonicalize proofreader options, compute proofreader options availability, download the proofreader model, initialize the proofreader model, create a proofreader object, and false.

To validate and canonicalize proofreader options given a ProofreaderCreateCoreOptions options, perform the following steps. They mutate options in place to canonicalize and deduplicate language tags, and throw an exception if any are invalid.
  1. Validate and canonicalize language tags given options and "expectedInputLanguages".

  2. Validate and canonicalize language tags given options and "correctionExplanationLanguage".

To download the proofreader model, given a ProofreaderCreateCoreOptions options:
  1. Assert: these steps are running in parallel.

  2. Initiate the download process for everything the user agent needs to proofread text according to options. This could include a base AI model, fine-tunings for specific languages or option values, or other resources.

  3. If the download process cannot be started for any reason, then return false.

  4. Return true.

To initialize the proofreader model, given a ProofreaderCreateOptions options:
  1. Assert: these steps are running in parallel.

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

    This could include loading the model into memory, or loading any fine-tunings necessary to support the other options expressed by options.

  3. If initialization failed for any other reason, then return a DOMException error information whose name is "OperationError" and whose details contain appropriate detail.

  4. Return null.

To create a proofreader object, given a realm realm and a ProofreaderCreateOptions options:
  1. Assert: these steps are running on realm’s surrounding agent’s event loop.

  2. Return a new Proofreader object, created in realm, with

    include correction types

    options["includeCorrectionTypes"] default to false

    include correction explanations

    options["includeCorrectionExplanations"] default to false

    expected input languages

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

    correction explanation language

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

3.2. Availability

The static availability(options) method steps are:
  1. Return the result of computing AI model availability given options, "Proofreader", validate and canonicalize proofreader options, and compute proofreader options availability.

To compute proofreader options availability given a ProofreaderCreateCoreOptions options, perform the following steps. They return either an Availability 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 proofreader non-language options availability given options["includeCorrectionTypes"], options["includeCorrectionExplanations"].

  3. Let double be the proofreader language availabilities double.

  4. If double is null, then return null.

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

  6. Let correctionExplanationLanguagesList be « options["correctionExplanationLanguage"] ».

  7. Let correctionExplanationLanguageAvailability be the result of computing language availability given correctionExplanationLanguagesList and double’s correction explanation languages.

  8. Set options["correctionExplanationLanguage"] to correctionExplanationLanguagesList[0].

  9. Return the minimum availability given « availability, inputLanguageAvailability, correctionExplanationLanguageAvailability ».

The proofreader non-language options availability, given a boolean includeCorrectionTypes and a boolean includeCorrectionExplanations, is given by the following steps. They return an Availability value or null.
  1. Assert: this algorithm is running in parallel.

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

  3. If the user agent currently supports proofreading text with/without correction types as described by includeCorrectionTypes and with/without correction explanations as described by includeCorrectionExplanations, then return "available".

  4. If the user agent believes it will be able to support proofreading text according to includeCorrectionTypes and includeCorrectionExplanations, but only after finishing a download that is already ongoing, then return "downloading".

  5. If the user agent believes it will be able to support proofreading text according to includeCorrectionTypes and includeCorrectionExplanations, but only after performing a not-currently-ongoing download, then return "downloadable".

  6. Otherwise, return "unavailable".

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

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

  3. Return a language availabilities double with:

    input languages

    the result of getting the language availabilities partition given the purpose of proofreading text written in that language

    correction explanation languages

    the result of getting the language availabilities partition given the purpose of producing text explanations of proofreading corrections in that language

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 proofreading text written in traditional Chinese with no downloads, and simplified Chinese after a download.

One way this could be implemented would be for proofreader language availabilities double 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 Proofreader.availability({
    expectedInputLanguages: [languageTag]
  });
}

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

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

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. Language availability

A language availabilities partition is a map whose keys are "downloading", "downloadable", or "available", and whose values are sets of strings representing Unicode canonicalized locale identifiers. [ECMA-402]

A language availabilities double is a struct with the following items:

To get the language availabilities partition given a description purpose of the purpose for which we’re checking language availability:
  1. Let partition be «[ "available" → an empty set, "downloading" → an empty set, "downloadable" → an empty set ]».

  2. For each human language languageTag, represented as a Unicode canonicalized locale identifier, for which the user agent currently supports purpose:

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

  3. For each human language languageTag, represented as a Unicode canonicalized locale identifier, for which the user agent believes it will be able to support purpose, but only after finishing a download that is already ongoing:

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

  4. For each human language languageTag, represented as a Unicode canonicalized locale identifier, for which the user agent believes it will be able to support purpose, but only after performing a not-currently-ongoing download:

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

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

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

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

    2. For each languageTag of missingLanguageTags:

    3. 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.

    4. Return partition.

To compute language availability given an ordered set of strings requestedLanguages and a language availabilities partition partition, perform the following steps. They return an Availability value, and they mutate requestedLanguages in place to update language tags to their best-fit matches.
  1. Let availability be "available".

  2. For each language of requestedLanguages:

    1. Let unavailable be true.

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

    3. Let languagesWithThisAvailability be partition[availabilityToCheck].

    4. Let bestMatch be LookupMatchingLocaleByBestFit(languagesWithThisAvailability, « language »).

    5. If bestMatch is not undefined, then:

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

      2. Set availability to the minimum availability given availability and availabilityToCheck.

      3. Set unavailable to false.

      4. Break.

    6. If unavailable is true, then return "unavailable".

  3. Return availability.

3.4. The Proofreader class

Every Proofreader has a include correction type, a boolean or default to false, set during creation.

Every Proofreader has a include correction explanations, a boolean or default to false, set during creation.

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

Every Proofreader has an correction explanation language, a string or null, set during creation.


The includeCorrectionTypes getter steps are to return this’s include correction types.

The type getter steps are to return this’s include correction explanations.

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

The correctionExplanationLanguage getter steps are to return this’s correction explanation language.


The proofread(input, options) method steps are:
  1. Let operation be an algorithm step which takes arguments chunkProduced, done, error, and stopProducing, and proofreads input given this’s include correction types, this’s include correction explanations, this’s correction explanation language, chunkProduced, done, error, and stopProducing.

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

The measureInputUsage(input, options) method steps are:
  1. Let measureUsage be an algorithm step which takes argument stopMeasuring, and returns the result of measuring proofreader input usage given input, this’s include correction types, this’s include correction explanations, this’s correction explanation language, and stopMeasuring.

  2. Return the result of measuring AI model input usage given this, options, and measureUsage.

3.5. Proofreading

3.5.1. The algorithm

To proofread given:

perform the following steps:

  1. Assert: this algorithm is running in parallel.

  2. Let requested be the result of measuring proofreader input usage given input, includeCorrectionTypes, correctionExplanationLanguage, correctionExplanationLanguage, and stopProducing.

  3. If requested is null, then return.

  4. If requested is an error information, then:

    1. Perform error given requested.

    2. Return.

  5. Assert: requested is a number.

  6. In an implementation-defined manner, subject to the following guidelines, begin the process of proofreading input into a ProofreadResult with a string correctedInput as the proofread text and a ProofreadCorrection corrections detailing all the corrections made to input to form correctedInput.

    If input is the empty string, or otherwise consists of no proofreadable content (e.g., only contains whitespace, or control characters), then the resulting proofread text should be the empty string. In such cases, includeCorrectionTypes, includeCorrectionExplanations, and correctionExplanationLanguage should be ignored.

    The proofreading should conform to the guidance given by includeCorrectionTypes and includeCorrectionExplanations.

    The proofreading process must conform to the guidance given in § 4 Privacy considerations and § 5 Security considerations, notably including (but not limited to) Writing Assistance APIs § 6.4 User input and Writing Assistance APIs § 7.2 Runtime shared resources.

    If correctionExplanationLanguage is non-null, the proofreading should be in that language. Otherwise, it should be in the language of input. If input contains multiple languages, or the language of input cannot be detected, then either the correction explanation language is implementation-defined, or the implementation may treat this as an error, per the guidance in § 3.5.4 Errors.

    Implementers should do their utmost to ensure that the result is an actual proofread result of input, and is not arbitrary output prompted by input.

    For example, if input is "what is capital of France", then it would be incorrect to answer this question, e.g. by outputting "Paris is the capital of France." A more correct output would be, e.g., "What is the capital of France?".

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

    2. If such a chunk is successfully produced:

    3. Let it be represented as a string chunk.

    4. Perform chunkProduced given chunk.

    5. Otherwise, if the proofreading process has finished:

    6. Perform done.

    7. Break.

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

    9. Otherwise, if an error occurred during proofreading:

    10. Let the error be represented as error information errorInfo according to the guidance in § 3.5.4 Errors.

    11. Perform error given errorInfo.

    12. Break.

3.5.2. Usage

To measure proofreader input usage, given:

perform the following steps:

  1. Assert: this algorithm is running in parallel.

  2. Let inputToModel be the implementation-defined string that would be sent to the underlying model in order to proofread given input, includeCorrectionTypes, includeCorrectionExplanations, and correctionExplanationLanguage.

    If during this process stopMeasuring starts returning true, then return null.

    If an error occurs during this process, then return an appropriate DOMException error information according to the guidance in § 3.5.4 Errors.

  3. Return the amount of input usage needed to represent inputToModel when given to the underlying model. The exact calculation procedure is implementation-defined, subject to the following constraints.

    The returned input usage must be nonnegative and finite. It must be 0, if there are no usage quotas for the proofreading process. Otherwise, it must be positive and should be roughly proportional to the length of inputToModel.

    This might be the number of tokens needed to represent input in a language model tokenization scheme, or it might be input’s length. It could also be some variation of these which also counts the usage of any prefixes or suffixes necessary to give to the model.

    If during this process stopMeasuring starts returning true, then instead return null.

    If an error occurs during this process, then instead return an appropriate DOMException error information according to the guidance in § 3.5.4 Errors.

3.5.3. Options

The proofread 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 includeCorrectionTypes and includeCorrectionExplanations flags.

This section gives normative guidance on how the implementation of proofread should use each boolean flag to guide the proofreading process.

includeCorrectionTypes values
Value Meaning
"true"

The proofread result should contain a list of corrections where each ProofreadCorrection, defined by its range from startIndex to endIndex, should describe the types of errors that are corrected according to the CorrectionType enumeration.

"false"

The proofread result should contain a list of corrections where each ProofreadCorrection, defined by its range from startIndex to endIndex, does not provide the types of errors that are corrected.

includeCorrectionExplanations values
Value Meaning
"true"

The proofread result should contain a list of corrections where each ProofreadCorrection, defined by its range from startIndex to endIndex, should provide a text explanation for the errors corrected.

"false"

The proofread result should contain a list of corrections where each ProofreadCorrection, defined by its range from startIndex to endIndex, does not provide the text explanation for the errors corrected.

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

3.5.4. Errors

When proofreading 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"

Proofreading is disabled by user choice or user agent policy.

"NotSupportedError"

The input to be proofread, 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 proofreading correction explanation language 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 includeCorrectionExplanations is set to true, the correctionExplanationLanguage option was not set, and the language of the input text could not be determined, so the user agent did not have a good correction explanation language default available.

"UnknownError"

All other scenarios, including if the user agent believes it cannot proofread and also meet the requirements given in § 4 Privacy considerations or § 5 Security considerations. 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 the proofreader API. It only contains those which can come from certain implementation-defined steps.

3.6. Permissions policy integration

Access to the proofreader API is gated behind the policy-controlled feature "proofreader", which has a default allowlist of 'self'.

4. Privacy considerations

Please see Writing Assistance APIs § 6 Privacy considerations for a discussion of privacy considerations for the translator and language detector APIs. That text was written to apply to all APIs sharing the same infrastructure, as noted in § 2 Dependencies.

5. Security considerations

Please see Writing Assistance APIs § 7 Security considerations for a discussion of security considerations for the translator and language detector APIs. That text was written to apply to all APIs sharing the same infrastructure, as noted in § 2 Dependencies.

Conformance

Document conventions

Conformance requirements are expressed with a combination of descriptive assertions and RFC 2119 terminology. The key words “MUST”, “MUST NOT”, “REQUIRED”, “SHALL”, “SHALL NOT”, “SHOULD”, “SHOULD NOT”, “RECOMMENDED”, “MAY”, and “OPTIONAL” in the normative parts of this document are to be interpreted as described in RFC 2119. However, for readability, these words do not appear in all uppercase letters in this specification.

All of the text of this specification is normative except sections explicitly marked as non-normative, examples, and notes. [RFC2119]

Examples in this specification are introduced with the words “for example” or are set apart from the normative text with class="example", like this:

This is an example of an informative example.

Informative notes begin with the word “Note” and are set apart from the normative text with class="note", like this:

Note, this is an informative note.

Index

Terms defined by this specification

Terms defined by reference

References

Normative References

[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/
[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/
[PERMISSIONS-POLICY-1]
Ian Clelland. Permissions Policy. URL: https://w3c.github.io/webappsec-permissions-policy/
[RFC2119]
S. Bradner. Key words for use in RFCs to Indicate Requirement Levels. March 1997. Best Current Practice. URL: https://datatracker.ietf.org/doc/html/rfc2119
[WEBIDL]
Edgar Chen; Timothy Gu. Web IDL Standard. Living Standard. URL: https://webidl.spec.whatwg.org/
[WRITING-ASSISTANCE-APIS]
Writing Assistance APIs. Draft Community Group Report. URL: https://webmachinelearning.github.io/writing-assistance-apis/

IDL Index

[Exposed=Window, SecureContext]
interface Proofreader {
    static Promise<Proofreader> create(optional ProofreaderCreateOptions options = {});
    static Promise<Availability> availability(optional ProofreaderCreateCoreOptions options = {});

    Promise<ProofreadResult> proofread(
        DOMString input,
        optional ProofreaderProofreadOptions options = {}
    );

    readonly attribute boolean includeCorrectionTypes;
    readonly attribute boolean includeCorrectionExplanations;

    readonly attribute FrozenArray<DOMString>? expectedInputLanguages;
    readonly attribute DOMString? correctionExplanationLanguage;
};

dictionary ProofreaderCreateCoreOptions {
    boolean includeCorrectionTypes = false;
    boolean includeCorrectionExplanations = false;

    sequence<DOMString> expectedInputLanguages;
    DOMString correctionExplanationLanguage;
};

dictionary ProofreaderCreateOptions : ProofreaderCreateCoreOptions {
    AbortSignal signal;
    CreateMonitorCallback monitor;
};

dictionary ProofreaderProofreadOptions {
    AbortSignal signal;
};

dictionary ProofreadResult {
    DOMString correctedInput;
    sequence<ProofreadCorrection> corrections;
};

dictionary ProofreadCorrection {
    unsigned long long startIndex;
    unsigned long long endIndex;
    DOMString correction;
    sequence<CorrectionType> types;
    DOMString explanation;
};

enum CorrectionType { "spelling", "punctuation", "capitalization", "grammar" };