@mast-ai/built-in-ai 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,193 @@
1
+ Apache License
2
+ Version 2.0, January 2004
3
+ http://www.apache.org/licenses/
4
+
5
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6
+
7
+ 1. Definitions.
8
+
9
+ "License" shall mean the terms and conditions for use, reproduction,
10
+ and distribution as defined by Sections 1 through 9 of this document.
11
+
12
+ "Licensor" shall mean the copyright owner or entity authorized by
13
+ the copyright owner that is granting the License.
14
+
15
+ "Legal Entity" shall mean the union of the acting entity and all
16
+ other entities that control, are controlled by, or are under common
17
+ control with that entity. For the purposes of this definition,
18
+ "control" means (i) the power, direct or indirect, to cause the
19
+ direction or management of such entity, whether by contract or
20
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
21
+ outstanding shares, or (iii) beneficial ownership of such entity.
22
+
23
+ "You" (or "Your") shall mean an individual or Legal Entity
24
+ exercising permissions granted by this License.
25
+
26
+ "Source" form shall mean the preferred form for making modifications,
27
+ including but not limited to software source code, documentation
28
+ source, and configuration files.
29
+
30
+ "Object" form shall mean any form resulting from mechanical
31
+ transformation or translation of a Source form, including but
32
+ not limited to compiled object code, generated documentation,
33
+ and conversions to other media types.
34
+
35
+ "Work" shall mean the work of authorship made available under
36
+ the License, as indicated by a copyright notice that is included in
37
+ or attached to the work (an example is provided in the Appendix below).
38
+
39
+ "Derivative Works" shall mean any work, whether in Source or Object
40
+ form, that is based on (or derived from) the Work and for which the
41
+ editorial revisions, annotations, elaborations, or other modifications
42
+ represent, as a whole, an original work of authorship. For the purposes
43
+ of this License, Derivative Works shall not include works that remain
44
+ separable from, or merely link (or bind by name) to the interfaces of,
45
+ the Work and Derivative Works thereof.
46
+
47
+ "Contribution" shall mean, as submitted to the Licensor for inclusion
48
+ in the Work by the copyright owner or by an individual or Legal Entity
49
+ authorized to submit on behalf of the copyright owner. For the purposes
50
+ of this definition, "submitted" means any form of electronic, verbal,
51
+ or written communication sent to the Licensor or its representatives,
52
+ including but not limited to communication on electronic mailing lists,
53
+ source code control systems, and issue tracking systems that are managed
54
+ by, or on behalf of, the Licensor for the purpose of discussing and
55
+ improving the Work, but excluding communication that is conspicuously
56
+ marked or designated in writing by the copyright owner as "Not a
57
+ Contribution."
58
+
59
+ "Contributor" shall mean Licensor and any Legal Entity on behalf of
60
+ whom a Contribution has been received by the Licensor and included
61
+ within the Work.
62
+
63
+ 2. Grant of Copyright License. Subject to the terms and conditions of
64
+ this License, each Contributor hereby grants to You a perpetual,
65
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
66
+ copyright license to reproduce, prepare Derivative Works of,
67
+ publicly display, publicly perform, sublicense, and distribute the
68
+ Work and such Derivative Works in Source or Object form.
69
+
70
+ 3. Grant of Patent License. Subject to the terms and conditions of
71
+ this License, each Contributor hereby grants to You a perpetual,
72
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
73
+ (except as stated in this section) patent license to make, have made,
74
+ use, offer to sell, sell, import, and otherwise transfer the Work,
75
+ where such license applies only to those patent claims licensable
76
+ by such Contributor that are necessarily infringed by their
77
+ Contribution(s) alone or by the combination of their Contribution(s)
78
+ with the Work to which such Contribution(s) was submitted. If You
79
+ institute patent litigation against any entity (including a cross-claim
80
+ or counterclaim in a lawsuit) alleging that the Work or any patent
81
+ claim embodied in the Work constitutes direct or contributory patent
82
+ infringement, then any patent licenses granted to You under this
83
+ License for that Work shall terminate as of the date such litigation
84
+ is filed.
85
+
86
+ 4. Redistribution. You may reproduce and distribute copies of the
87
+ Work or Derivative Works thereof in any medium, with or without
88
+ modifications, and in Source or Object form, provided that You
89
+ meet the following conditions:
90
+
91
+ (a) You must give any other recipients of the Work or Derivative
92
+ Works a copy of this License; and
93
+
94
+ (b) You must cause any modified files to carry prominent notices
95
+ stating that You changed the files; and
96
+
97
+ (c) You must retain, in the Source form of any Derivative Works
98
+ that You distribute, all copyright, patent, trademark, and
99
+ attribution notices from the Source form of the Work,
100
+ excluding those notices that do not pertain to any part of
101
+ the Derivative Works; and
102
+
103
+ (d) If the Work includes a "NOTICE" text file as part of its
104
+ distribution, You must include a readable copy of the
105
+ attribution notices contained within such NOTICE file, in
106
+ at least one of the following places: within a NOTICE text
107
+ file distributed as part of the Derivative Works; within
108
+ the Source form or documentation, if provided along with the
109
+ Derivative Works; or, within a display generated by the
110
+ Derivative Works, if and wherever such third-party notices
111
+ normally appear. The contents of the NOTICE file are for
112
+ informational purposes only and do not modify the License.
113
+ You may add Your own attribution notices within Derivative
114
+ Works that You distribute, alongside or in addition to the
115
+ NOTICE text from the Work, provided that such additional
116
+ attribution notices cannot be construed as modifying the License.
117
+
118
+ You may add Your own license statement for Your modifications and
119
+ may provide additional grant of rights to use, copy, modify, merge,
120
+ publish, distribute, sublicense, and/or sell copies of the
121
+ Contribution, and to permit persons to whom the Contribution is
122
+ furnished to do so.
123
+
124
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
125
+ any Contribution intentionally submitted for inclusion in the Work
126
+ by You to the Licensor shall be under the terms and conditions of
127
+ this License, without any additional terms or conditions.
128
+ Notwithstanding the above, nothing herein shall supersede or modify
129
+ the terms of any separate license agreement you may have executed
130
+ with Licensor regarding such Contributions.
131
+
132
+ 6. Trademarks. This License does not grant permission to use the trade
133
+ names, trademarks, service marks, or product names of the Licensor,
134
+ except as required for reasonable and customary use in describing the
135
+ origin of the Work and reproducing the content of the NOTICE file.
136
+
137
+ 7. Disclaimer of Warranty. Unless required by applicable law or
138
+ agreed to in writing, Licensor provides the Work (and each
139
+ Contributor provides its Contributions) on an "AS IS" BASIS,
140
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
141
+ implied, including, without limitation, any conditions of
142
+ TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
143
+ PARTICULAR PURPOSE. You are solely responsible for determining the
144
+ appropriateness of using or reproducing the Work and assume any
145
+ risks associated with Your exercise of permissions under this License.
146
+
147
+ 8. Limitation of Liability. In no event and under no legal theory,
148
+ whether in tort (including negligence), contract, or otherwise,
149
+ unless required by applicable law (such as deliberate and grossly
150
+ negligent acts) or agreed to in writing, shall any Contributor be
151
+ liable to You for damages, including any direct, indirect, special,
152
+ incidental, or exemplary damages of any character arising as a
153
+ result of this License or out of the use or inability to use the
154
+ Work (including but not limited to damages for loss of goodwill,
155
+ workstop, computer failure or malfunction, or all other commercial
156
+ damages or losses), even if such Contributor has been advised of the
157
+ possibility of such damages.
158
+
159
+ 9. Accepting Warranty or Additional Liability. While redistributing
160
+ the Work or Derivative Works thereof, You may choose to offer,
161
+ and charge a fee for, acceptance of support, warranty, indemnity,
162
+ or other liability obligations and/or rights consistent with this
163
+ License. However, in accepting such obligations, You may act only
164
+ on Your own behalf and on Your sole responsibility, not on behalf
165
+ of any other Contributor, and only if You agree to indemnify,
166
+ defend, and hold each Contributor harmless for any liability
167
+ incurred by, or claims asserted against, such Contributor by reason
168
+ of your accepting any such warranty or additional liability.
169
+
170
+ END OF TERMS AND CONDITIONS
171
+
172
+ APPENDIX: How to apply the Apache License to your work.
173
+
174
+ To apply the Apache License to your work, attach the following
175
+ boilerplate notice, with the fields enclosed by brackets "[]"
176
+ replaced with your own identifying information. (Don't include
177
+ the brackets!) The text should be enclosed in the appropriate
178
+ comment syntax for the programming language used. Source files
179
+ may also indicate a copyright notice separately from the text below.
180
+
181
+ Copyright 2026 Andre Cipriani Bandarra
182
+
183
+ Licensed under the Apache License, Version 2.0 (the "License");
184
+ you may not use this file except in compliance with the License.
185
+ You may obtain a copy of the License at
186
+
187
+ http://www.apache.org/licenses/LICENSE-2.0
188
+
189
+ Unless required by applicable law or agreed to in writing, software
190
+ distributed under the License is distributed on an "AS IS" BASIS,
191
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
192
+ See the License for the specific language governing permissions and
193
+ limitations under the License.
package/README.md ADDED
@@ -0,0 +1,48 @@
1
+ # @mast-ai/built-in-ai
2
+
3
+ On-device inference for [MAST](https://github.com/andreban/mast-ai) via Chrome's [built-in AI](https://developer.chrome.com/docs/ai/built-in) (Prompt API / Gemini Nano). No server, no API key, no network round trip.
4
+
5
+ Also exposes browser AI capabilities as ready-to-register MAST tools: summarization, translation, language detection, and proofreading.
6
+
7
+ ## Install
8
+
9
+ ```bash
10
+ npm install @mast-ai/core @mast-ai/built-in-ai
11
+ ```
12
+
13
+ Requires Chrome with the Prompt API and related built-in AI APIs enabled.
14
+
15
+ ## Adapter
16
+
17
+ ```typescript
18
+ import { AgentRunner, ToolRegistry, createAgent } from '@mast-ai/core';
19
+ import { BuiltInAIAdapter, checkAvailability } from '@mast-ai/built-in-ai';
20
+
21
+ const availability = await checkAvailability();
22
+ if (availability !== 'available') {
23
+ throw new Error(`Prompt API not ready: ${availability}`);
24
+ }
25
+
26
+ const adapter = new BuiltInAIAdapter();
27
+ const runner = new AgentRunner(adapter, new ToolRegistry());
28
+
29
+ const agent = createAgent({ name: 'LocalAssistant', instructions: '...', tools: [] });
30
+ const result = await runner.run(agent, 'Hello!');
31
+ ```
32
+
33
+ ## Built-in tools
34
+
35
+ ```typescript
36
+ import { ToolRegistry } from '@mast-ai/core';
37
+ import { addAllBuiltInAITools } from '@mast-ai/built-in-ai';
38
+
39
+ const registry = new ToolRegistry();
40
+ addAllBuiltInAITools(registry);
41
+ // Registers: summarize, translate, detectLanguage, proofread
42
+ ```
43
+
44
+ Or register them individually: `SummarizeTool`, `TranslateTool`, `DetectLanguageTool`, `ProofreadTool`.
45
+
46
+ ## License
47
+
48
+ Apache-2.0. Copyright 2026 Andre Cipriani Bandarra.
@@ -0,0 +1,31 @@
1
+ import type { LlmAdapter, AdapterRequest, AdapterResponse, AdapterStreamChunk } from '@mast-ai/core';
2
+ /** Options for {@link BuiltInAIAdapter}. */
3
+ export interface BuiltInAIAdapterOptions {
4
+ /** Called during model download with bytes loaded and total bytes. */
5
+ onDownloadProgress?: (progress: {
6
+ loaded: number;
7
+ total: number;
8
+ }) => void;
9
+ }
10
+ /**
11
+ * LlmAdapter backed by the browser's Prompt API (on-device model).
12
+ *
13
+ * Limitation: tool calling is not supported. The Prompt API has no native
14
+ * mechanism for structured tool invocation — `toolCalls` will always be `[]`.
15
+ */
16
+ export declare class BuiltInAIAdapter implements LlmAdapter {
17
+ private readonly options;
18
+ private cachedSession;
19
+ private cachedHistory;
20
+ /** @param options - Optional configuration such as a download-progress callback. */
21
+ constructor(options?: BuiltInAIAdapterOptions);
22
+ /** {@inheritDoc LlmAdapter.generate} */
23
+ generate(request: AdapterRequest): Promise<AdapterResponse>;
24
+ /** {@inheritDoc LlmAdapter.generateStream} */
25
+ generateStream(request: AdapterRequest): AsyncIterable<AdapterStreamChunk>;
26
+ private acquireSession;
27
+ private isCacheHit;
28
+ private invalidateCache;
29
+ }
30
+ /** Returns the availability of the browser's on-device language model via `LanguageModel.availability()`. */
31
+ export declare function checkAvailability(): Promise<import("./types.js").LanguageModelAvailability>;
@@ -0,0 +1,151 @@
1
+ // Copyright 2026 Andre Cipriani Bandarra
2
+ // SPDX-License-Identifier: Apache-2.0
3
+ import { AdapterError } from '@mast-ai/core';
4
+ /**
5
+ * LlmAdapter backed by the browser's Prompt API (on-device model).
6
+ *
7
+ * Limitation: tool calling is not supported. The Prompt API has no native
8
+ * mechanism for structured tool invocation — `toolCalls` will always be `[]`.
9
+ */
10
+ export class BuiltInAIAdapter {
11
+ options;
12
+ cachedSession = null;
13
+ cachedHistory = [];
14
+ /** @param options - Optional configuration such as a download-progress callback. */
15
+ constructor(options = {}) {
16
+ this.options = options;
17
+ }
18
+ /** {@inheritDoc LlmAdapter.generate} */
19
+ async generate(request) {
20
+ if (request.tools.length > 0) {
21
+ console.warn('BuiltInAIAdapter: tool calling is not supported — tools will never be invoked.');
22
+ }
23
+ const { session, lastMessage } = await this.acquireSession(request);
24
+ try {
25
+ const input = messageToString(lastMessage);
26
+ const text = await session.prompt(input, { signal: request.signal });
27
+ this.cachedHistory = [
28
+ ...request.messages,
29
+ { role: 'assistant', content: { type: 'text', text } },
30
+ ];
31
+ return { text, toolCalls: [] };
32
+ }
33
+ catch (err) {
34
+ this.invalidateCache();
35
+ throw err;
36
+ }
37
+ }
38
+ /** {@inheritDoc LlmAdapter.generateStream} */
39
+ async *generateStream(request) {
40
+ if (request.tools.length > 0) {
41
+ console.warn('BuiltInAIAdapter: tool calling is not supported — tools will never be invoked.');
42
+ }
43
+ const { session, lastMessage } = await this.acquireSession(request);
44
+ try {
45
+ const input = messageToString(lastMessage);
46
+ const stream = session.promptStreaming(input, { signal: request.signal });
47
+ const reader = stream.getReader();
48
+ let fullText = '';
49
+ try {
50
+ while (true) {
51
+ const { done, value } = await reader.read();
52
+ if (done)
53
+ break;
54
+ fullText += value;
55
+ yield { type: 'text_delta', delta: value };
56
+ }
57
+ }
58
+ finally {
59
+ reader.releaseLock();
60
+ }
61
+ this.cachedHistory = [
62
+ ...request.messages,
63
+ { role: 'assistant', content: { type: 'text', text: fullText } },
64
+ ];
65
+ }
66
+ catch (err) {
67
+ this.invalidateCache();
68
+ throw err;
69
+ }
70
+ }
71
+ async acquireSession(request) {
72
+ if (request.messages.length === 0) {
73
+ throw new AdapterError('Request must contain at least one message.');
74
+ }
75
+ const lastMessage = request.messages[request.messages.length - 1];
76
+ const history = request.messages.slice(0, -1);
77
+ if (this.isCacheHit(history)) {
78
+ return { session: this.cachedSession, lastMessage };
79
+ }
80
+ this.invalidateCache();
81
+ if (typeof LanguageModel === 'undefined') {
82
+ throw new AdapterError('Prompt API is not supported in this browser.');
83
+ }
84
+ const availability = await LanguageModel.availability();
85
+ if (availability === 'unavailable') {
86
+ throw new AdapterError('Built-in AI model is unavailable on this device.');
87
+ }
88
+ if (availability === 'after-download' || availability === 'downloading') {
89
+ throw new AdapterError(`Built-in AI model is not ready (status: "${availability}"). Wait for the model to finish downloading.`);
90
+ }
91
+ const initialPrompts = buildInitialPrompts(request.system, history);
92
+ const session = await LanguageModel.create({
93
+ signal: request.signal,
94
+ initialPrompts,
95
+ monitor: this.options.onDownloadProgress
96
+ ? (m) => {
97
+ m.addEventListener('downloadprogress', (e) => {
98
+ const evt = e;
99
+ this.options.onDownloadProgress({ loaded: evt.loaded, total: evt.total });
100
+ });
101
+ }
102
+ : undefined,
103
+ });
104
+ if (session.contextUsage >= session.contextWindow) {
105
+ session.destroy();
106
+ throw new AdapterError("Conversation history exceeds the model's context window.");
107
+ }
108
+ this.cachedSession = session;
109
+ this.cachedHistory = history;
110
+ return { session, lastMessage };
111
+ }
112
+ isCacheHit(history) {
113
+ if (!this.cachedSession)
114
+ return false;
115
+ // cachedHistory = all prior messages + last assistant response.
116
+ // history = all messages except the new user turn = cachedHistory when cache is warm.
117
+ if (history.length !== this.cachedHistory.length)
118
+ return false;
119
+ if (history.length === 0)
120
+ return true;
121
+ const last = history[history.length - 1];
122
+ const cachedLast = this.cachedHistory[this.cachedHistory.length - 1];
123
+ return JSON.stringify(last) === JSON.stringify(cachedLast);
124
+ }
125
+ invalidateCache() {
126
+ this.cachedSession?.destroy();
127
+ this.cachedSession = null;
128
+ this.cachedHistory = [];
129
+ }
130
+ }
131
+ function buildInitialPrompts(system, history) {
132
+ const prompts = [];
133
+ if (system) {
134
+ prompts.push({ role: 'system', content: system });
135
+ }
136
+ for (const msg of history) {
137
+ prompts.push({ role: msg.role, content: messageToString(msg) });
138
+ }
139
+ return prompts;
140
+ }
141
+ function messageToString(message) {
142
+ if (message.content.type === 'text') {
143
+ return message.content.text;
144
+ }
145
+ // tool_calls and tool_result have no text representation for the Prompt API
146
+ return '';
147
+ }
148
+ /** Returns the availability of the browser's on-device language model via `LanguageModel.availability()`. */
149
+ export async function checkAvailability() {
150
+ return LanguageModel.availability();
151
+ }
@@ -0,0 +1,13 @@
1
+ export { BuiltInAIAdapter, checkAvailability } from './BuiltInAIAdapter.js';
2
+ export type { BuiltInAIAdapterOptions } from './BuiltInAIAdapter.js';
3
+ export type { LanguageModelAvailability } from './types.js';
4
+ export { SummarizeTool } from './tools/summarize.js';
5
+ export type { SummarizeToolOptions, SummarizeArgs } from './tools/summarize.js';
6
+ export { DetectLanguageTool } from './tools/detectLanguage.js';
7
+ export type { DetectLanguageToolOptions, DetectLanguageArgs } from './tools/detectLanguage.js';
8
+ export { TranslateTool } from './tools/translate.js';
9
+ export type { TranslateToolOptions, TranslateArgs } from './tools/translate.js';
10
+ export { ProofreadTool } from './tools/proofread.js';
11
+ export type { ProofreadToolOptions, ProofreadArgs, ProofreadCorrection, ProofreadResult, } from './tools/proofread.js';
12
+ export { addAllBuiltInAITools } from './tools/index.js';
13
+ export type { AddAllBuiltInAIToolsOptions } from './tools/index.js';
package/dist/index.js ADDED
@@ -0,0 +1,8 @@
1
+ // Copyright 2026 Andre Cipriani Bandarra
2
+ // SPDX-License-Identifier: Apache-2.0
3
+ export { BuiltInAIAdapter, checkAvailability } from './BuiltInAIAdapter.js';
4
+ export { SummarizeTool } from './tools/summarize.js';
5
+ export { DetectLanguageTool } from './tools/detectLanguage.js';
6
+ export { TranslateTool } from './tools/translate.js';
7
+ export { ProofreadTool } from './tools/proofread.js';
8
+ export { addAllBuiltInAITools } from './tools/index.js';
@@ -0,0 +1,38 @@
1
+ import type { Tool, ToolDefinition, ToolContext, ToolRegistry } from '@mast-ai/core';
2
+ import type { LanguageDetectionResult } from '../types.js';
3
+ /** Arguments passed by the model when invoking the `detectLanguage` tool. */
4
+ export interface DetectLanguageArgs {
5
+ /** The text whose language should be detected. */
6
+ text: string;
7
+ }
8
+ /** Options for {@link DetectLanguageTool}. */
9
+ export interface DetectLanguageToolOptions {
10
+ /** Called during model download with bytes loaded and total bytes. */
11
+ onDownloadProgress?: (progress: {
12
+ loaded: number;
13
+ total: number;
14
+ }) => void;
15
+ }
16
+ /**
17
+ * {@link Tool} that identifies the language of a piece of text using the
18
+ * browser's Language Detector API.
19
+ *
20
+ * Use {@link DetectLanguageTool.addToRegistry} to register the tool — direct
21
+ * construction is not recommended because the session is created asynchronously.
22
+ */
23
+ export declare class DetectLanguageTool implements Tool<DetectLanguageArgs, LanguageDetectionResult> {
24
+ private session;
25
+ /**
26
+ * Registers a `DetectLanguageTool` instance into `registry` once the
27
+ * underlying Language Detector session is ready.
28
+ *
29
+ * Throws immediately if the Language Detector API is unsupported or unavailable.
30
+ * The tool is silently skipped if background session creation fails.
31
+ */
32
+ static addToRegistry(registry: ToolRegistry, options?: DetectLanguageToolOptions): Promise<void>;
33
+ /** {@inheritDoc Tool.definition} */
34
+ definition(): ToolDefinition;
35
+ /** {@inheritDoc Tool.call} */
36
+ call(args: DetectLanguageArgs, context: ToolContext): Promise<LanguageDetectionResult>;
37
+ private acquireSession;
38
+ }
@@ -0,0 +1,82 @@
1
+ // Copyright 2026 Andre Cipriani Bandarra
2
+ // SPDX-License-Identifier: Apache-2.0
3
+ import { AdapterError } from '@mast-ai/core';
4
+ /**
5
+ * {@link Tool} that identifies the language of a piece of text using the
6
+ * browser's Language Detector API.
7
+ *
8
+ * Use {@link DetectLanguageTool.addToRegistry} to register the tool — direct
9
+ * construction is not recommended because the session is created asynchronously.
10
+ */
11
+ export class DetectLanguageTool {
12
+ session = null;
13
+ /**
14
+ * Registers a `DetectLanguageTool` instance into `registry` once the
15
+ * underlying Language Detector session is ready.
16
+ *
17
+ * Throws immediately if the Language Detector API is unsupported or unavailable.
18
+ * The tool is silently skipped if background session creation fails.
19
+ */
20
+ static async addToRegistry(registry, options) {
21
+ if (typeof LanguageDetector === 'undefined') {
22
+ throw new AdapterError('Language Detector API is not supported in this browser.');
23
+ }
24
+ const availability = await LanguageDetector.availability();
25
+ if (availability === 'unavailable') {
26
+ throw new AdapterError('Language Detector API is unavailable on this device.');
27
+ }
28
+ const tool = new DetectLanguageTool();
29
+ const monitor = options?.onDownloadProgress
30
+ ? (m) => {
31
+ m.addEventListener('downloadprogress', (e) => {
32
+ const evt = e;
33
+ options.onDownloadProgress({ loaded: evt.loaded, total: evt.total });
34
+ });
35
+ }
36
+ : undefined;
37
+ LanguageDetector.create({ monitor })
38
+ .then((session) => {
39
+ tool.session = session;
40
+ registry.register(tool);
41
+ })
42
+ .catch(() => {
43
+ // Background creation failed — tool remains unregistered.
44
+ });
45
+ }
46
+ /** {@inheritDoc Tool.definition} */
47
+ definition() {
48
+ return {
49
+ name: 'detectLanguage',
50
+ description: 'Detect the language of a piece of text. ' +
51
+ "Returns the most likely BCP 47 language tag (e.g. 'en', 'fr', 'ja') " +
52
+ 'and a confidence score between 0 and 1.',
53
+ parameters: {
54
+ type: 'object',
55
+ properties: {
56
+ text: {
57
+ type: 'string',
58
+ description: 'The text whose language should be detected.',
59
+ },
60
+ },
61
+ required: ['text'],
62
+ },
63
+ scope: 'read',
64
+ };
65
+ }
66
+ /** {@inheritDoc Tool.call} */
67
+ async call(args, context) {
68
+ if (typeof LanguageDetector === 'undefined') {
69
+ throw new AdapterError('Language Detector API is not supported in this browser.');
70
+ }
71
+ const session = await this.acquireSession(context);
72
+ const results = await session.detect(args.text, { signal: context.signal });
73
+ return results[0] ?? { detectedLanguage: null, confidence: 0 };
74
+ }
75
+ async acquireSession(context) {
76
+ if (this.session) {
77
+ return this.session;
78
+ }
79
+ this.session = await LanguageDetector.create({ signal: context.signal });
80
+ return this.session;
81
+ }
82
+ }
@@ -0,0 +1,16 @@
1
+ import type { ToolRegistry } from '@mast-ai/core';
2
+ /** Options for {@link addAllBuiltInAITools}. */
3
+ export interface AddAllBuiltInAIToolsOptions {
4
+ /** Called during model download with the tool name and bytes loaded / total bytes. */
5
+ onDownloadProgress?: (tool: string, progress: {
6
+ loaded: number;
7
+ total: number;
8
+ }) => void;
9
+ }
10
+ /**
11
+ * Convenience helper that registers all available built-in AI tools into `registry`.
12
+ *
13
+ * Uses `Promise.allSettled` internally so a single unavailable tool does not
14
+ * prevent the others from being registered.
15
+ */
16
+ export declare function addAllBuiltInAITools(registry: ToolRegistry, options?: AddAllBuiltInAIToolsOptions): Promise<void>;
@@ -0,0 +1,36 @@
1
+ // Copyright 2026 Andre Cipriani Bandarra
2
+ // SPDX-License-Identifier: Apache-2.0
3
+ import { SummarizeTool } from './summarize.js';
4
+ import { DetectLanguageTool } from './detectLanguage.js';
5
+ import { TranslateTool } from './translate.js';
6
+ import { ProofreadTool } from './proofread.js';
7
+ /**
8
+ * Convenience helper that registers all available built-in AI tools into `registry`.
9
+ *
10
+ * Uses `Promise.allSettled` internally so a single unavailable tool does not
11
+ * prevent the others from being registered.
12
+ */
13
+ export async function addAllBuiltInAITools(registry, options) {
14
+ await Promise.allSettled([
15
+ SummarizeTool.addToRegistry(registry, {
16
+ onDownloadProgress: options?.onDownloadProgress
17
+ ? (p) => options.onDownloadProgress('summarize', p)
18
+ : undefined,
19
+ }),
20
+ DetectLanguageTool.addToRegistry(registry, {
21
+ onDownloadProgress: options?.onDownloadProgress
22
+ ? (p) => options.onDownloadProgress('detectLanguage', p)
23
+ : undefined,
24
+ }),
25
+ TranslateTool.addToRegistry(registry, {
26
+ onDownloadProgress: options?.onDownloadProgress
27
+ ? (p) => options.onDownloadProgress('translate', p)
28
+ : undefined,
29
+ }),
30
+ ProofreadTool.addToRegistry(registry, {
31
+ onDownloadProgress: options?.onDownloadProgress
32
+ ? (p) => options.onDownloadProgress('proofread', p)
33
+ : undefined,
34
+ }),
35
+ ]);
36
+ }
@@ -0,0 +1,47 @@
1
+ import type { Tool, ToolDefinition, ToolContext, ToolRegistry } from '@mast-ai/core';
2
+ import type { ProofreadCorrection, ProofreadResult } from '../types.js';
3
+ export type { ProofreadCorrection, ProofreadResult };
4
+ /** Arguments passed by the model when invoking the `proofread` tool. */
5
+ export interface ProofreadArgs {
6
+ /** The text to proofread. */
7
+ text: string;
8
+ }
9
+ /** Options for {@link ProofreadTool}. */
10
+ export interface ProofreadToolOptions {
11
+ /** Called during model download with bytes loaded / total. */
12
+ onDownloadProgress?: (progress: {
13
+ loaded: number;
14
+ total: number;
15
+ }) => void;
16
+ }
17
+ /**
18
+ * {@link Tool} that checks text for spelling and grammar errors using the
19
+ * browser's Proofreader API.
20
+ *
21
+ * Use {@link ProofreadTool.addToRegistry} to register the tool — direct
22
+ * construction is not recommended.
23
+ *
24
+ * Session creation strategy:
25
+ * - `"available"` — session is created eagerly in `addToRegistry` and reused.
26
+ * - `"downloadable"` / `"downloading"` — session is created lazily on the first
27
+ * `call()`, which must occur within a user-gesture context (browser requirement
28
+ * for triggering a model download).
29
+ */
30
+ export declare class ProofreadTool implements Tool<ProofreadArgs, ProofreadResult> {
31
+ private readonly options?;
32
+ private session;
33
+ constructor(options?: ProofreadToolOptions | undefined);
34
+ /**
35
+ * Registers a `ProofreadTool` instance into `registry`.
36
+ *
37
+ * Throws if the Proofreader API global is absent or reports `"unavailable"`.
38
+ * When the model is already available, the session is created immediately.
39
+ * When a download is required, session creation is deferred to the first `call()`.
40
+ */
41
+ static addToRegistry(registry: ToolRegistry, options?: ProofreadToolOptions): Promise<void>;
42
+ /** {@inheritDoc Tool.definition} */
43
+ definition(): ToolDefinition;
44
+ /** {@inheritDoc Tool.call} */
45
+ call(args: ProofreadArgs, context: ToolContext): Promise<ProofreadResult>;
46
+ private buildMonitor;
47
+ }
@@ -0,0 +1,85 @@
1
+ // Copyright 2026 Andre Cipriani Bandarra
2
+ // SPDX-License-Identifier: Apache-2.0
3
+ import { AdapterError } from '@mast-ai/core';
4
+ /**
5
+ * {@link Tool} that checks text for spelling and grammar errors using the
6
+ * browser's Proofreader API.
7
+ *
8
+ * Use {@link ProofreadTool.addToRegistry} to register the tool — direct
9
+ * construction is not recommended.
10
+ *
11
+ * Session creation strategy:
12
+ * - `"available"` — session is created eagerly in `addToRegistry` and reused.
13
+ * - `"downloadable"` / `"downloading"` — session is created lazily on the first
14
+ * `call()`, which must occur within a user-gesture context (browser requirement
15
+ * for triggering a model download).
16
+ */
17
+ export class ProofreadTool {
18
+ options;
19
+ session = null;
20
+ constructor(options) {
21
+ this.options = options;
22
+ }
23
+ /**
24
+ * Registers a `ProofreadTool` instance into `registry`.
25
+ *
26
+ * Throws if the Proofreader API global is absent or reports `"unavailable"`.
27
+ * When the model is already available, the session is created immediately.
28
+ * When a download is required, session creation is deferred to the first `call()`.
29
+ */
30
+ static async addToRegistry(registry, options) {
31
+ if (typeof Proofreader === 'undefined') {
32
+ throw new AdapterError('Proofreader API is not supported in this browser.');
33
+ }
34
+ const availability = await Proofreader.availability();
35
+ if (availability === 'unavailable') {
36
+ throw new AdapterError('Proofreader API is not available on this device.');
37
+ }
38
+ const tool = new ProofreadTool(options);
39
+ if (availability === 'available') {
40
+ tool.session = await Proofreader.create();
41
+ }
42
+ // For "downloadable"/"downloading", session creation is deferred to call().
43
+ registry.register(tool);
44
+ }
45
+ /** {@inheritDoc Tool.definition} */
46
+ definition() {
47
+ return {
48
+ name: 'proofread',
49
+ description: 'Check a piece of text for spelling and grammar errors using an on-device AI model. ' +
50
+ 'Returns a list of corrections, each with the problematic span and the corrected replacement.',
51
+ parameters: {
52
+ type: 'object',
53
+ properties: {
54
+ text: {
55
+ type: 'string',
56
+ description: 'The text to proofread.',
57
+ },
58
+ },
59
+ required: ['text'],
60
+ },
61
+ scope: 'read',
62
+ };
63
+ }
64
+ /** {@inheritDoc Tool.call} */
65
+ async call(args, context) {
66
+ if (typeof Proofreader === 'undefined') {
67
+ throw new AdapterError('Proofreader API is not supported in this browser.');
68
+ }
69
+ if (!this.session) {
70
+ this.session = await Proofreader.create({ monitor: this.buildMonitor() });
71
+ }
72
+ return this.session.proofread(args.text, { signal: context.signal });
73
+ }
74
+ buildMonitor() {
75
+ if (!this.options?.onDownloadProgress)
76
+ return undefined;
77
+ const cb = this.options.onDownloadProgress;
78
+ return (m) => {
79
+ m.addEventListener('downloadprogress', (e) => {
80
+ const evt = e;
81
+ cb({ loaded: evt.loaded, total: evt.total });
82
+ });
83
+ };
84
+ }
85
+ }
@@ -0,0 +1,42 @@
1
+ import type { Tool, ToolDefinition, ToolContext, ToolRegistry } from '@mast-ai/core';
2
+ import type { SummarizerType, SummarizerFormat, SummarizerLength } from '../types.js';
3
+ /** Arguments passed by the model when invoking the `summarize` tool. */
4
+ export interface SummarizeArgs {
5
+ /** The full text to summarize. */
6
+ text: string;
7
+ type?: SummarizerType;
8
+ format?: SummarizerFormat;
9
+ length?: SummarizerLength;
10
+ /** Optional hint to guide the summarization (e.g. `"meeting transcript"`). */
11
+ context?: string;
12
+ }
13
+ /** Options for {@link SummarizeTool}. */
14
+ export interface SummarizeToolOptions {
15
+ /** Called during model download with bytes loaded and total bytes. */
16
+ onDownloadProgress?: (progress: {
17
+ loaded: number;
18
+ total: number;
19
+ }) => void;
20
+ }
21
+ /**
22
+ * {@link Tool} that condenses text using the browser's Summarizer API.
23
+ *
24
+ * Use {@link SummarizeTool.addToRegistry} to register the tool — direct
25
+ * construction is not recommended because the session is created asynchronously.
26
+ */
27
+ export declare class SummarizeTool implements Tool<SummarizeArgs, string> {
28
+ private cached;
29
+ /**
30
+ * Registers a `SummarizeTool` instance into `registry` once the underlying
31
+ * Summarizer session is ready.
32
+ *
33
+ * Throws immediately if the Summarizer API is unsupported or unavailable.
34
+ * The tool is silently skipped if background session creation fails.
35
+ */
36
+ static addToRegistry(registry: ToolRegistry, options?: SummarizeToolOptions): Promise<void>;
37
+ /** {@inheritDoc Tool.definition} */
38
+ definition(): ToolDefinition;
39
+ /** {@inheritDoc Tool.call} */
40
+ call(args: SummarizeArgs, context: ToolContext): Promise<string>;
41
+ private acquireSession;
42
+ }
@@ -0,0 +1,132 @@
1
+ // Copyright 2026 Andre Cipriani Bandarra
2
+ // SPDX-License-Identifier: Apache-2.0
3
+ import { AdapterError } from '@mast-ai/core';
4
+ /**
5
+ * {@link Tool} that condenses text using the browser's Summarizer API.
6
+ *
7
+ * Use {@link SummarizeTool.addToRegistry} to register the tool — direct
8
+ * construction is not recommended because the session is created asynchronously.
9
+ */
10
+ export class SummarizeTool {
11
+ cached = null;
12
+ /**
13
+ * Registers a `SummarizeTool` instance into `registry` once the underlying
14
+ * Summarizer session is ready.
15
+ *
16
+ * Throws immediately if the Summarizer API is unsupported or unavailable.
17
+ * The tool is silently skipped if background session creation fails.
18
+ */
19
+ static async addToRegistry(registry, options) {
20
+ if (typeof Summarizer === 'undefined') {
21
+ throw new AdapterError('Summarizer API is not supported in this browser.');
22
+ }
23
+ const availability = await Summarizer.availability();
24
+ if (availability === 'unavailable') {
25
+ throw new AdapterError('Summarizer API is unavailable on this device.');
26
+ }
27
+ const tool = new SummarizeTool();
28
+ const monitor = options?.onDownloadProgress
29
+ ? (m) => {
30
+ m.addEventListener('downloadprogress', (e) => {
31
+ const evt = e;
32
+ options.onDownloadProgress({ loaded: evt.loaded, total: evt.total });
33
+ });
34
+ }
35
+ : undefined;
36
+ // Return immediately — session creation (including any download) happens in the background.
37
+ // The tool is registered once the session is ready.
38
+ Summarizer.create({ monitor })
39
+ .then((session) => {
40
+ tool.cached = { session, type: undefined, format: undefined, length: undefined };
41
+ registry.register(tool);
42
+ })
43
+ .catch(() => {
44
+ // Background creation failed — tool remains unregistered.
45
+ });
46
+ }
47
+ /** {@inheritDoc Tool.definition} */
48
+ definition() {
49
+ return {
50
+ name: 'summarize',
51
+ description: 'Condense a long piece of text into a shorter form. ' +
52
+ 'Use when the user asks to summarize, shorten, or extract the key points of a document, ' +
53
+ 'article, or any other lengthy content.',
54
+ parameters: {
55
+ type: 'object',
56
+ properties: {
57
+ text: {
58
+ type: 'string',
59
+ description: 'The full text to summarize.',
60
+ },
61
+ type: {
62
+ type: 'string',
63
+ enum: ['key-points', 'tldr', 'teaser', 'headline'],
64
+ description: 'Shape of the summary. ' +
65
+ "'key-points' returns a bullet-point list of the main ideas (default). " +
66
+ "'tldr' returns a short paragraph capturing the essence. " +
67
+ "'teaser' returns an engaging excerpt meant to entice reading the full text. " +
68
+ "'headline' returns a single-sentence title.",
69
+ },
70
+ format: {
71
+ type: 'string',
72
+ enum: ['plain-text', 'markdown'],
73
+ description: "Output format. Use 'markdown' when the result will be rendered; " +
74
+ "'plain-text' otherwise. Defaults to 'plain-text'.",
75
+ },
76
+ length: {
77
+ type: 'string',
78
+ enum: ['short', 'medium', 'long'],
79
+ description: 'Target length of the summary relative to the input. ' + "Defaults to 'medium'.",
80
+ },
81
+ context: {
82
+ type: 'string',
83
+ description: "Optional hint to guide the summarization, e.g. 'scientific paper', " +
84
+ "'meeting transcript', or 'news article for a general audience'.",
85
+ },
86
+ },
87
+ required: ['text'],
88
+ },
89
+ scope: 'read',
90
+ };
91
+ }
92
+ /** {@inheritDoc Tool.call} */
93
+ async call(args, context) {
94
+ if (typeof Summarizer === 'undefined') {
95
+ throw new AdapterError('Summarizer API is not supported in this browser.');
96
+ }
97
+ const session = await this.acquireSession(args, context);
98
+ return session.summarize(args.text, {
99
+ context: args.context,
100
+ signal: context.signal,
101
+ });
102
+ }
103
+ async acquireSession(args, context) {
104
+ if (this.cached &&
105
+ this.cached.type === args.type &&
106
+ this.cached.format === args.format &&
107
+ this.cached.length === args.length) {
108
+ return this.cached.session;
109
+ }
110
+ const old = this.cached;
111
+ this.cached = null;
112
+ let session;
113
+ try {
114
+ session = await Summarizer.create({
115
+ type: args.type,
116
+ format: args.format,
117
+ length: args.length,
118
+ signal: context.signal,
119
+ });
120
+ }
121
+ finally {
122
+ old?.session.destroy();
123
+ }
124
+ this.cached = {
125
+ session,
126
+ type: args.type,
127
+ format: args.format,
128
+ length: args.length,
129
+ };
130
+ return session;
131
+ }
132
+ }
@@ -0,0 +1,45 @@
1
+ import type { Tool, ToolDefinition, ToolContext, ToolRegistry } from '@mast-ai/core';
2
+ /** Arguments passed by the model when invoking the `translate` tool. */
3
+ export interface TranslateArgs {
4
+ /** The text to translate. */
5
+ text: string;
6
+ /** BCP 47 language tag of the source language (e.g. `"en"`). */
7
+ sourceLanguage: string;
8
+ /** BCP 47 language tag of the target language (e.g. `"fr"`). */
9
+ targetLanguage: string;
10
+ }
11
+ /** Options for {@link TranslateTool}. */
12
+ export interface TranslateToolOptions {
13
+ /** Called during model download for a new language pair with the pair and bytes loaded / total. */
14
+ onDownloadProgress?: (progress: {
15
+ loaded: number;
16
+ total: number;
17
+ sourceLanguage: string;
18
+ targetLanguage: string;
19
+ }) => void;
20
+ }
21
+ /**
22
+ * {@link Tool} that translates text between languages using the browser's
23
+ * Translator API.
24
+ *
25
+ * Use {@link TranslateTool.addToRegistry} to register the tool — direct
26
+ * construction is not recommended. Sessions are created lazily per language
27
+ * pair on first use and cached for subsequent calls.
28
+ */
29
+ export declare class TranslateTool implements Tool<TranslateArgs, string> {
30
+ private readonly options?;
31
+ private sessions;
32
+ constructor(options?: TranslateToolOptions | undefined);
33
+ /**
34
+ * Registers a `TranslateTool` instance into `registry`.
35
+ *
36
+ * Throws immediately if the Translator API global is absent. No session is
37
+ * created at registration time — sessions are created lazily in `call()`.
38
+ */
39
+ static addToRegistry(registry: ToolRegistry, options?: TranslateToolOptions): Promise<void>;
40
+ /** {@inheritDoc Tool.definition} */
41
+ definition(): ToolDefinition;
42
+ /** {@inheritDoc Tool.call} */
43
+ call(args: TranslateArgs, context: ToolContext): Promise<string>;
44
+ private acquireSession;
45
+ }
@@ -0,0 +1,97 @@
1
+ // Copyright 2026 Andre Cipriani Bandarra
2
+ // SPDX-License-Identifier: Apache-2.0
3
+ import { AdapterError } from '@mast-ai/core';
4
+ /**
5
+ * {@link Tool} that translates text between languages using the browser's
6
+ * Translator API.
7
+ *
8
+ * Use {@link TranslateTool.addToRegistry} to register the tool — direct
9
+ * construction is not recommended. Sessions are created lazily per language
10
+ * pair on first use and cached for subsequent calls.
11
+ */
12
+ export class TranslateTool {
13
+ options;
14
+ sessions = new Map();
15
+ constructor(options) {
16
+ this.options = options;
17
+ }
18
+ /**
19
+ * Registers a `TranslateTool` instance into `registry`.
20
+ *
21
+ * Throws immediately if the Translator API global is absent. No session is
22
+ * created at registration time — sessions are created lazily in `call()`.
23
+ */
24
+ static async addToRegistry(registry, options) {
25
+ if (typeof Translator === 'undefined') {
26
+ throw new AdapterError('Translator API is not supported in this browser.');
27
+ }
28
+ registry.register(new TranslateTool(options));
29
+ }
30
+ /** {@inheritDoc Tool.definition} */
31
+ definition() {
32
+ return {
33
+ name: 'translate',
34
+ description: 'Translate a piece of text from one language to another using an on-device AI model. ' +
35
+ "Languages are specified as BCP 47 tags (e.g. 'en', 'fr', 'ja').",
36
+ parameters: {
37
+ type: 'object',
38
+ properties: {
39
+ text: {
40
+ type: 'string',
41
+ description: 'The text to translate.',
42
+ },
43
+ sourceLanguage: {
44
+ type: 'string',
45
+ description: 'BCP 47 language tag of the source language (e.g. "en").',
46
+ },
47
+ targetLanguage: {
48
+ type: 'string',
49
+ description: 'BCP 47 language tag of the target language (e.g. "fr").',
50
+ },
51
+ },
52
+ required: ['text', 'sourceLanguage', 'targetLanguage'],
53
+ },
54
+ scope: 'read',
55
+ };
56
+ }
57
+ /** {@inheritDoc Tool.call} */
58
+ async call(args, context) {
59
+ if (typeof Translator === 'undefined') {
60
+ throw new AdapterError('Translator API is not supported in this browser.');
61
+ }
62
+ const session = await this.acquireSession(args.sourceLanguage, args.targetLanguage, context);
63
+ return session.translate(args.text, { signal: context.signal });
64
+ }
65
+ async acquireSession(sourceLanguage, targetLanguage, context) {
66
+ const key = `${sourceLanguage}:${targetLanguage}`;
67
+ const cached = this.sessions.get(key);
68
+ if (cached) {
69
+ return cached;
70
+ }
71
+ const availability = await Translator.availability({ sourceLanguage, targetLanguage });
72
+ if (availability === 'unavailable') {
73
+ throw new AdapterError(`Translation from ${sourceLanguage} to ${targetLanguage} is not available on this device.`);
74
+ }
75
+ const monitor = this.options?.onDownloadProgress
76
+ ? (m) => {
77
+ m.addEventListener('downloadprogress', (e) => {
78
+ const evt = e;
79
+ this.options.onDownloadProgress({
80
+ loaded: evt.loaded,
81
+ total: evt.total,
82
+ sourceLanguage,
83
+ targetLanguage,
84
+ });
85
+ });
86
+ }
87
+ : undefined;
88
+ const session = await Translator.create({
89
+ sourceLanguage,
90
+ targetLanguage,
91
+ signal: context.signal,
92
+ monitor,
93
+ });
94
+ this.sessions.set(key, session);
95
+ return session;
96
+ }
97
+ }
@@ -0,0 +1,206 @@
1
+ /**
2
+ * Availability status of the on-device language model returned by `LanguageModel.availability()`.
3
+ *
4
+ * - `"readily"` — model is ready to use immediately.
5
+ * - `"after-download"` — model must be downloaded before use.
6
+ * - `"downloading"` — download is in progress.
7
+ * - `"unavailable"` — not supported on this device or browser.
8
+ */
9
+ export type LanguageModelAvailability = 'readily' | 'after-download' | 'downloading' | 'unavailable';
10
+ /** A single message passed to `LanguageModel.create` as part of `initialPrompts`. */
11
+ export interface LanguageModelMessage {
12
+ role: 'user' | 'assistant' | 'system';
13
+ content: string;
14
+ }
15
+ /** Options accepted by `LanguageModel.create`. */
16
+ export interface LanguageModelCreateOptions {
17
+ signal?: AbortSignal;
18
+ initialPrompts?: LanguageModelMessage[];
19
+ /** Callback invoked with a download progress monitor target. */
20
+ monitor?: (monitor: EventTarget) => void;
21
+ }
22
+ /** Options accepted by `LanguageModelSession.prompt` and `promptStreaming`. */
23
+ export interface LanguageModelPromptOptions {
24
+ signal?: AbortSignal;
25
+ }
26
+ /** A live session obtained from `LanguageModel.create`. */
27
+ export interface LanguageModelSession {
28
+ prompt(input: string, options?: LanguageModelPromptOptions): Promise<string>;
29
+ promptStreaming(input: string, options?: LanguageModelPromptOptions): ReadableStream<string>;
30
+ /** Number of tokens currently consumed in the session context. */
31
+ contextUsage: number;
32
+ /** Maximum number of tokens the session context can hold. */
33
+ contextWindow: number;
34
+ destroy(): void;
35
+ addEventListener(type: 'contextoverflow', listener: EventListener): void;
36
+ }
37
+ declare global {
38
+ const LanguageModel: {
39
+ availability(options?: Partial<LanguageModelCreateOptions>): Promise<LanguageModelAvailability>;
40
+ create(options?: LanguageModelCreateOptions): Promise<LanguageModelSession>;
41
+ };
42
+ }
43
+ /**
44
+ * Availability status of the on-device Summarizer API returned by `Summarizer.availability()`.
45
+ *
46
+ * - `"readily"` — ready to use immediately.
47
+ * - `"after-download"` — must be downloaded before use.
48
+ * - `"downloading"` — download is in progress.
49
+ * - `"unavailable"` — not supported on this device or browser.
50
+ */
51
+ export type SummarizerAvailability = 'readily' | 'after-download' | 'downloading' | 'unavailable';
52
+ /** Shape of the summary output. */
53
+ export type SummarizerType = 'key-points' | 'tldr' | 'teaser' | 'headline';
54
+ /** Output format of the summary. */
55
+ export type SummarizerFormat = 'plain-text' | 'markdown';
56
+ /** Target length of the summary relative to the source text. */
57
+ export type SummarizerLength = 'short' | 'medium' | 'long';
58
+ /** Options accepted by `Summarizer.create`. */
59
+ export interface SummarizerCreateOptions {
60
+ type?: SummarizerType;
61
+ format?: SummarizerFormat;
62
+ length?: SummarizerLength;
63
+ /** Shared context prepended to every summarization call made on this session. */
64
+ sharedContext?: string;
65
+ signal?: AbortSignal;
66
+ /** Callback invoked with a download progress monitor target. */
67
+ monitor?: (monitor: EventTarget) => void;
68
+ }
69
+ /** Per-call options passed to `SummarizerSession.summarize` / `summarizeStreaming`. */
70
+ export interface SummarizerCallOptions {
71
+ /** Optional hint providing additional context for this specific call. */
72
+ context?: string;
73
+ signal?: AbortSignal;
74
+ }
75
+ /** A live session obtained from `Summarizer.create`. */
76
+ export interface SummarizerSession {
77
+ summarize(text: string, options?: SummarizerCallOptions): Promise<string>;
78
+ summarizeStreaming(text: string, options?: SummarizerCallOptions): ReadableStream<string>;
79
+ destroy(): void;
80
+ }
81
+ declare global {
82
+ const Summarizer: {
83
+ availability(options?: Partial<SummarizerCreateOptions>): Promise<SummarizerAvailability>;
84
+ create(options?: SummarizerCreateOptions): Promise<SummarizerSession>;
85
+ };
86
+ }
87
+ /**
88
+ * Availability status of the on-device Language Detector API.
89
+ *
90
+ * - `"readily"` — ready to use immediately.
91
+ * - `"after-download"` — must be downloaded before use.
92
+ * - `"downloading"` — download is in progress.
93
+ * - `"unavailable"` — not supported on this device or browser.
94
+ */
95
+ export type LanguageDetectorAvailability = 'readily' | 'after-download' | 'downloading' | 'unavailable';
96
+ /** Options accepted by `LanguageDetector.create`. */
97
+ export interface LanguageDetectorCreateOptions {
98
+ signal?: AbortSignal;
99
+ /** Callback invoked with a download progress monitor target. */
100
+ monitor?: (monitor: EventTarget) => void;
101
+ }
102
+ /** A single language detection result. */
103
+ export interface LanguageDetectionResult {
104
+ /** BCP 47 language tag (e.g. `"en"`, `"fr"`), or `null` if undetermined. */
105
+ detectedLanguage: string | null;
106
+ /** Confidence score in the range [0, 1]. */
107
+ confidence: number;
108
+ }
109
+ /** Per-call options passed to `LanguageDetectorSession.detect`. */
110
+ export interface LanguageDetectorCallOptions {
111
+ signal?: AbortSignal;
112
+ }
113
+ /** A live session obtained from `LanguageDetector.create`. */
114
+ export interface LanguageDetectorSession {
115
+ detect(text: string, options?: LanguageDetectorCallOptions): Promise<LanguageDetectionResult[]>;
116
+ destroy(): void;
117
+ }
118
+ declare global {
119
+ const LanguageDetector: {
120
+ availability(options?: Partial<LanguageDetectorCreateOptions>): Promise<LanguageDetectorAvailability>;
121
+ create(options?: LanguageDetectorCreateOptions): Promise<LanguageDetectorSession>;
122
+ };
123
+ }
124
+ /**
125
+ * Availability status of the on-device Translator API for a given language pair.
126
+ *
127
+ * - `"readily"` — ready to use immediately.
128
+ * - `"after-download"` — must be downloaded before use.
129
+ * - `"downloading"` — download is in progress.
130
+ * - `"unavailable"` — not supported on this device or browser.
131
+ */
132
+ export type TranslatorAvailability = 'readily' | 'after-download' | 'downloading' | 'unavailable';
133
+ /** Options for checking Translator availability for a specific language pair. */
134
+ export interface TranslatorAvailabilityOptions {
135
+ sourceLanguage: string;
136
+ targetLanguage: string;
137
+ }
138
+ /** Options accepted by `Translator.create`. */
139
+ export interface TranslatorCreateOptions {
140
+ sourceLanguage: string;
141
+ targetLanguage: string;
142
+ signal?: AbortSignal;
143
+ /** Callback invoked with a download progress monitor target. */
144
+ monitor?: (monitor: EventTarget) => void;
145
+ }
146
+ /** Per-call options passed to `TranslatorSession.translate`. */
147
+ export interface TranslatorCallOptions {
148
+ signal?: AbortSignal;
149
+ }
150
+ /** A live session obtained from `Translator.create`. */
151
+ export interface TranslatorSession {
152
+ translate(text: string, options?: TranslatorCallOptions): Promise<string>;
153
+ destroy(): void;
154
+ }
155
+ declare global {
156
+ const Translator: {
157
+ availability(options: TranslatorAvailabilityOptions): Promise<TranslatorAvailability>;
158
+ create(options: TranslatorCreateOptions): Promise<TranslatorSession>;
159
+ };
160
+ }
161
+ /**
162
+ * Availability status of the on-device Proofreader API.
163
+ *
164
+ * - `"readily"` — ready to use immediately.
165
+ * - `"after-download"` — must be downloaded before use.
166
+ * - `"downloading"` — download is in progress.
167
+ * - `"unavailable"` — not supported on this device or browser.
168
+ */
169
+ export type ProofreaderAvailability = 'available' | 'downloadable' | 'downloading' | 'unavailable';
170
+ /** Options accepted by `Proofreader.create`. */
171
+ export interface ProofreaderCreateOptions {
172
+ signal?: AbortSignal;
173
+ /** Callback invoked with a download progress monitor target. */
174
+ monitor?: (monitor: EventTarget) => void;
175
+ }
176
+ /** Per-call options passed to `ProofreaderSession.proofread`. */
177
+ export interface ProofreaderCallOptions {
178
+ signal?: AbortSignal;
179
+ }
180
+ /** A single correction returned by the Proofreader API. */
181
+ export interface ProofreadCorrection {
182
+ /** The corrected replacement text. */
183
+ correction: string;
184
+ /** Start index of the error span in the original input (inclusive). */
185
+ startIndex: number;
186
+ /** End index of the error span in the original input (exclusive). */
187
+ endIndex: number;
188
+ }
189
+ /** The result returned by `ProofreaderSession.proofread`. */
190
+ export interface ProofreadResult {
191
+ /** The input text with all corrections applied. */
192
+ correctedInput: string;
193
+ /** Individual corrections found in the input. */
194
+ corrections: ProofreadCorrection[];
195
+ }
196
+ /** A live session obtained from `Proofreader.create`. */
197
+ export interface ProofreaderSession {
198
+ proofread(text: string, options?: ProofreaderCallOptions): Promise<ProofreadResult>;
199
+ destroy(): void;
200
+ }
201
+ declare global {
202
+ const Proofreader: {
203
+ availability(): Promise<ProofreaderAvailability>;
204
+ create(options?: ProofreaderCreateOptions): Promise<ProofreaderSession>;
205
+ };
206
+ }
package/dist/types.js ADDED
@@ -0,0 +1,3 @@
1
+ // Copyright 2026 Andre Cipriani Bandarra
2
+ // SPDX-License-Identifier: Apache-2.0
3
+ export {};
package/package.json ADDED
@@ -0,0 +1,36 @@
1
+ {
2
+ "name": "@mast-ai/built-in-ai",
3
+ "version": "0.1.0",
4
+ "license": "Apache-2.0",
5
+ "type": "module",
6
+ "main": "./dist/index.js",
7
+ "types": "./dist/index.d.ts",
8
+ "files": [
9
+ "dist"
10
+ ],
11
+ "repository": {
12
+ "type": "git",
13
+ "url": "git+https://github.com/andreban/mast-ai.git",
14
+ "directory": "packages/built-in-ai"
15
+ },
16
+ "publishConfig": {
17
+ "registry": "https://registry.npmjs.org",
18
+ "access": "public"
19
+ },
20
+ "scripts": {
21
+ "clean": "node -e \"require('fs').rmSync('dist',{recursive:true,force:true})\"",
22
+ "build": "npm run clean && tsc",
23
+ "prepublishOnly": "npm run build",
24
+ "dev": "tsc --watch",
25
+ "test": "vitest",
26
+ "lint": "eslint src",
27
+ "format": "prettier --write src"
28
+ },
29
+ "dependencies": {
30
+ "@mast-ai/core": "^0.1.0"
31
+ },
32
+ "devDependencies": {
33
+ "typescript": "~6.0.2",
34
+ "vitest": "^4.1.4"
35
+ }
36
+ }