@absolutejs/ai 0.4.1 → 0.6.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/CHANGELOG.md CHANGED
@@ -6,6 +6,23 @@ This file is generated by `absolute-changelog` from the entries in
6
6
  `changelog/`. Edit an entry, not this file — and add new ones under
7
7
  `changelog/unreleased/`.
8
8
 
9
+ ## 0.6.0 — 2026-10-20
10
+
11
+ ### Added
12
+
13
+ - **Load tools on demand (deferLoading, through Anthropic tool search) and clear old tool results past a threshold (toolResultClearing); both cross the provider proxy** (`AIToolResultClearing`, `AIToolDefinition`, `AIProviderToolDefinition`, `AIProviderStreamParams`, `StreamAIOptions`)
14
+
15
+ ## 0.5.0 — 2026-10-19
16
+
17
+ ### Breaking
18
+
19
+ - **AIToolDefinition.handler may return { text, images } as well as a string** (`AIToolDefinition`, `toolOutputText`)
20
+ _Migration:_ Code that calls a tool's handler itself (a wrapper, a test) now receives AIToolOutput, a string or { text, images }. Read its text with toolOutputText(output). Handlers that return a string need no change.
21
+
22
+ ### Added
23
+
24
+ - **Tools can return images for the model to see, such as a screenshot: a handler returns { text, images } and the tool loops send the images inside the tool result, mapped for Anthropic, OpenAI Responses, OpenAI Chat Completions, Gemini and Ollama** (`AIToolResult`, `AIToolOutput`, `toolOutputText`, `AIProviderContentBlock`, `anthropic`, `openai`, `openaiResponses`, `gemini`, `ollama`, `streamAIToSSE`, `streamAIWithTools`, `generateAIWithTools`, `hardenUntrustedTool`, `createAIStoredToolResultRecovery`)
25
+
9
26
  ## 0.4.1 — 2026-10-17
10
27
 
11
28
  ### Fixed
package/changelog.json CHANGED
@@ -2,6 +2,61 @@
2
2
  "contract": 1,
3
3
  "name": "@absolutejs/ai",
4
4
  "releases": [
5
+ {
6
+ "changes": [
7
+ {
8
+ "kind": "added",
9
+ "summary": "Load tools on demand (deferLoading, through Anthropic tool search) and clear old tool results past a threshold (toolResultClearing); both cross the provider proxy",
10
+ "symbols": [
11
+ "AIToolResultClearing",
12
+ "AIToolDefinition",
13
+ "AIProviderToolDefinition",
14
+ "AIProviderStreamParams",
15
+ "StreamAIOptions"
16
+ ]
17
+ }
18
+ ],
19
+ "date": "2026-10-20",
20
+ "version": "0.6.0"
21
+ },
22
+ {
23
+ "changes": [
24
+ {
25
+ "kind": "breaking",
26
+ "migration": {
27
+ "instruction": "Code that calls a tool's handler itself (a wrapper, a test) now receives AIToolOutput, a string or { text, images }. Read its text with toolOutputText(output). Handlers that return a string need no change.",
28
+ "manual": true
29
+ },
30
+ "summary": "AIToolDefinition.handler may return { text, images } as well as a string",
31
+ "symbols": [
32
+ "AIToolDefinition",
33
+ "toolOutputText"
34
+ ]
35
+ },
36
+ {
37
+ "kind": "added",
38
+ "summary": "Tools can return images for the model to see, such as a screenshot: a handler returns { text, images } and the tool loops send the images inside the tool result, mapped for Anthropic, OpenAI Responses, OpenAI Chat Completions, Gemini and Ollama",
39
+ "symbols": [
40
+ "AIToolResult",
41
+ "AIToolOutput",
42
+ "toolOutputText",
43
+ "AIProviderContentBlock",
44
+ "anthropic",
45
+ "openai",
46
+ "openaiResponses",
47
+ "gemini",
48
+ "ollama",
49
+ "streamAIToSSE",
50
+ "streamAIWithTools",
51
+ "generateAIWithTools",
52
+ "hardenUntrustedTool",
53
+ "createAIStoredToolResultRecovery"
54
+ ]
55
+ }
56
+ ],
57
+ "date": "2026-10-19",
58
+ "version": "0.5.0"
59
+ },
5
60
  {
6
61
  "changes": [
7
62
  {
package/dist/ai/index.js CHANGED
@@ -258,6 +258,14 @@ var parseAIMessage = (raw) => {
258
258
  };
259
259
  var serializeAIMessage = (message) => JSON.stringify(message);
260
260
 
261
+ // src/ai/toolOutput.ts
262
+ var toolOutputText = (output) => typeof output === "string" ? output : output.text;
263
+ var toolOutputImages = (output) => typeof output === "string" || !output.images?.length ? undefined : output.images;
264
+ var toolResultBlock = (toolUseId, output, content = toolOutputText(output)) => {
265
+ const images = toolOutputImages(output);
266
+ return images ? { content, images, tool_use_id: toolUseId, type: "tool_result" } : { content, tool_use_id: toolUseId, type: "tool_result" };
267
+ };
268
+
261
269
  // src/ai/inputCapacity.ts
262
270
  class AIInputError extends Error {
263
271
  code;
@@ -470,6 +478,7 @@ var sendMessage = async (socket, message) => {
470
478
  return true;
471
479
  };
472
480
  var buildToolDefinitions = (tools) => Object.entries(tools).map(([name, def]) => ({
481
+ ...def.deferLoading ? { deferLoading: true } : {},
473
482
  description: def.description,
474
483
  input_schema: def.input,
475
484
  name
@@ -643,14 +652,11 @@ var processToolTurn = async (socket, options, state, messageId, conversationId,
643
652
  const toolResultBlocks = [];
644
653
  for (const toolCall of toolCalls) {
645
654
  await sendToolRunning(socket, toolCall.name, toolCall.input, messageId, conversationId);
646
- const result = await executeTool(options, toolCall.name, toolCall.input);
655
+ const output = await executeTool(options, toolCall.name, toolCall.input);
656
+ const result = toolOutputText(output);
647
657
  await sendToolComplete(socket, toolCall.name, result, messageId, conversationId);
648
658
  options.onToolUse?.(toolCall.name, toolCall.input, result);
649
- toolResultBlocks.push({
650
- content: result,
651
- tool_use_id: toolCall.id,
652
- type: "tool_result"
653
- });
659
+ toolResultBlocks.push(toolResultBlock(toolCall.id, output));
654
660
  state.executedToolKeys.add(serializeToolCall(toolCall.name, toolCall.input));
655
661
  }
656
662
  state.currentMessages.push({
@@ -665,6 +671,7 @@ var processToolTurn = async (socket, options, state, messageId, conversationId,
665
671
  model: options.model,
666
672
  promptCaching: options.promptCaching,
667
673
  providerOptions: options.providerOptions,
674
+ toolResultClearing: options.toolResultClearing,
668
675
  reasoning: options.reasoning,
669
676
  signal,
670
677
  systemPrompt: options.systemPrompt,
@@ -755,6 +762,7 @@ var processStream = async (socket, options, messages, messageId, conversationId,
755
762
  model: options.model,
756
763
  promptCaching: options.promptCaching,
757
764
  providerOptions: options.providerOptions,
765
+ toolResultClearing: options.toolResultClearing,
758
766
  reasoning: options.reasoning,
759
767
  signal,
760
768
  systemPrompt: options.systemPrompt,
@@ -924,6 +932,7 @@ var withHeartbeat = async function* (source, signal, intervalMs) {
924
932
  }
925
933
  };
926
934
  var buildToolDefinitions2 = (tools) => Object.entries(tools).map(([name, def]) => ({
935
+ ...def.deferLoading ? { deferLoading: true } : {},
927
936
  description: def.description,
928
937
  input_schema: def.input,
929
938
  name
@@ -1112,7 +1121,8 @@ var executeToolCalls = async function* (pendingToolCalls, options, renderers, tu
1112
1121
  turnState.allToolsHtml += renderers.toolRunning(toolCall.name, toolCall.input);
1113
1122
  yield { data: turnState.allToolsHtml, event: "tools" };
1114
1123
  }
1115
- const result = await executeTool2(options, toolCall.name, toolCall.input);
1124
+ const output = await executeTool2(options, toolCall.name, toolCall.input);
1125
+ const result = toolOutputText(output);
1116
1126
  if (options.structuredEvents) {
1117
1127
  yield {
1118
1128
  data: JSON.stringify({
@@ -1129,11 +1139,7 @@ var executeToolCalls = async function* (pendingToolCalls, options, renderers, tu
1129
1139
  }
1130
1140
  options.onToolUse?.(toolCall.name, toolCall.input, result);
1131
1141
  const resultContent = options.maxToolResultChars !== undefined ? truncateToolResult(result, options.maxToolResultChars) : result;
1132
- toolResultBlocks.push({
1133
- content: resultContent,
1134
- tool_use_id: toolCall.id,
1135
- type: "tool_result"
1136
- });
1142
+ toolResultBlocks.push(toolResultBlock(toolCall.id, output, resultContent));
1137
1143
  }
1138
1144
  return toolResultBlocks;
1139
1145
  };
@@ -1191,6 +1197,7 @@ var streamTurns = async function* (options, renderers, messages, signal, startTi
1191
1197
  reasoning: options.reasoning,
1192
1198
  signal,
1193
1199
  systemPrompt: options.systemPrompt,
1200
+ toolResultClearing: options.toolResultClearing,
1194
1201
  tools: toolDefs
1195
1202
  }, options.contextPolicy, (prepared) => {
1196
1203
  turnState.currentMessages = prepared.messages;
@@ -1803,6 +1810,7 @@ var mergeUsage = (left, right) => {
1803
1810
  };
1804
1811
  };
1805
1812
  var toProviderTools = (tools) => Object.entries(tools).map(([name, definition]) => ({
1813
+ ...definition.deferLoading ? { deferLoading: true } : {},
1806
1814
  description: definition.description,
1807
1815
  input_schema: definition.input,
1808
1816
  name
@@ -1833,12 +1841,8 @@ var generateAIWithTools = async (options) => {
1833
1841
  const resultBlocks = await Promise.all(result.toolCalls.map(async (call) => {
1834
1842
  const definition = tools[call.name];
1835
1843
  const output = definition ? await Promise.resolve(definition.handler(call.input)).catch((err) => `Error: ${err instanceof Error ? err.message : String(err)}`) : `Error: unknown tool "${call.name}"`;
1836
- onToolUse?.(call.name, call.input, output);
1837
- return {
1838
- content: output,
1839
- tool_use_id: call.id,
1840
- type: "tool_result"
1841
- };
1844
+ onToolUse?.(call.name, call.input, toolOutputText(output));
1845
+ return toolResultBlock(call.id, output);
1842
1846
  }));
1843
1847
  return [
1844
1848
  ...result.requestMessages ?? messages,
@@ -1988,14 +1992,15 @@ var flushThinking3 = (blocks, thinking) => {
1988
1992
  var executeToolHandler = async (tools, call) => {
1989
1993
  const definition = tools[call.name];
1990
1994
  if (!definition) {
1991
- return { ok: false, result: `Error: unknown tool "${call.name}"` };
1995
+ return { ok: false, output: `Error: unknown tool "${call.name}"` };
1992
1996
  }
1993
1997
  try {
1994
- return { ok: true, result: await definition.handler(call.input) };
1998
+ const output = await definition.handler(call.input);
1999
+ return { ok: true, output };
1995
2000
  } catch (err) {
1996
2001
  return {
1997
2002
  ok: false,
1998
- result: `Error: ${err instanceof Error ? err.message : String(err)}`
2003
+ output: `Error: ${err instanceof Error ? err.message : String(err)}`
1999
2004
  };
2000
2005
  }
2001
2006
  };
@@ -2142,7 +2147,8 @@ var streamAIWithTools = async function* (options) {
2142
2147
  type: "tool_start"
2143
2148
  };
2144
2149
  const startedAt = Date.now();
2145
- const { ok, result } = await executeToolHandler(tools, call);
2150
+ const { ok, output } = await executeToolHandler(tools, call);
2151
+ const result = toolOutputText(output);
2146
2152
  executedKeys.add(toolCallKey(call));
2147
2153
  yield {
2148
2154
  id: call.id,
@@ -2153,11 +2159,7 @@ var streamAIWithTools = async function* (options) {
2153
2159
  result,
2154
2160
  type: "tool_result"
2155
2161
  };
2156
- resultBlocks.push({
2157
- content: result,
2158
- tool_use_id: call.id,
2159
- type: "tool_result"
2160
- });
2162
+ resultBlocks.push(toolResultBlock(call.id, output));
2161
2163
  if (ok && stopAfterTools?.includes(call.name)) {
2162
2164
  terminalToolSucceeded = true;
2163
2165
  break;
@@ -2300,6 +2302,7 @@ var wireParams = (params) => ({
2300
2302
  ...params.systemPrompt === undefined ? {} : { systemPrompt: params.systemPrompt },
2301
2303
  ...params.temperature === undefined ? {} : { temperature: params.temperature },
2302
2304
  ...params.toolChoice === undefined ? {} : { toolChoice: params.toolChoice },
2305
+ ...params.toolResultClearing === undefined ? {} : { toolResultClearing: params.toolResultClearing },
2303
2306
  ...params.tools === undefined ? {} : { tools: params.tools },
2304
2307
  ...params.topP === undefined ? {} : { topP: params.topP }
2305
2308
  });
@@ -5179,7 +5182,10 @@ var convertToolBlock = (block) => {
5179
5182
  if (block.type === "tool_result") {
5180
5183
  return {
5181
5184
  call_id: block.tool_use_id,
5182
- output: typeof block.content === "string" ? block.content : "",
5185
+ output: block.images?.length ? [
5186
+ { text: block.content, type: "input_text" },
5187
+ ...block.images.map((source) => mapBlockToResponsesFormat({ source, type: "image" }))
5188
+ ] : block.content,
5183
5189
  type: "function_call_output"
5184
5190
  };
5185
5191
  }
@@ -5709,6 +5715,7 @@ var NOT_FOUND4 = -1;
5709
5715
  var isRecord3 = (value) => typeof value === "object" && value !== null;
5710
5716
  var isRecordArray2 = (value) => Array.isArray(value) && value.length > 0 && isRecord3(value[0]);
5711
5717
  var hasArrayContent = (msg) => typeof msg.content !== "string" && Array.isArray(msg.content);
5718
+ var imageUrl = (source) => source.type === "url" ? source.url : `data:${source.media_type};base64,${source.data}`;
5712
5719
  var buildToolMessages = (blocks) => {
5713
5720
  const toolUseBlocks = blocks.filter((block) => block.type === "tool_use");
5714
5721
  const toolResultBlocks = blocks.filter((block) => block.type === "tool_result");
@@ -5734,6 +5741,18 @@ var buildToolMessages = (blocks) => {
5734
5741
  tool_call_id: result.tool_use_id
5735
5742
  });
5736
5743
  }
5744
+ const images = toolResultBlocks.flatMap((result) => result.images ?? []);
5745
+ if (images.length > 0)
5746
+ messages.push({
5747
+ content: [
5748
+ { text: "Images returned by the tool calls above:", type: "text" },
5749
+ ...images.map((source) => ({
5750
+ image_url: { url: imageUrl(source) },
5751
+ type: "image_url"
5752
+ }))
5753
+ ],
5754
+ role: "user"
5755
+ });
5737
5756
  return messages;
5738
5757
  };
5739
5758
  var mapToolDefinitions = (tools) => tools.map((tool) => ({
@@ -5747,9 +5766,7 @@ var mapToolDefinitions = (tools) => tools.map((tool) => ({
5747
5766
  var mapContentBlockToOpenAI = (block) => {
5748
5767
  if (block.type === "image") {
5749
5768
  return {
5750
- image_url: {
5751
- url: block.source.type === "url" ? block.source.url : `data:${block.source.media_type};base64,${block.source.data}`
5752
- },
5769
+ image_url: { url: imageUrl(block.source) },
5753
5770
  type: "image_url"
5754
5771
  };
5755
5772
  }
@@ -6372,7 +6389,10 @@ var convertMessageContent = (content) => {
6372
6389
  if (typeof content === "string") {
6373
6390
  return [{ text: content }];
6374
6391
  }
6375
- return content.map(mapContentBlock).filter((mapped) => mapped !== null);
6392
+ return content.flatMap((block) => block.type === "tool_result" && block.images?.length ? [
6393
+ mapContentBlock(block),
6394
+ ...block.images.map((source) => mapContentBlock({ source, type: "image" }))
6395
+ ] : [mapContentBlock(block)]).filter((mapped) => mapped !== null);
6376
6396
  };
6377
6397
  var hasFunctionResponse = (content) => content.some((block) => block.type === "tool_result");
6378
6398
  var convertSingleMessage = (msg) => {
@@ -6672,7 +6692,10 @@ var mapContentBlock2 = (block) => {
6672
6692
  }
6673
6693
  if (block.type === "tool_result") {
6674
6694
  return {
6675
- content: block.content,
6695
+ content: block.images?.length ? [
6696
+ { text: block.content, type: "text" },
6697
+ ...block.images.map((source) => ({ source, type: "image" }))
6698
+ ] : block.content,
6676
6699
  tool_use_id: block.tool_use_id,
6677
6700
  type: "tool_result"
6678
6701
  };
@@ -6700,10 +6723,32 @@ var mapMessage = (msg) => ({
6700
6723
  role: msg.role === "system" ? "user" : msg.role
6701
6724
  });
6702
6725
  var mapToolDefinition2 = (tool) => ({
6726
+ ...tool.deferLoading ? { defer_loading: true } : {},
6703
6727
  description: tool.description,
6704
6728
  input_schema: tool.input_schema,
6705
6729
  name: tool.name
6706
6730
  });
6731
+ var TOOL_SEARCH_TOOL = {
6732
+ name: "tool_search_tool_bm25",
6733
+ type: "tool_search_tool_bm25_20251119"
6734
+ };
6735
+ var CONTEXT_MANAGEMENT_BETA = "context-management-2025-06-27";
6736
+ var contextManagementFor = (clearing) => ({
6737
+ edits: [
6738
+ {
6739
+ ...clearing.clearAtLeastInputTokens === undefined ? {} : {
6740
+ clear_at_least: {
6741
+ type: "input_tokens",
6742
+ value: clearing.clearAtLeastInputTokens
6743
+ }
6744
+ },
6745
+ ...clearing.excludeTools?.length ? { exclude_tools: [...clearing.excludeTools] } : {},
6746
+ ...clearing.keepToolUses === undefined ? {} : { keep: { type: "tool_uses", value: clearing.keepToolUses } },
6747
+ trigger: { type: "input_tokens", value: clearing.triggerInputTokens },
6748
+ type: "clear_tool_uses_20250919"
6749
+ }
6750
+ ]
6751
+ });
6707
6752
  var requestOptionsFor = (params) => {
6708
6753
  const raw = params.providerOptions?.anthropic;
6709
6754
  if (raw === undefined)
@@ -6812,16 +6857,20 @@ var buildRequestBody3 = (params, configuredMax, configCaching) => {
6812
6857
  ] : params.systemPrompt;
6813
6858
  }
6814
6859
  const clientTools = params.tools?.map(mapToolDefinition2) ?? [];
6815
- if (clientTools.length > 0) {
6816
- if (caching) {
6817
- clientTools[clientTools.length - 1] = {
6818
- ...clientTools[clientTools.length - 1],
6819
- cache_control: { type: "ephemeral" }
6820
- };
6821
- }
6860
+ const deferring = clientTools.some((tool) => tool.defer_loading === true);
6861
+ const lastLoaded = clientTools.findLastIndex((tool) => tool.defer_loading !== true);
6862
+ if (caching && lastLoaded >= 0) {
6863
+ clientTools[lastLoaded] = {
6864
+ ...clientTools[lastLoaded],
6865
+ cache_control: { type: "ephemeral" }
6866
+ };
6822
6867
  }
6823
6868
  const serverTools = (options.serverTools ?? []).map(mapServerTool);
6824
- const tools = [...clientTools, ...serverTools];
6869
+ const tools = [
6870
+ ...clientTools,
6871
+ ...deferring ? [TOOL_SEARCH_TOOL] : [],
6872
+ ...serverTools
6873
+ ];
6825
6874
  if (tools.length > 0) {
6826
6875
  body.tools = tools;
6827
6876
  if (params.toolChoice === "auto" || params.toolChoice === "none") {
@@ -6835,6 +6884,9 @@ var buildRequestBody3 = (params, configuredMax, configCaching) => {
6835
6884
  if (params.stopSequences && params.stopSequences.length > 0) {
6836
6885
  body.stop_sequences = params.stopSequences;
6837
6886
  }
6887
+ if (params.toolResultClearing) {
6888
+ body.context_management = contextManagementFor(params.toolResultClearing);
6889
+ }
6838
6890
  const mode = params.reasoning && params.reasoning.effort !== "none" ? anthropicReasoningMode(params.model) : "none";
6839
6891
  if (params.reasoning?.effort === "none")
6840
6892
  body.thinking = { type: "disabled" };
@@ -7281,6 +7333,11 @@ var fetchAndStream = async function* (baseUrl, config, params, configuredMax, pr
7281
7333
  const suppliedHeaders = typeof config.headers === "function" ? await config.headers(params) : config.headers ?? {};
7282
7334
  const requestHeaders = new Headers(suppliedHeaders);
7283
7335
  requestHeaders.set("Content-Type", "application/json");
7336
+ if (body.context_management !== undefined) {
7337
+ const betas = (requestHeaders.get("anthropic-beta") ?? "").split(",").map((beta) => beta.trim()).filter(Boolean);
7338
+ if (!betas.includes(CONTEXT_MANAGEMENT_BETA))
7339
+ requestHeaders.set("anthropic-beta", [...betas, CONTEXT_MANAGEMENT_BETA].join(","));
7340
+ }
7284
7341
  if (config.authStyle === "bearer") {
7285
7342
  requestHeaders.set("Authorization", `Bearer ${token}`);
7286
7343
  } else {
@@ -7349,7 +7406,12 @@ var anthropic = (config) => {
7349
7406
  const hosted = tools.filter((tool) => isRecord5(tool) && typeof tool.type === "string" && /^(web_search_|web_fetch_|code_execution_|bash_code_execution_|text_editor_code_execution_|tool_search_tool_)/u.test(tool.type));
7350
7407
  const scope = hosted.length > 0 || body.mcp_servers !== undefined ? "caller-input" : "request";
7351
7408
  if (hosted.length > 0) {
7352
- const clientTools = tools.filter((tool) => !hosted.includes(tool));
7409
+ const clientTools = tools.filter((tool) => !hosted.includes(tool)).map((tool) => {
7410
+ if (!isRecord5(tool) || tool.defer_loading === undefined)
7411
+ return tool;
7412
+ const { defer_loading: _deferred, ...loaded } = tool;
7413
+ return loaded;
7414
+ });
7353
7415
  if (clientTools.length)
7354
7416
  counted.tools = clientTools;
7355
7417
  else
@@ -7418,8 +7480,10 @@ var convertMessage2 = (msg) => {
7418
7480
  });
7419
7481
  }
7420
7482
  for (const block of toolResultBlocks) {
7483
+ const images = (block.images ?? []).flatMap((source) => source.type === "base64" ? [source.data] : []);
7421
7484
  results.push({
7422
7485
  content: typeof block.content === "string" ? block.content : "",
7486
+ ...images.length > 0 ? { images } : {},
7423
7487
  role: "tool"
7424
7488
  });
7425
7489
  }
@@ -9026,6 +9090,12 @@ var createAIStoredToolResultRecovery = (toolNames) => async ({ params }) => {
9026
9090
  if (block.type !== "tool_result" || !eligible.has(block.tool_use_id) || block === newest)
9027
9091
  return block;
9028
9092
  const marker = "[Earlier lookup removed from working context. Its immutable original remains saved. The original tool call and source/version arguments above are unchanged: repeat that lookup if needed to verify facts. Do not infer facts from this marker.]";
9093
+ if (block.images?.length)
9094
+ return {
9095
+ content: marker,
9096
+ tool_use_id: block.tool_use_id,
9097
+ type: block.type
9098
+ };
9029
9099
  return block.content.length > marker.length ? { ...block, content: marker } : block;
9030
9100
  })
9031
9101
  }));
@@ -9167,10 +9237,11 @@ export {
9167
9237
  streamAIWithTools,
9168
9238
  streamWithAIContext,
9169
9239
  tableCard,
9240
+ toolOutputText,
9170
9241
  verifyOpenRouterWebhookSignature,
9171
9242
  withResilience,
9172
9243
  xai
9173
9244
  };
9174
9245
 
9175
- //# debugId=A58174807DA8A73664756E2164756E21
9246
+ //# debugId=9A889A121344253764756E2164756E21
9176
9247
  //# sourceMappingURL=index.js.map