@tanstack/ai-anthropic 0.18.11 → 0.19.1
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/dist/esm/adapters/files.d.ts +25 -0
- package/dist/esm/adapters/files.js +61 -0
- package/dist/esm/adapters/files.js.map +1 -0
- package/dist/esm/adapters/text.d.ts +11 -3
- package/dist/esm/adapters/text.js +47 -22
- package/dist/esm/adapters/text.js.map +1 -1
- package/dist/esm/index.d.ts +1 -0
- package/dist/esm/index.js +2 -1
- package/dist/esm/model-meta.d.ts +26 -4
- package/dist/esm/model-meta.js +52 -3
- package/dist/esm/model-meta.js.map +1 -1
- package/dist/esm/text/text-provider-options.d.ts +3 -3
- package/dist/esm/text/text-provider-options.js.map +1 -1
- package/package.json +3 -3
- package/src/adapters/files.ts +85 -0
- package/src/adapters/text.ts +105 -40
- package/src/index.ts +8 -0
- package/src/model-meta.ts +79 -4
- package/src/text/text-provider-options.ts +3 -5
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { BaseFilesAdapter, FileHandle, FileUploadInput } from '@tanstack/ai/adapters';
|
|
2
|
+
import { AnthropicClientConfig } from '../utils/client.js';
|
|
3
|
+
export interface AnthropicFilesConfig extends AnthropicClientConfig {
|
|
4
|
+
}
|
|
5
|
+
/**
|
|
6
|
+
* Anthropic Files adapter — uploads media to the Anthropic Files API (beta) and
|
|
7
|
+
* references it by `file_id`. Pair with `anthropicText()`: reference the
|
|
8
|
+
* returned handle in an image/document message via `fileSourceFromHandle`.
|
|
9
|
+
*/
|
|
10
|
+
export declare class AnthropicFilesAdapter extends BaseFilesAdapter<'anthropic'> {
|
|
11
|
+
readonly name: "anthropic";
|
|
12
|
+
private readonly client;
|
|
13
|
+
constructor(config: AnthropicFilesConfig);
|
|
14
|
+
upload(input: FileUploadInput): Promise<FileHandle<'anthropic'>>;
|
|
15
|
+
get(id: string): Promise<FileHandle<'anthropic'>>;
|
|
16
|
+
delete(id: string): Promise<void>;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Create an Anthropic Files adapter with an explicit API key.
|
|
20
|
+
*/
|
|
21
|
+
export declare function createAnthropicFiles(apiKey: string, config?: Omit<AnthropicFilesConfig, 'apiKey'>): AnthropicFilesAdapter;
|
|
22
|
+
/**
|
|
23
|
+
* Create an Anthropic Files adapter, reading the API key from `ANTHROPIC_API_KEY`.
|
|
24
|
+
*/
|
|
25
|
+
export declare function anthropicFiles(config?: Omit<AnthropicFilesConfig, 'apiKey'>): AnthropicFilesAdapter;
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { createAnthropicClient, getAnthropicApiKeyFromEnv } from "../utils/client.js";
|
|
2
|
+
import { BaseFilesAdapter, normalizeFileUploadInput } from "@tanstack/ai/adapters";
|
|
3
|
+
import { toFile } from "@anthropic-ai/sdk";
|
|
4
|
+
//#region src/adapters/files.ts
|
|
5
|
+
/** Beta header required for the Anthropic Files API. */
|
|
6
|
+
var FILES_API_BETA = "files-api-2025-04-14";
|
|
7
|
+
/**
|
|
8
|
+
* Anthropic Files adapter — uploads media to the Anthropic Files API (beta) and
|
|
9
|
+
* references it by `file_id`. Pair with `anthropicText()`: reference the
|
|
10
|
+
* returned handle in an image/document message via `fileSourceFromHandle`.
|
|
11
|
+
*/
|
|
12
|
+
var AnthropicFilesAdapter = class extends BaseFilesAdapter {
|
|
13
|
+
name = "anthropic";
|
|
14
|
+
client;
|
|
15
|
+
constructor(config) {
|
|
16
|
+
super();
|
|
17
|
+
this.client = createAnthropicClient(config);
|
|
18
|
+
}
|
|
19
|
+
async upload(input) {
|
|
20
|
+
const { blob, mimeType, filename } = normalizeFileUploadInput(input);
|
|
21
|
+
const file = await toFile(blob, filename, { ...mimeType ? { type: mimeType } : {} });
|
|
22
|
+
return toFileHandle(await this.client.beta.files.upload({
|
|
23
|
+
file,
|
|
24
|
+
betas: [FILES_API_BETA]
|
|
25
|
+
}));
|
|
26
|
+
}
|
|
27
|
+
async get(id) {
|
|
28
|
+
return toFileHandle(await this.client.beta.files.retrieveMetadata(id, { betas: [FILES_API_BETA] }));
|
|
29
|
+
}
|
|
30
|
+
async delete(id) {
|
|
31
|
+
await this.client.beta.files.delete(id, { betas: [FILES_API_BETA] });
|
|
32
|
+
}
|
|
33
|
+
};
|
|
34
|
+
function toFileHandle(file) {
|
|
35
|
+
return {
|
|
36
|
+
id: file.id,
|
|
37
|
+
provider: "anthropic",
|
|
38
|
+
mimeType: file.mime_type,
|
|
39
|
+
sizeBytes: file.size_bytes,
|
|
40
|
+
filename: file.filename
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Create an Anthropic Files adapter with an explicit API key.
|
|
45
|
+
*/
|
|
46
|
+
function createAnthropicFiles(apiKey, config) {
|
|
47
|
+
return new AnthropicFilesAdapter({
|
|
48
|
+
...config,
|
|
49
|
+
apiKey
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Create an Anthropic Files adapter, reading the API key from `ANTHROPIC_API_KEY`.
|
|
54
|
+
*/
|
|
55
|
+
function anthropicFiles(config) {
|
|
56
|
+
return createAnthropicFiles(getAnthropicApiKeyFromEnv(), config);
|
|
57
|
+
}
|
|
58
|
+
//#endregion
|
|
59
|
+
export { AnthropicFilesAdapter, anthropicFiles, createAnthropicFiles };
|
|
60
|
+
|
|
61
|
+
//# sourceMappingURL=files.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"files.js","names":[],"sources":["../../../src/adapters/files.ts"],"sourcesContent":["import { toFile } from '@anthropic-ai/sdk'\nimport {\n BaseFilesAdapter,\n normalizeFileUploadInput,\n} from '@tanstack/ai/adapters'\nimport {\n createAnthropicClient,\n getAnthropicApiKeyFromEnv,\n} from '../utils/client'\nimport type Anthropic_SDK from '@anthropic-ai/sdk'\nimport type { FileMetadata } from '@anthropic-ai/sdk/resources/beta/files'\nimport type { FileHandle, FileUploadInput } from '@tanstack/ai/adapters'\nimport type { AnthropicClientConfig } from '../utils/client'\n\n/** Beta header required for the Anthropic Files API. */\nconst FILES_API_BETA = 'files-api-2025-04-14'\n\nexport interface AnthropicFilesConfig extends AnthropicClientConfig {}\n\n/**\n * Anthropic Files adapter — uploads media to the Anthropic Files API (beta) and\n * references it by `file_id`. Pair with `anthropicText()`: reference the\n * returned handle in an image/document message via `fileSourceFromHandle`.\n */\nexport class AnthropicFilesAdapter extends BaseFilesAdapter<'anthropic'> {\n readonly name = 'anthropic' as const\n private readonly client: Anthropic_SDK\n\n constructor(config: AnthropicFilesConfig) {\n super()\n this.client = createAnthropicClient(config)\n }\n\n async upload(input: FileUploadInput): Promise<FileHandle<'anthropic'>> {\n const { blob, mimeType, filename } = normalizeFileUploadInput(input)\n const file = await toFile(blob, filename, {\n ...(mimeType ? { type: mimeType } : {}),\n })\n const result = await this.client.beta.files.upload({\n file,\n betas: [FILES_API_BETA],\n })\n return toFileHandle(result)\n }\n\n async get(id: string): Promise<FileHandle<'anthropic'>> {\n const result = await this.client.beta.files.retrieveMetadata(id, {\n betas: [FILES_API_BETA],\n })\n return toFileHandle(result)\n }\n\n async delete(id: string): Promise<void> {\n await this.client.beta.files.delete(id, { betas: [FILES_API_BETA] })\n }\n}\n\nfunction toFileHandle(file: FileMetadata): FileHandle<'anthropic'> {\n return {\n id: file.id,\n provider: 'anthropic',\n mimeType: file.mime_type,\n sizeBytes: file.size_bytes,\n filename: file.filename,\n }\n}\n\n/**\n * Create an Anthropic Files adapter with an explicit API key.\n */\nexport function createAnthropicFiles(\n apiKey: string,\n config?: Omit<AnthropicFilesConfig, 'apiKey'>,\n): AnthropicFilesAdapter {\n return new AnthropicFilesAdapter({ ...config, apiKey })\n}\n\n/**\n * Create an Anthropic Files adapter, reading the API key from `ANTHROPIC_API_KEY`.\n */\nexport function anthropicFiles(\n config?: Omit<AnthropicFilesConfig, 'apiKey'>,\n): AnthropicFilesAdapter {\n return createAnthropicFiles(getAnthropicApiKeyFromEnv(), config)\n}\n"],"mappings":";;;;;AAeA,IAAM,iBAAiB;;;;;;AASvB,IAAa,wBAAb,cAA2C,iBAA8B;CACvE,OAAgB;CAChB;CAEA,YAAY,QAA8B;EACxC,MAAM;EACN,KAAK,SAAS,sBAAsB,MAAM;CAC5C;CAEA,MAAM,OAAO,OAA0D;EACrE,MAAM,EAAE,MAAM,UAAU,aAAa,yBAAyB,KAAK;EACnE,MAAM,OAAO,MAAM,OAAO,MAAM,UAAU,EACxC,GAAI,WAAW,EAAE,MAAM,SAAS,IAAI,CAAC,EACvC,CAAC;EAKD,OAAO,aAAa,MAJC,KAAK,OAAO,KAAK,MAAM,OAAO;GACjD;GACA,OAAO,CAAC,cAAc;EACxB,CAAC,CACyB;CAC5B;CAEA,MAAM,IAAI,IAA8C;EAItD,OAAO,aAAa,MAHC,KAAK,OAAO,KAAK,MAAM,iBAAiB,IAAI,EAC/D,OAAO,CAAC,cAAc,EACxB,CAAC,CACyB;CAC5B;CAEA,MAAM,OAAO,IAA2B;EACtC,MAAM,KAAK,OAAO,KAAK,MAAM,OAAO,IAAI,EAAE,OAAO,CAAC,cAAc,EAAE,CAAC;CACrE;AACF;AAEA,SAAS,aAAa,MAA6C;CACjE,OAAO;EACL,IAAI,KAAK;EACT,UAAU;EACV,UAAU,KAAK;EACf,WAAW,KAAK;EAChB,UAAU,KAAK;CACjB;AACF;;;;AAKA,SAAgB,qBACd,QACA,QACuB;CACvB,OAAO,IAAI,sBAAsB;EAAE,GAAG;EAAQ;CAAO,CAAC;AACxD;;;;AAKA,SAAgB,eACd,QACuB;CACvB,OAAO,qBAAqB,0BAA0B,GAAG,MAAM;AACjE"}
|
|
@@ -1,16 +1,22 @@
|
|
|
1
1
|
import { BaseTextAdapter, StructuredOutputOptions, StructuredOutputResult } from '@tanstack/ai/adapters';
|
|
2
2
|
import { ANTHROPIC_MODELS, AnthropicChatModelProviderOptionsByName, AnthropicChatModelToolCapabilitiesByName, AnthropicModelInputModalitiesByName } from '../model-meta.js';
|
|
3
3
|
import { AnthropicBeta } from '@anthropic-ai/sdk/resources/beta/beta';
|
|
4
|
-
import { AnyTool, Modality, AdapterYieldChunk, TextOptions } from '@tanstack/ai';
|
|
4
|
+
import { AnyTool, Modality, ModelMessage, AdapterYieldChunk, TextOptions } from '@tanstack/ai';
|
|
5
5
|
import { AnthropicSystemPromptMetadata, ExternalTextProviderOptions } from '../text/text-provider-options.js';
|
|
6
6
|
import { AnthropicMessageMetadataByModality } from '../message-types.js';
|
|
7
7
|
import { AnthropicClientConfig, AnthropicMessagesClient } from '../utils/client.js';
|
|
8
|
+
/**
|
|
9
|
+
* True when any message carries a provider file-handle source, so the request
|
|
10
|
+
* must send the Files API beta header.
|
|
11
|
+
*/
|
|
12
|
+
export declare function messagesHaveFileSource(messages: Array<ModelMessage>): boolean;
|
|
8
13
|
/**
|
|
9
14
|
* Computes the `betas` array for a Messages request. Unions:
|
|
10
15
|
* - `interleaved-thinking-2025-05-14` when interleaved thinking is enabled,
|
|
11
16
|
* - `code-execution-2025-08-25` when a `code_execution` tool is present,
|
|
12
17
|
* - `skills-2025-10-02` when that tool carries skills,
|
|
13
|
-
* - `context-management-2025-06-27` when `context_management` is set
|
|
18
|
+
* - `context-management-2025-06-27` when `context_management` is set,
|
|
19
|
+
* - `files-api-2025-04-14` when a message references an uploaded file handle.
|
|
14
20
|
* Returns `undefined` when none apply (so the call site omits `betas`).
|
|
15
21
|
*/
|
|
16
22
|
export declare function computeAnthropicBetas(tools: Array<AnyTool> | undefined, modelOptions: {
|
|
@@ -19,7 +25,8 @@ export declare function computeAnthropicBetas(tools: Array<AnyTool> | undefined,
|
|
|
19
25
|
budget_tokens?: number;
|
|
20
26
|
};
|
|
21
27
|
context_management?: unknown | null;
|
|
22
|
-
|
|
28
|
+
mcp_servers?: ReadonlyArray<unknown>;
|
|
29
|
+
} | undefined, hasFileSource?: boolean): Array<AnthropicBeta> | undefined;
|
|
23
30
|
/**
|
|
24
31
|
* Configuration for Anthropic text adapter
|
|
25
32
|
*/
|
|
@@ -52,6 +59,7 @@ type ResolveToolCapabilities<TModel extends string> = TModel extends keyof Anthr
|
|
|
52
59
|
export declare class AnthropicTextAdapter<TModel extends (typeof ANTHROPIC_MODELS)[number], TProviderOptions extends Record<string, any> = ResolveProviderOptions<TModel>, TInputModalities extends ReadonlyArray<Modality> = ResolveInputModalities<TModel>, TToolCapabilities extends ReadonlyArray<string> = ResolveToolCapabilities<TModel>> extends BaseTextAdapter<TModel, TProviderOptions, TInputModalities, AnthropicMessageMetadataByModality, TToolCapabilities, unknown, AnthropicSystemPromptMetadata> {
|
|
53
60
|
readonly kind: "text";
|
|
54
61
|
readonly name: "anthropic";
|
|
62
|
+
readonly supportsFileSources = true;
|
|
55
63
|
private readonly client;
|
|
56
64
|
constructor(config: AnthropicTextAdapterConfig, model: TModel);
|
|
57
65
|
chatStream(options: TextOptions<TProviderOptions>): AsyncIterable<AdapterYieldChunk>;
|
|
@@ -5,7 +5,7 @@ import { validateTextProviderOptions } from "../text/text-provider-options.js";
|
|
|
5
5
|
import { buildAnthropicUsage } from "../usage.js";
|
|
6
6
|
import { createAnthropicClient, generateId, getAnthropicApiKeyFromEnv } from "../utils/client.js";
|
|
7
7
|
import { ANTHROPIC_COMBINED_TOOLS_AND_SCHEMA_MODELS, getAnthropicDefaultMaxTokens } from "../model-meta.js";
|
|
8
|
-
import { EventType, normalizeSystemPrompts } from "@tanstack/ai";
|
|
8
|
+
import { EventType, fileReferenceFor, isFileSource, normalizeSystemPrompts } from "@tanstack/ai";
|
|
9
9
|
import { toRunErrorRawEvent } from "@tanstack/ai/adapter-internals";
|
|
10
10
|
import { BaseTextAdapter } from "@tanstack/ai/adapters";
|
|
11
11
|
//#region src/adapters/text.ts
|
|
@@ -45,17 +45,27 @@ function buildServerToolResultBlock(toolUseId, meta) {
|
|
|
45
45
|
};
|
|
46
46
|
}
|
|
47
47
|
/**
|
|
48
|
+
* True when any message carries a provider file-handle source, so the request
|
|
49
|
+
* must send the Files API beta header.
|
|
50
|
+
*/
|
|
51
|
+
function messagesHaveFileSource(messages) {
|
|
52
|
+
return messages.some((message) => Array.isArray(message.content) && message.content.some((part) => "source" in part && isFileSource(part.source)));
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
48
55
|
* Computes the `betas` array for a Messages request. Unions:
|
|
49
56
|
* - `interleaved-thinking-2025-05-14` when interleaved thinking is enabled,
|
|
50
57
|
* - `code-execution-2025-08-25` when a `code_execution` tool is present,
|
|
51
58
|
* - `skills-2025-10-02` when that tool carries skills,
|
|
52
|
-
* - `context-management-2025-06-27` when `context_management` is set
|
|
59
|
+
* - `context-management-2025-06-27` when `context_management` is set,
|
|
60
|
+
* - `files-api-2025-04-14` when a message references an uploaded file handle.
|
|
53
61
|
* Returns `undefined` when none apply (so the call site omits `betas`).
|
|
54
62
|
*/
|
|
55
|
-
function computeAnthropicBetas(tools, modelOptions) {
|
|
63
|
+
function computeAnthropicBetas(tools, modelOptions, hasFileSource = false) {
|
|
56
64
|
const betas = /* @__PURE__ */ new Set();
|
|
65
|
+
if (hasFileSource) betas.add("files-api-2025-04-14");
|
|
57
66
|
if (modelOptions?.thinking?.type === "enabled" && typeof modelOptions.thinking.budget_tokens === "number" && modelOptions.thinking.budget_tokens > 0) betas.add("interleaved-thinking-2025-05-14");
|
|
58
67
|
if (modelOptions?.context_management != null) betas.add("context-management-2025-06-27");
|
|
68
|
+
if (modelOptions?.mcp_servers && modelOptions.mcp_servers.length > 0) betas.add("mcp-client-2025-04-04");
|
|
59
69
|
const codeExecTool = tools?.find((tool) => getAnthropicProviderToolKind(tool) === "code_execution");
|
|
60
70
|
if (codeExecTool) {
|
|
61
71
|
const cfgType = readCodeExecutionConfig(codeExecTool)?.type;
|
|
@@ -81,6 +91,7 @@ function asSdkAnthropicMessagesClient(client) {
|
|
|
81
91
|
var AnthropicTextAdapter = class extends BaseTextAdapter {
|
|
82
92
|
kind = "text";
|
|
83
93
|
name = "anthropic";
|
|
94
|
+
supportsFileSources = true;
|
|
84
95
|
client;
|
|
85
96
|
constructor(config, model) {
|
|
86
97
|
super({}, model);
|
|
@@ -94,7 +105,7 @@ var AnthropicTextAdapter = class extends BaseTextAdapter {
|
|
|
94
105
|
provider: "anthropic",
|
|
95
106
|
model: this.model
|
|
96
107
|
});
|
|
97
|
-
const betas = computeAnthropicBetas(options.tools, options.modelOptions);
|
|
108
|
+
const betas = computeAnthropicBetas(options.tools, options.modelOptions, messagesHaveFileSource(options.messages));
|
|
98
109
|
const stream = await this.client.beta.messages.create({
|
|
99
110
|
...requestParams,
|
|
100
111
|
stream: true,
|
|
@@ -149,7 +160,7 @@ var AnthropicTextAdapter = class extends BaseTextAdapter {
|
|
|
149
160
|
provider: "anthropic",
|
|
150
161
|
model: this.model
|
|
151
162
|
});
|
|
152
|
-
const betas = computeAnthropicBetas(chatOptions.tools, chatOptions.modelOptions);
|
|
163
|
+
const betas = computeAnthropicBetas(chatOptions.tools, chatOptions.modelOptions, messagesHaveFileSource(chatOptions.messages));
|
|
153
164
|
const response = await this.client.beta.messages.create({
|
|
154
165
|
...requestParams,
|
|
155
166
|
stream: false,
|
|
@@ -287,32 +298,46 @@ var AnthropicTextAdapter = class extends BaseTextAdapter {
|
|
|
287
298
|
}
|
|
288
299
|
case "image": {
|
|
289
300
|
const metadata = part.metadata;
|
|
301
|
+
let imageSource;
|
|
302
|
+
if (isFileSource(part.source)) imageSource = {
|
|
303
|
+
type: "file",
|
|
304
|
+
file_id: fileReferenceFor(part.source, this.name)
|
|
305
|
+
};
|
|
306
|
+
else if (part.source.type === "data") imageSource = {
|
|
307
|
+
type: "base64",
|
|
308
|
+
data: part.source.value,
|
|
309
|
+
media_type: part.source.mimeType
|
|
310
|
+
};
|
|
311
|
+
else imageSource = {
|
|
312
|
+
type: "url",
|
|
313
|
+
url: part.source.value
|
|
314
|
+
};
|
|
290
315
|
return {
|
|
291
316
|
type: "image",
|
|
292
|
-
source:
|
|
293
|
-
type: "base64",
|
|
294
|
-
data: part.source.value,
|
|
295
|
-
media_type: part.source.mimeType
|
|
296
|
-
} : {
|
|
297
|
-
type: "url",
|
|
298
|
-
url: part.source.value
|
|
299
|
-
},
|
|
317
|
+
source: imageSource,
|
|
300
318
|
...metadata?.cache_control !== void 0 && { cache_control: metadata.cache_control }
|
|
301
319
|
};
|
|
302
320
|
}
|
|
303
321
|
case "document": {
|
|
304
322
|
const metadata = part.metadata;
|
|
305
323
|
const title = metadata?.title ?? metadata?.filename;
|
|
324
|
+
let docSource;
|
|
325
|
+
if (isFileSource(part.source)) docSource = {
|
|
326
|
+
type: "file",
|
|
327
|
+
file_id: fileReferenceFor(part.source, this.name)
|
|
328
|
+
};
|
|
329
|
+
else if (part.source.type === "data") docSource = {
|
|
330
|
+
type: "base64",
|
|
331
|
+
data: part.source.value,
|
|
332
|
+
media_type: part.source.mimeType
|
|
333
|
+
};
|
|
334
|
+
else docSource = {
|
|
335
|
+
type: "url",
|
|
336
|
+
url: part.source.value
|
|
337
|
+
};
|
|
306
338
|
return {
|
|
307
339
|
type: "document",
|
|
308
|
-
source:
|
|
309
|
-
type: "base64",
|
|
310
|
-
data: part.source.value,
|
|
311
|
-
media_type: part.source.mimeType
|
|
312
|
-
} : {
|
|
313
|
-
type: "url",
|
|
314
|
-
url: part.source.value
|
|
315
|
-
},
|
|
340
|
+
source: docSource,
|
|
316
341
|
...metadata?.cache_control !== void 0 && { cache_control: metadata.cache_control },
|
|
317
342
|
...metadata?.citations !== void 0 && { citations: metadata.citations },
|
|
318
343
|
...metadata?.context !== void 0 && { context: metadata.context },
|
|
@@ -873,6 +898,6 @@ function anthropicText(model, config) {
|
|
|
873
898
|
return createAnthropicChat(model, getAnthropicApiKeyFromEnv(), config);
|
|
874
899
|
}
|
|
875
900
|
//#endregion
|
|
876
|
-
export { AnthropicTextAdapter, anthropicText, computeAnthropicBetas, createAnthropicChat, createAnthropicChatWithClient };
|
|
901
|
+
export { AnthropicTextAdapter, anthropicText, computeAnthropicBetas, createAnthropicChat, createAnthropicChatWithClient, messagesHaveFileSource };
|
|
877
902
|
|
|
878
903
|
//# sourceMappingURL=text.js.map
|