@eko-ai/eko 1.3.4 → 2.0.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.
Files changed (161) hide show
  1. package/README.md +37 -19
  2. package/dist/agent/a2a.d.ts +7 -0
  3. package/dist/agent/a2a.d.ts.map +1 -0
  4. package/dist/agent/base.d.ts +47 -0
  5. package/dist/agent/base.d.ts.map +1 -0
  6. package/dist/agent/browser/browser_base.d.ts +30 -0
  7. package/dist/agent/browser/browser_base.d.ts.map +1 -0
  8. package/dist/agent/browser/browser_labels.d.ts +21 -0
  9. package/dist/agent/browser/browser_labels.d.ts.map +1 -0
  10. package/dist/agent/browser/browser_screen.d.ts +16 -0
  11. package/dist/agent/browser/browser_screen.d.ts.map +1 -0
  12. package/dist/agent/browser/build_dom_tree.d.ts +2 -0
  13. package/dist/agent/browser/build_dom_tree.d.ts.map +1 -0
  14. package/dist/agent/browser/index.d.ts +6 -0
  15. package/dist/agent/browser/index.d.ts.map +1 -0
  16. package/dist/agent/chat.d.ts +7 -0
  17. package/dist/agent/chat.d.ts.map +1 -0
  18. package/dist/agent/computer.d.ts +23 -0
  19. package/dist/agent/computer.d.ts.map +1 -0
  20. package/dist/agent/file.d.ts +14 -0
  21. package/dist/agent/file.d.ts.map +1 -0
  22. package/dist/agent/index.d.ts +9 -0
  23. package/dist/agent/index.d.ts.map +1 -0
  24. package/dist/agent/shell.d.ts +14 -0
  25. package/dist/agent/shell.d.ts.map +1 -0
  26. package/dist/agent/timer.d.ts +5 -0
  27. package/dist/agent/timer.d.ts.map +1 -0
  28. package/dist/common/log.d.ts +43 -2
  29. package/dist/common/log.d.ts.map +1 -0
  30. package/dist/common/utils.d.ts +12 -0
  31. package/dist/common/utils.d.ts.map +1 -0
  32. package/dist/common/xml.d.ts +7 -0
  33. package/dist/common/xml.d.ts.map +1 -0
  34. package/dist/config/index.d.ts +8 -0
  35. package/dist/config/index.d.ts.map +1 -0
  36. package/dist/core/chain.d.ts +45 -0
  37. package/dist/core/chain.d.ts.map +1 -0
  38. package/dist/core/context.d.ts +23 -0
  39. package/dist/core/context.d.ts.map +1 -0
  40. package/dist/core/index.d.ts +18 -0
  41. package/dist/core/index.d.ts.map +1 -0
  42. package/dist/core/plan.d.ts +11 -0
  43. package/dist/core/plan.d.ts.map +1 -0
  44. package/dist/index.cjs.js +18163 -10855
  45. package/dist/index.d.ts +13 -10
  46. package/dist/index.d.ts.map +1 -0
  47. package/dist/index.esm.js +18147 -10887
  48. package/dist/llm/index.d.ts +15 -0
  49. package/dist/llm/index.d.ts.map +1 -0
  50. package/dist/mcp/client.d.ts +28 -0
  51. package/dist/mcp/client.d.ts.map +1 -0
  52. package/dist/mcp/index.d.ts +28 -0
  53. package/dist/mcp/index.d.ts.map +1 -0
  54. package/dist/prompt/agent.d.ts +6 -0
  55. package/dist/prompt/agent.d.ts.map +1 -0
  56. package/dist/prompt/plan.d.ts +4 -0
  57. package/dist/prompt/plan.d.ts.map +1 -0
  58. package/dist/tools/foreach_task.d.ts +12 -0
  59. package/dist/tools/foreach_task.d.ts.map +1 -0
  60. package/dist/tools/human_interact.d.ts +12 -0
  61. package/dist/tools/human_interact.d.ts.map +1 -0
  62. package/dist/tools/index.d.ts +19 -0
  63. package/dist/tools/index.d.ts.map +1 -0
  64. package/dist/tools/task_node_status.d.ts +12 -0
  65. package/dist/tools/task_node_status.d.ts.map +1 -0
  66. package/dist/tools/variable_storage.d.ts +12 -0
  67. package/dist/tools/variable_storage.d.ts.map +1 -0
  68. package/dist/tools/watch_trigger.d.ts +12 -0
  69. package/dist/tools/watch_trigger.d.ts.map +1 -0
  70. package/dist/tools/wrapper.d.ts +12 -0
  71. package/dist/tools/wrapper.d.ts.map +1 -0
  72. package/dist/types/core.types.d.ts +114 -0
  73. package/dist/types/core.types.d.ts.map +1 -0
  74. package/dist/types/index.d.ts +3 -3
  75. package/dist/types/index.d.ts.map +1 -0
  76. package/dist/types/llm.types.d.ts +80 -51
  77. package/dist/types/llm.types.d.ts.map +1 -0
  78. package/dist/types/mcp.types.d.ts +35 -0
  79. package/dist/types/mcp.types.d.ts.map +1 -0
  80. package/dist/types/tools.types.d.ts +56 -152
  81. package/dist/types/tools.types.d.ts.map +1 -0
  82. package/package.json +18 -58
  83. package/dist/common/chrome/proxy.d.ts +0 -24
  84. package/dist/common/context-compressor.d.ts +0 -10
  85. package/dist/common/summarize-workflow.d.ts +0 -2
  86. package/dist/common/tools/cancel_workflow.d.ts +0 -9
  87. package/dist/common/tools/document_agent.d.ts +0 -8
  88. package/dist/common/tools/human.d.ts +0 -30
  89. package/dist/common/tools/index.d.ts +0 -4
  90. package/dist/common/tools/write_context.d.ts +0 -7
  91. package/dist/core/eko.d.ts +0 -30
  92. package/dist/core/tool-registry.d.ts +0 -13
  93. package/dist/extension/content/index.d.ts +0 -1
  94. package/dist/extension/core.d.ts +0 -11
  95. package/dist/extension/index.d.ts +0 -7
  96. package/dist/extension/script/bing.js +0 -25
  97. package/dist/extension/script/build_dom_tree.d.ts +0 -38
  98. package/dist/extension/script/build_dom_tree.js +0 -662
  99. package/dist/extension/script/common.js +0 -212
  100. package/dist/extension/script/duckduckgo.js +0 -25
  101. package/dist/extension/script/google.js +0 -26
  102. package/dist/extension/tools/browser.d.ts +0 -23
  103. package/dist/extension/tools/browser_action.d.ts +0 -20
  104. package/dist/extension/tools/export_file.d.ts +0 -18
  105. package/dist/extension/tools/extract_content.d.ts +0 -18
  106. package/dist/extension/tools/get_all_tabs.d.ts +0 -9
  107. package/dist/extension/tools/html_script.d.ts +0 -10
  108. package/dist/extension/tools/index.d.ts +0 -12
  109. package/dist/extension/tools/open_url.d.ts +0 -19
  110. package/dist/extension/tools/request_login.d.ts +0 -10
  111. package/dist/extension/tools/screenshot.d.ts +0 -18
  112. package/dist/extension/tools/switch_tab.d.ts +0 -8
  113. package/dist/extension/tools/tab_management.d.ts +0 -13
  114. package/dist/extension/tools/tool_returns_screenshot.d.ts +0 -8
  115. package/dist/extension/tools/web_search.d.ts +0 -18
  116. package/dist/extension/utils.d.ts +0 -31
  117. package/dist/extension.cjs.js +0 -2793
  118. package/dist/extension.esm.js +0 -2786
  119. package/dist/extension_content_script.js +0 -1078
  120. package/dist/fellou/computer.d.ts +0 -20
  121. package/dist/fellou/index.d.ts +0 -6
  122. package/dist/fellou/tools/computer_use.d.ts +0 -18
  123. package/dist/fellou.cjs.js +0 -238
  124. package/dist/fellou.esm.js +0 -235
  125. package/dist/models/action.d.ts +0 -33
  126. package/dist/models/workflow.d.ts +0 -25
  127. package/dist/nodejs/core.d.ts +0 -2
  128. package/dist/nodejs/index.d.ts +0 -3
  129. package/dist/nodejs/script/build_dom_tree.d.ts +0 -1
  130. package/dist/nodejs/tools/browser_use.d.ts +0 -28
  131. package/dist/nodejs/tools/command_execute.d.ts +0 -12
  132. package/dist/nodejs/tools/file_read.d.ts +0 -11
  133. package/dist/nodejs/tools/file_write.d.ts +0 -15
  134. package/dist/nodejs/tools/index.d.ts +0 -5
  135. package/dist/nodejs.cjs.js +0 -73507
  136. package/dist/nodejs.esm.js +0 -73504
  137. package/dist/schemas/workflow.schema.d.ts +0 -44
  138. package/dist/services/llm/claude-provider.d.ts +0 -12
  139. package/dist/services/llm/openai-provider.d.ts +0 -12
  140. package/dist/services/llm/provider-factory.d.ts +0 -4
  141. package/dist/services/parser/workflow-parser.d.ts +0 -23
  142. package/dist/services/workflow/generator.d.ts +0 -16
  143. package/dist/services/workflow/templates.d.ts +0 -8
  144. package/dist/types/action.types.d.ts +0 -53
  145. package/dist/types/eko.types.d.ts +0 -37
  146. package/dist/types/parser.types.d.ts +0 -9
  147. package/dist/types/workflow.types.d.ts +0 -57
  148. package/dist/utils/execution-logger.d.ts +0 -69
  149. package/dist/utils/sleep.d.ts +0 -1
  150. package/dist/web/core.d.ts +0 -2
  151. package/dist/web/index.d.ts +0 -5
  152. package/dist/web/script/build_dom_tree.d.ts +0 -10
  153. package/dist/web/tools/browser.d.ts +0 -21
  154. package/dist/web/tools/browser_use.d.ts +0 -19
  155. package/dist/web/tools/export_file.d.ts +0 -18
  156. package/dist/web/tools/extract_content.d.ts +0 -17
  157. package/dist/web/tools/html_script.d.ts +0 -10
  158. package/dist/web/tools/index.d.ts +0 -6
  159. package/dist/web/tools/screenshot.d.ts +0 -18
  160. package/dist/web.cjs.js +0 -9952
  161. package/dist/web.esm.js +0 -9948
@@ -1,2793 +0,0 @@
1
- 'use strict';
2
-
3
- var os = require('os');
4
- var path = require('path');
5
- var util = require('util');
6
-
7
- const prettyLogStyles = {
8
- reset: [0, 0],
9
- bold: [1, 22],
10
- dim: [2, 22],
11
- italic: [3, 23],
12
- underline: [4, 24],
13
- overline: [53, 55],
14
- inverse: [7, 27],
15
- hidden: [8, 28],
16
- strikethrough: [9, 29],
17
- black: [30, 39],
18
- red: [31, 39],
19
- green: [32, 39],
20
- yellow: [33, 39],
21
- blue: [34, 39],
22
- magenta: [35, 39],
23
- cyan: [36, 39],
24
- white: [37, 39],
25
- blackBright: [90, 39],
26
- redBright: [91, 39],
27
- greenBright: [92, 39],
28
- yellowBright: [93, 39],
29
- blueBright: [94, 39],
30
- magentaBright: [95, 39],
31
- cyanBright: [96, 39],
32
- whiteBright: [97, 39],
33
- bgBlack: [40, 49],
34
- bgRed: [41, 49],
35
- bgGreen: [42, 49],
36
- bgYellow: [43, 49],
37
- bgBlue: [44, 49],
38
- bgMagenta: [45, 49],
39
- bgCyan: [46, 49],
40
- bgWhite: [47, 49],
41
- bgBlackBright: [100, 49],
42
- bgRedBright: [101, 49],
43
- bgGreenBright: [102, 49],
44
- bgYellowBright: [103, 49],
45
- bgBlueBright: [104, 49],
46
- bgMagentaBright: [105, 49],
47
- bgCyanBright: [106, 49],
48
- bgWhiteBright: [107, 49],
49
- };
50
-
51
- function formatTemplate(settings, template, values, hideUnsetPlaceholder = false) {
52
- const templateString = String(template);
53
- const ansiColorWrap = (placeholderValue, code) => `\u001b[${code[0]}m${placeholderValue}\u001b[${code[1]}m`;
54
- const styleWrap = (value, style) => {
55
- if (style != null && typeof style === "string") {
56
- return ansiColorWrap(value, prettyLogStyles[style]);
57
- }
58
- else if (style != null && Array.isArray(style)) {
59
- return style.reduce((prevValue, thisStyle) => styleWrap(prevValue, thisStyle), value);
60
- }
61
- else {
62
- if (style != null && style[value.trim()] != null) {
63
- return styleWrap(value, style[value.trim()]);
64
- }
65
- else if (style != null && style["*"] != null) {
66
- return styleWrap(value, style["*"]);
67
- }
68
- else {
69
- return value;
70
- }
71
- }
72
- };
73
- const defaultStyle = null;
74
- return templateString.replace(/{{(.+?)}}/g, (_, placeholder) => {
75
- const value = values[placeholder] != null ? String(values[placeholder]) : hideUnsetPlaceholder ? "" : _;
76
- return settings.stylePrettyLogs
77
- ? styleWrap(value, settings?.prettyLogStyles?.[placeholder] ?? defaultStyle) + ansiColorWrap("", prettyLogStyles.reset)
78
- : value;
79
- });
80
- }
81
-
82
- function formatNumberAddZeros(value, digits = 2, addNumber = 0) {
83
- if (value != null && isNaN(value)) {
84
- return "";
85
- }
86
- value = value != null ? value + addNumber : value;
87
- return digits === 2
88
- ? value == null
89
- ? "--"
90
- : value < 10
91
- ? "0" + value
92
- : value.toString()
93
- : value == null
94
- ? "---"
95
- : value < 10
96
- ? "00" + value
97
- : value < 100
98
- ? "0" + value
99
- : value.toString();
100
- }
101
-
102
- function urlToObject(url) {
103
- return {
104
- href: url.href,
105
- protocol: url.protocol,
106
- username: url.username,
107
- password: url.password,
108
- host: url.host,
109
- hostname: url.hostname,
110
- port: url.port,
111
- pathname: url.pathname,
112
- search: url.search,
113
- searchParams: [...url.searchParams].map(([key, value]) => ({ key, value })),
114
- hash: url.hash,
115
- origin: url.origin,
116
- };
117
- }
118
-
119
- var Runtime = {
120
- getCallerStackFrame,
121
- getErrorTrace,
122
- getMeta,
123
- transportJSON,
124
- transportFormatted: transportFormatted$1,
125
- isBuffer,
126
- isError,
127
- prettyFormatLogObj,
128
- prettyFormatErrorObj,
129
- };
130
- const meta = {
131
- runtime: "Nodejs",
132
- runtimeVersion: process?.version,
133
- hostname: os.hostname ? os.hostname() : undefined,
134
- };
135
- function getMeta(logLevelId, logLevelName, stackDepthLevel, hideLogPositionForPerformance, name, parentNames) {
136
- return Object.assign({}, meta, {
137
- name,
138
- parentNames,
139
- date: new Date(),
140
- logLevelId,
141
- logLevelName,
142
- path: !hideLogPositionForPerformance ? getCallerStackFrame(stackDepthLevel) : undefined,
143
- });
144
- }
145
- function getCallerStackFrame(stackDepthLevel, error = Error()) {
146
- return stackLineToStackFrame(error?.stack?.split("\n")?.filter((thisLine) => thisLine.includes(" at "))?.[stackDepthLevel]);
147
- }
148
- function getErrorTrace(error) {
149
- return error?.stack?.split("\n")?.reduce((result, line) => {
150
- if (line.includes(" at ")) {
151
- result.push(stackLineToStackFrame(line));
152
- }
153
- return result;
154
- }, []);
155
- }
156
- function stackLineToStackFrame(line) {
157
- const pathResult = {
158
- fullFilePath: undefined,
159
- fileName: undefined,
160
- fileNameWithLine: undefined,
161
- fileColumn: undefined,
162
- fileLine: undefined,
163
- filePath: undefined,
164
- filePathWithLine: undefined,
165
- method: undefined,
166
- };
167
- if (line != null && line.includes(" at ")) {
168
- line = line.replace(/^\s+at\s+/gm, "");
169
- const errorStackLine = line.split(" (");
170
- const fullFilePath = line?.slice(-1) === ")" ? line?.match(/\(([^)]+)\)/)?.[1] : line;
171
- const pathArray = fullFilePath?.includes(":") ? fullFilePath?.replace("file://", "")?.replace(process.cwd(), "")?.split(":") : undefined;
172
- const fileColumn = pathArray?.pop();
173
- const fileLine = pathArray?.pop();
174
- const filePath = pathArray?.pop();
175
- const filePathWithLine = path.normalize(`${filePath}:${fileLine}`);
176
- const fileName = filePath?.split("/")?.pop();
177
- const fileNameWithLine = `${fileName}:${fileLine}`;
178
- if (filePath != null && filePath.length > 0) {
179
- pathResult.fullFilePath = fullFilePath;
180
- pathResult.fileName = fileName;
181
- pathResult.fileNameWithLine = fileNameWithLine;
182
- pathResult.fileColumn = fileColumn;
183
- pathResult.fileLine = fileLine;
184
- pathResult.filePath = filePath;
185
- pathResult.filePathWithLine = filePathWithLine;
186
- pathResult.method = errorStackLine?.[1] != null ? errorStackLine?.[0] : undefined;
187
- }
188
- }
189
- return pathResult;
190
- }
191
- function isError(e) {
192
- return util.types?.isNativeError != null ? util.types.isNativeError(e) : e instanceof Error;
193
- }
194
- function prettyFormatLogObj(maskedArgs, settings) {
195
- return maskedArgs.reduce((result, arg) => {
196
- isError(arg) ? result.errors.push(prettyFormatErrorObj(arg, settings)) : result.args.push(arg);
197
- return result;
198
- }, { args: [], errors: [] });
199
- }
200
- function prettyFormatErrorObj(error, settings) {
201
- const errorStackStr = getErrorTrace(error).map((stackFrame) => {
202
- return formatTemplate(settings, settings.prettyErrorStackTemplate, { ...stackFrame }, true);
203
- });
204
- const placeholderValuesError = {
205
- errorName: ` ${error.name} `,
206
- errorMessage: Object.getOwnPropertyNames(error)
207
- .reduce((result, key) => {
208
- if (key !== "stack") {
209
- result.push(error[key]);
210
- }
211
- return result;
212
- }, [])
213
- .join(", "),
214
- errorStack: errorStackStr.join("\n"),
215
- };
216
- return formatTemplate(settings, settings.prettyErrorTemplate, placeholderValuesError);
217
- }
218
- function transportFormatted$1(logMetaMarkup, logArgs, logErrors, settings) {
219
- const logErrorsStr = (logErrors.length > 0 && logArgs.length > 0 ? "\n" : "") + logErrors.join("\n");
220
- settings.prettyInspectOptions.colors = settings.stylePrettyLogs;
221
- console.log(logMetaMarkup + util.formatWithOptions(settings.prettyInspectOptions, ...logArgs) + logErrorsStr);
222
- }
223
- function transportJSON(json) {
224
- console.log(jsonStringifyRecursive(json));
225
- function jsonStringifyRecursive(obj) {
226
- const cache = new Set();
227
- return JSON.stringify(obj, (key, value) => {
228
- if (typeof value === "object" && value !== null) {
229
- if (cache.has(value)) {
230
- return "[Circular]";
231
- }
232
- cache.add(value);
233
- }
234
- if (typeof value === "bigint") {
235
- return `${value}`;
236
- }
237
- if (typeof value === "undefined") {
238
- return "[undefined]";
239
- }
240
- return value;
241
- });
242
- }
243
- }
244
- function isBuffer(arg) {
245
- return Buffer.isBuffer(arg);
246
- }
247
-
248
- class BaseLogger {
249
- constructor(settings, logObj, stackDepthLevel = 4) {
250
- this.logObj = logObj;
251
- this.stackDepthLevel = stackDepthLevel;
252
- this.runtime = Runtime;
253
- this.settings = {
254
- type: settings?.type ?? "pretty",
255
- name: settings?.name,
256
- parentNames: settings?.parentNames,
257
- minLevel: settings?.minLevel ?? 0,
258
- argumentsArrayName: settings?.argumentsArrayName,
259
- hideLogPositionForProduction: settings?.hideLogPositionForProduction ?? false,
260
- prettyLogTemplate: settings?.prettyLogTemplate ??
261
- "{{yyyy}}.{{mm}}.{{dd}} {{hh}}:{{MM}}:{{ss}}:{{ms}}\t{{logLevelName}}\t{{filePathWithLine}}{{nameWithDelimiterPrefix}}\t",
262
- prettyErrorTemplate: settings?.prettyErrorTemplate ?? "\n{{errorName}} {{errorMessage}}\nerror stack:\n{{errorStack}}",
263
- prettyErrorStackTemplate: settings?.prettyErrorStackTemplate ?? " • {{fileName}}\t{{method}}\n\t{{filePathWithLine}}",
264
- prettyErrorParentNamesSeparator: settings?.prettyErrorParentNamesSeparator ?? ":",
265
- prettyErrorLoggerNameDelimiter: settings?.prettyErrorLoggerNameDelimiter ?? "\t",
266
- stylePrettyLogs: settings?.stylePrettyLogs ?? true,
267
- prettyLogTimeZone: settings?.prettyLogTimeZone ?? "UTC",
268
- prettyLogStyles: settings?.prettyLogStyles ?? {
269
- logLevelName: {
270
- "*": ["bold", "black", "bgWhiteBright", "dim"],
271
- SILLY: ["bold", "white"],
272
- TRACE: ["bold", "whiteBright"],
273
- DEBUG: ["bold", "green"],
274
- INFO: ["bold", "blue"],
275
- WARN: ["bold", "yellow"],
276
- ERROR: ["bold", "red"],
277
- FATAL: ["bold", "redBright"],
278
- },
279
- dateIsoStr: "white",
280
- filePathWithLine: "white",
281
- name: ["white", "bold"],
282
- nameWithDelimiterPrefix: ["white", "bold"],
283
- nameWithDelimiterSuffix: ["white", "bold"],
284
- errorName: ["bold", "bgRedBright", "whiteBright"],
285
- fileName: ["yellow"],
286
- fileNameWithLine: "white",
287
- },
288
- prettyInspectOptions: settings?.prettyInspectOptions ?? {
289
- colors: true,
290
- compact: false,
291
- depth: Infinity,
292
- },
293
- metaProperty: settings?.metaProperty ?? "_meta",
294
- maskPlaceholder: settings?.maskPlaceholder ?? "[***]",
295
- maskValuesOfKeys: settings?.maskValuesOfKeys ?? ["password"],
296
- maskValuesOfKeysCaseInsensitive: settings?.maskValuesOfKeysCaseInsensitive ?? false,
297
- maskValuesRegEx: settings?.maskValuesRegEx,
298
- prefix: [...(settings?.prefix ?? [])],
299
- attachedTransports: [...(settings?.attachedTransports ?? [])],
300
- overwrite: {
301
- mask: settings?.overwrite?.mask,
302
- toLogObj: settings?.overwrite?.toLogObj,
303
- addMeta: settings?.overwrite?.addMeta,
304
- addPlaceholders: settings?.overwrite?.addPlaceholders,
305
- formatMeta: settings?.overwrite?.formatMeta,
306
- formatLogObj: settings?.overwrite?.formatLogObj,
307
- transportFormatted: settings?.overwrite?.transportFormatted,
308
- transportJSON: settings?.overwrite?.transportJSON,
309
- },
310
- };
311
- }
312
- log(logLevelId, logLevelName, ...args) {
313
- if (logLevelId < this.settings.minLevel) {
314
- return;
315
- }
316
- const logArgs = [...this.settings.prefix, ...args];
317
- const maskedArgs = this.settings.overwrite?.mask != null
318
- ? this.settings.overwrite?.mask(logArgs)
319
- : this.settings.maskValuesOfKeys != null && this.settings.maskValuesOfKeys.length > 0
320
- ? this._mask(logArgs)
321
- : logArgs;
322
- const thisLogObj = this.logObj != null ? this._recursiveCloneAndExecuteFunctions(this.logObj) : undefined;
323
- const logObj = this.settings.overwrite?.toLogObj != null ? this.settings.overwrite?.toLogObj(maskedArgs, thisLogObj) : this._toLogObj(maskedArgs, thisLogObj);
324
- const logObjWithMeta = this.settings.overwrite?.addMeta != null
325
- ? this.settings.overwrite?.addMeta(logObj, logLevelId, logLevelName)
326
- : this._addMetaToLogObj(logObj, logLevelId, logLevelName);
327
- let logMetaMarkup;
328
- let logArgsAndErrorsMarkup = undefined;
329
- if (this.settings.overwrite?.formatMeta != null) {
330
- logMetaMarkup = this.settings.overwrite?.formatMeta(logObjWithMeta?.[this.settings.metaProperty]);
331
- }
332
- if (this.settings.overwrite?.formatLogObj != null) {
333
- logArgsAndErrorsMarkup = this.settings.overwrite?.formatLogObj(maskedArgs, this.settings);
334
- }
335
- if (this.settings.type === "pretty") {
336
- logMetaMarkup = logMetaMarkup ?? this._prettyFormatLogObjMeta(logObjWithMeta?.[this.settings.metaProperty]);
337
- logArgsAndErrorsMarkup = logArgsAndErrorsMarkup ?? this.runtime.prettyFormatLogObj(maskedArgs, this.settings);
338
- }
339
- if (logMetaMarkup != null && logArgsAndErrorsMarkup != null) {
340
- this.settings.overwrite?.transportFormatted != null
341
- ? this.settings.overwrite?.transportFormatted(logMetaMarkup, logArgsAndErrorsMarkup.args, logArgsAndErrorsMarkup.errors, this.settings)
342
- : this.runtime.transportFormatted(logMetaMarkup, logArgsAndErrorsMarkup.args, logArgsAndErrorsMarkup.errors, this.settings);
343
- }
344
- else {
345
- this.settings.overwrite?.transportJSON != null
346
- ? this.settings.overwrite?.transportJSON(logObjWithMeta)
347
- : this.settings.type !== "hidden"
348
- ? this.runtime.transportJSON(logObjWithMeta)
349
- : undefined;
350
- }
351
- if (this.settings.attachedTransports != null && this.settings.attachedTransports.length > 0) {
352
- this.settings.attachedTransports.forEach((transportLogger) => {
353
- transportLogger(logObjWithMeta);
354
- });
355
- }
356
- return logObjWithMeta;
357
- }
358
- attachTransport(transportLogger) {
359
- this.settings.attachedTransports.push(transportLogger);
360
- }
361
- getSubLogger(settings, logObj) {
362
- const subLoggerSettings = {
363
- ...this.settings,
364
- ...settings,
365
- parentNames: this.settings?.parentNames != null && this.settings?.name != null
366
- ? [...this.settings.parentNames, this.settings.name]
367
- : this.settings?.name != null
368
- ? [this.settings.name]
369
- : undefined,
370
- prefix: [...this.settings.prefix, ...(settings?.prefix ?? [])],
371
- };
372
- const subLogger = new this.constructor(subLoggerSettings, logObj ?? this.logObj, this.stackDepthLevel);
373
- return subLogger;
374
- }
375
- _mask(args) {
376
- const maskValuesOfKeys = this.settings.maskValuesOfKeysCaseInsensitive !== true ? this.settings.maskValuesOfKeys : this.settings.maskValuesOfKeys.map((key) => key.toLowerCase());
377
- return args?.map((arg) => {
378
- return this._recursiveCloneAndMaskValuesOfKeys(arg, maskValuesOfKeys);
379
- });
380
- }
381
- _recursiveCloneAndMaskValuesOfKeys(source, keys, seen = []) {
382
- if (seen.includes(source)) {
383
- return { ...source };
384
- }
385
- if (typeof source === "object" && source !== null) {
386
- seen.push(source);
387
- }
388
- if (this.runtime.isError(source) || this.runtime.isBuffer(source)) {
389
- return source;
390
- }
391
- else if (source instanceof Map) {
392
- return new Map(source);
393
- }
394
- else if (source instanceof Set) {
395
- return new Set(source);
396
- }
397
- else if (Array.isArray(source)) {
398
- return source.map((item) => this._recursiveCloneAndMaskValuesOfKeys(item, keys, seen));
399
- }
400
- else if (source instanceof Date) {
401
- return new Date(source.getTime());
402
- }
403
- else if (source instanceof URL) {
404
- return urlToObject(source);
405
- }
406
- else if (source !== null && typeof source === "object") {
407
- const baseObject = this.runtime.isError(source) ? this._cloneError(source) : Object.create(Object.getPrototypeOf(source));
408
- return Object.getOwnPropertyNames(source).reduce((o, prop) => {
409
- o[prop] = keys.includes(this.settings?.maskValuesOfKeysCaseInsensitive !== true ? prop : prop.toLowerCase())
410
- ? this.settings.maskPlaceholder
411
- : (() => {
412
- try {
413
- return this._recursiveCloneAndMaskValuesOfKeys(source[prop], keys, seen);
414
- }
415
- catch (e) {
416
- return null;
417
- }
418
- })();
419
- return o;
420
- }, baseObject);
421
- }
422
- else {
423
- if (typeof source === "string") {
424
- let modifiedSource = source;
425
- for (const regEx of this.settings?.maskValuesRegEx || []) {
426
- modifiedSource = modifiedSource.replace(regEx, this.settings?.maskPlaceholder || "");
427
- }
428
- return modifiedSource;
429
- }
430
- return source;
431
- }
432
- }
433
- _recursiveCloneAndExecuteFunctions(source, seen = []) {
434
- if (this.isObjectOrArray(source) && seen.includes(source)) {
435
- return this.shallowCopy(source);
436
- }
437
- if (this.isObjectOrArray(source)) {
438
- seen.push(source);
439
- }
440
- if (Array.isArray(source)) {
441
- return source.map((item) => this._recursiveCloneAndExecuteFunctions(item, seen));
442
- }
443
- else if (source instanceof Date) {
444
- return new Date(source.getTime());
445
- }
446
- else if (this.isObject(source)) {
447
- return Object.getOwnPropertyNames(source).reduce((o, prop) => {
448
- const descriptor = Object.getOwnPropertyDescriptor(source, prop);
449
- if (descriptor) {
450
- Object.defineProperty(o, prop, descriptor);
451
- const value = source[prop];
452
- o[prop] = typeof value === "function" ? value() : this._recursiveCloneAndExecuteFunctions(value, seen);
453
- }
454
- return o;
455
- }, Object.create(Object.getPrototypeOf(source)));
456
- }
457
- else {
458
- return source;
459
- }
460
- }
461
- isObjectOrArray(value) {
462
- return typeof value === "object" && value !== null;
463
- }
464
- isObject(value) {
465
- return typeof value === "object" && !Array.isArray(value) && value !== null;
466
- }
467
- shallowCopy(source) {
468
- if (Array.isArray(source)) {
469
- return [...source];
470
- }
471
- else {
472
- return { ...source };
473
- }
474
- }
475
- _toLogObj(args, clonedLogObj = {}) {
476
- args = args?.map((arg) => (this.runtime.isError(arg) ? this._toErrorObject(arg) : arg));
477
- if (this.settings.argumentsArrayName == null) {
478
- if (args.length === 1 && !Array.isArray(args[0]) && this.runtime.isBuffer(args[0]) !== true && !(args[0] instanceof Date)) {
479
- clonedLogObj = typeof args[0] === "object" && args[0] != null ? { ...args[0], ...clonedLogObj } : { 0: args[0], ...clonedLogObj };
480
- }
481
- else {
482
- clonedLogObj = { ...clonedLogObj, ...args };
483
- }
484
- }
485
- else {
486
- clonedLogObj = {
487
- ...clonedLogObj,
488
- [this.settings.argumentsArrayName]: args,
489
- };
490
- }
491
- return clonedLogObj;
492
- }
493
- _cloneError(error) {
494
- const cloned = new error.constructor();
495
- Object.getOwnPropertyNames(error).forEach((key) => {
496
- cloned[key] = error[key];
497
- });
498
- return cloned;
499
- }
500
- _toErrorObject(error) {
501
- return {
502
- nativeError: error,
503
- name: error.name ?? "Error",
504
- message: error.message,
505
- stack: this.runtime.getErrorTrace(error),
506
- };
507
- }
508
- _addMetaToLogObj(logObj, logLevelId, logLevelName) {
509
- return {
510
- ...logObj,
511
- [this.settings.metaProperty]: this.runtime.getMeta(logLevelId, logLevelName, this.stackDepthLevel, this.settings.hideLogPositionForProduction, this.settings.name, this.settings.parentNames),
512
- };
513
- }
514
- _prettyFormatLogObjMeta(logObjMeta) {
515
- if (logObjMeta == null) {
516
- return "";
517
- }
518
- let template = this.settings.prettyLogTemplate;
519
- const placeholderValues = {};
520
- if (template.includes("{{yyyy}}.{{mm}}.{{dd}} {{hh}}:{{MM}}:{{ss}}:{{ms}}")) {
521
- template = template.replace("{{yyyy}}.{{mm}}.{{dd}} {{hh}}:{{MM}}:{{ss}}:{{ms}}", "{{dateIsoStr}}");
522
- }
523
- else {
524
- if (this.settings.prettyLogTimeZone === "UTC") {
525
- placeholderValues["yyyy"] = logObjMeta?.date?.getUTCFullYear() ?? "----";
526
- placeholderValues["mm"] = formatNumberAddZeros(logObjMeta?.date?.getUTCMonth(), 2, 1);
527
- placeholderValues["dd"] = formatNumberAddZeros(logObjMeta?.date?.getUTCDate(), 2);
528
- placeholderValues["hh"] = formatNumberAddZeros(logObjMeta?.date?.getUTCHours(), 2);
529
- placeholderValues["MM"] = formatNumberAddZeros(logObjMeta?.date?.getUTCMinutes(), 2);
530
- placeholderValues["ss"] = formatNumberAddZeros(logObjMeta?.date?.getUTCSeconds(), 2);
531
- placeholderValues["ms"] = formatNumberAddZeros(logObjMeta?.date?.getUTCMilliseconds(), 3);
532
- }
533
- else {
534
- placeholderValues["yyyy"] = logObjMeta?.date?.getFullYear() ?? "----";
535
- placeholderValues["mm"] = formatNumberAddZeros(logObjMeta?.date?.getMonth(), 2, 1);
536
- placeholderValues["dd"] = formatNumberAddZeros(logObjMeta?.date?.getDate(), 2);
537
- placeholderValues["hh"] = formatNumberAddZeros(logObjMeta?.date?.getHours(), 2);
538
- placeholderValues["MM"] = formatNumberAddZeros(logObjMeta?.date?.getMinutes(), 2);
539
- placeholderValues["ss"] = formatNumberAddZeros(logObjMeta?.date?.getSeconds(), 2);
540
- placeholderValues["ms"] = formatNumberAddZeros(logObjMeta?.date?.getMilliseconds(), 3);
541
- }
542
- }
543
- const dateInSettingsTimeZone = this.settings.prettyLogTimeZone === "UTC" ? logObjMeta?.date : new Date(logObjMeta?.date?.getTime() - logObjMeta?.date?.getTimezoneOffset() * 60000);
544
- placeholderValues["rawIsoStr"] = dateInSettingsTimeZone?.toISOString();
545
- placeholderValues["dateIsoStr"] = dateInSettingsTimeZone?.toISOString().replace("T", " ").replace("Z", "");
546
- placeholderValues["logLevelName"] = logObjMeta?.logLevelName;
547
- placeholderValues["fileNameWithLine"] = logObjMeta?.path?.fileNameWithLine ?? "";
548
- placeholderValues["filePathWithLine"] = logObjMeta?.path?.filePathWithLine ?? "";
549
- placeholderValues["fullFilePath"] = logObjMeta?.path?.fullFilePath ?? "";
550
- let parentNamesString = this.settings.parentNames?.join(this.settings.prettyErrorParentNamesSeparator);
551
- parentNamesString = parentNamesString != null && logObjMeta?.name != null ? parentNamesString + this.settings.prettyErrorParentNamesSeparator : undefined;
552
- placeholderValues["name"] = logObjMeta?.name != null || parentNamesString != null ? (parentNamesString ?? "") + logObjMeta?.name ?? "" : "";
553
- placeholderValues["nameWithDelimiterPrefix"] =
554
- placeholderValues["name"].length > 0 ? this.settings.prettyErrorLoggerNameDelimiter + placeholderValues["name"] : "";
555
- placeholderValues["nameWithDelimiterSuffix"] =
556
- placeholderValues["name"].length > 0 ? placeholderValues["name"] + this.settings.prettyErrorLoggerNameDelimiter : "";
557
- if (this.settings.overwrite?.addPlaceholders != null) {
558
- this.settings.overwrite?.addPlaceholders(logObjMeta, placeholderValues);
559
- }
560
- return formatTemplate(this.settings, template, placeholderValues);
561
- }
562
- }
563
-
564
- class Logger extends BaseLogger {
565
- constructor(settings, logObj) {
566
- const isBrowser = typeof window !== "undefined" && typeof document !== "undefined";
567
- const isBrowserBlinkEngine = isBrowser ? window.chrome !== undefined && window.CSS !== undefined && window.CSS.supports("color", "green") : false;
568
- const isSafari = isBrowser ? /^((?!chrome|android).)*safari/i.test(navigator.userAgent) : false;
569
- settings = settings || {};
570
- settings.stylePrettyLogs = settings.stylePrettyLogs && isBrowser && !isBrowserBlinkEngine ? false : settings.stylePrettyLogs;
571
- super(settings, logObj, isSafari ? 4 : 5);
572
- }
573
- log(logLevelId, logLevelName, ...args) {
574
- return super.log(logLevelId, logLevelName, ...args);
575
- }
576
- silly(...args) {
577
- return super.log(0, "SILLY", ...args);
578
- }
579
- trace(...args) {
580
- return super.log(1, "TRACE", ...args);
581
- }
582
- debug(...args) {
583
- return super.log(2, "DEBUG", ...args);
584
- }
585
- info(...args) {
586
- return super.log(3, "INFO", ...args);
587
- }
588
- warn(...args) {
589
- return super.log(4, "WARN", ...args);
590
- }
591
- error(...args) {
592
- return super.log(5, "ERROR", ...args);
593
- }
594
- fatal(...args) {
595
- return super.log(6, "FATAL", ...args);
596
- }
597
- getSubLogger(settings, logObj) {
598
- return super.getSubLogger(settings, logObj);
599
- }
600
- }
601
-
602
- function transportFormatted(logMetaMarkup, logArgs, logErrors, settings) {
603
- settings.prettyInspectOptions.colors = settings.stylePrettyLogs;
604
- const logLevel = logMetaMarkup.trim().split(" ")[2];
605
- let logFunc;
606
- switch (logLevel) {
607
- case "WARN":
608
- logFunc = console.warn;
609
- break;
610
- case "ERROR":
611
- case "FATAL":
612
- logFunc = console.error;
613
- break;
614
- case "INFO":
615
- logFunc = console.info;
616
- break;
617
- case "DEBUG":
618
- case "TRACE":
619
- case "SILLY":
620
- default:
621
- logFunc = console.debug;
622
- break;
623
- }
624
- logFunc(logMetaMarkup, ...logArgs);
625
- logErrors.forEach(err => {
626
- console.error(logMetaMarkup + err);
627
- });
628
- }
629
- function formatMeta(logObjMeta) {
630
- if (!logObjMeta) {
631
- return '';
632
- }
633
- const { date, logLevelName } = logObjMeta;
634
- const year = date.getFullYear();
635
- const month = String(date.getMonth() + 1).padStart(2, '0');
636
- const day = String(date.getDate()).padStart(2, '0');
637
- const hours = String(date.getHours()).padStart(2, '0');
638
- const minutes = String(date.getMinutes()).padStart(2, '0');
639
- const seconds = String(date.getSeconds()).padStart(2, '0');
640
- const milliseconds = String(date.getMilliseconds()).padStart(3, '0');
641
- const formattedDate = `${year}-${month}-${day} ${hours}:${minutes}:${seconds}.${milliseconds}`;
642
- const loggerName = logObjMeta.name;
643
- return `${formattedDate} ${logLevelName} ${loggerName}`;
644
- }
645
- const logger = new Logger({
646
- name: "ekoLogger",
647
- overwrite: {
648
- transportFormatted,
649
- formatMeta,
650
- }
651
- });
652
-
653
- async function getWindowId(context) {
654
- let windowId = context.variables.get('windowId');
655
- if (windowId) {
656
- try {
657
- await context.ekoConfig.chromeProxy.windows.get(windowId);
658
- }
659
- catch (e) {
660
- windowId = null;
661
- context.variables.delete('windowId');
662
- let tabId = context.variables.get('tabId');
663
- if (tabId) {
664
- try {
665
- let tab = await context.ekoConfig.chromeProxy.tabs.get(tabId);
666
- windowId = tab.windowId;
667
- }
668
- catch (e) {
669
- context.variables.delete('tabId');
670
- }
671
- }
672
- }
673
- }
674
- if (!windowId) {
675
- const window = await context.ekoConfig.chromeProxy.windows.getCurrent();
676
- windowId = window.id;
677
- }
678
- // `window.FELLOU_WINDOW_ID` is a feature of Downstream Caller
679
- if (!windowId) {
680
- windowId = window.FELLOU_WINDOW_ID;
681
- }
682
- if (!windowId) {
683
- logger.warn("`getWindowId()` returns " + windowId);
684
- }
685
- return windowId;
686
- }
687
- async function getTabId(context) {
688
- logger.debug("getTabId()...");
689
- let tabs = await context.ekoConfig.chromeProxy.tabs.query({});
690
- logger.debug("all tabs:", tabs);
691
- const filtered = tabs.filter((tab) => tab.title && tab.url);
692
- logger.debug("filtered:", filtered);
693
- if (filtered.length > 0) {
694
- if (typeof filtered[0].activeTime != "undefined") {
695
- const sorted = filtered.sort((a, b) => parseInt(b.activeTime) - parseInt(a.activeTime));
696
- logger.debug("sorted tabs:", sorted);
697
- const tabId = sorted[0].id;
698
- logger.debug("tabId:", tabId);
699
- return tabId;
700
- }
701
- else {
702
- tabs = await context.ekoConfig.chromeProxy.tabs.query({ active: true, currentWindow: true });
703
- if (tabs.length > 0) {
704
- const tabId = tabs[0].id;
705
- logger.debug("tabId:", tabId);
706
- return tabId;
707
- }
708
- else {
709
- throw Error("no active tab found");
710
- }
711
- }
712
- }
713
- else {
714
- throw Error("no tab found");
715
- }
716
- }
717
- function getCurrentTabId(chromeProxy, windowId) {
718
- return new Promise((resolve, reject) => {
719
- logger.debug("debug the Promise in getCurrentTabId()...");
720
- logger.debug("get the active tabId on: ", { windowId });
721
- let queryInfo;
722
- if (windowId !== undefined) {
723
- logger.debug(`get the active tab in window (windowId=${windowId})...`);
724
- queryInfo = { windowId, active: true };
725
- }
726
- else {
727
- logger.debug(`get the active tabId on current window`);
728
- queryInfo = { active: true, currentWindow: true };
729
- }
730
- chromeProxy.tabs.query(queryInfo, (tabs) => {
731
- if (chromeProxy.runtime.lastError) {
732
- logger.error(`failed to get: `, chromeProxy.runtime.lastError);
733
- reject(chromeProxy.runtime.lastError);
734
- return;
735
- }
736
- if (tabs.length > 0) {
737
- logger.debug(`found the tab, ID=${tabs[0].id}`);
738
- resolve(tabs[0].id);
739
- }
740
- else {
741
- logger.debug(`cannot find the tab, returns undefined`);
742
- resolve(undefined);
743
- }
744
- });
745
- });
746
- }
747
- async function open_new_tab(chromeProxy, url, windowId) {
748
- if (!windowId) {
749
- const window = await chromeProxy.windows.getCurrent();
750
- windowId = window.id;
751
- }
752
- logger.debug("windowId: " + windowId);
753
- let tab = await chromeProxy.tabs.create({
754
- url: url,
755
- windowId: windowId,
756
- });
757
- logger.debug("chromeProxy.tabs.create() done");
758
- let tabId = tab.id;
759
- let completedTab = await waitForTabComplete(chromeProxy, tabId);
760
- logger.debug("waitForTabComplete() done");
761
- await sleep(200);
762
- logger.debug("sleep() done");
763
- return completedTab;
764
- }
765
- async function executeScript(chromeProxy, tabId, func, args) {
766
- let frameResults = await chromeProxy.scripting.executeScript({
767
- target: { tabId: tabId },
768
- func: func,
769
- args: args,
770
- });
771
- return frameResults[0].result;
772
- }
773
- async function waitForTabComplete(chromeProxy, tabId, timeout = 30000) {
774
- return new Promise(async (resolve, reject) => {
775
- logger.debug("debug waitForTabComplete()...");
776
- const time = setTimeout(async () => {
777
- logger.debug("listener(#1)=", listener);
778
- chromeProxy.tabs.onUpdated.removeListener(listener);
779
- logger.debug("tabId(#1)=", tabId);
780
- let tab = await chromeProxy.tabs.get(tabId);
781
- logger.debug("tab(#1)=", tab);
782
- if (tab.status === 'complete') {
783
- logger.warn('Timeout: waitForTabComplete, but tab is already complete.');
784
- resolve(tab);
785
- }
786
- else {
787
- logger.warn("Timeout: waitForTabComplete, and tab is not complete");
788
- resolve(tab);
789
- }
790
- }, timeout);
791
- logger.debug("setTimeout done");
792
- const listener = async (updatedTabId, changeInfo, tab) => {
793
- logger.debug("listener start...");
794
- if (updatedTabId === tabId && changeInfo.status === 'complete') {
795
- logger.debug("listener(#2)=", listener);
796
- chromeProxy.tabs.onUpdated.removeListener(listener);
797
- clearTimeout(time);
798
- resolve(tab);
799
- }
800
- };
801
- logger.debug("tabId(#2)=", tabId);
802
- let tab = await chromeProxy.tabs.get(tabId);
803
- logger.debug("tab(#2)=", tab);
804
- if (tab.status === 'complete') {
805
- resolve(tab);
806
- clearTimeout(time);
807
- return;
808
- }
809
- logger.debug("listener(#3)=", listener);
810
- chromeProxy.tabs.onUpdated.addListener(listener);
811
- logger.debug("debug waitForTabComplete()...done");
812
- });
813
- }
814
- async function doesTabExists(chromeProxy, tabId) {
815
- const tabExists = await new Promise((resolve) => {
816
- chromeProxy.tabs.get(tabId, (tab) => {
817
- if (chromeProxy.runtime.lastError) {
818
- resolve(false);
819
- }
820
- else {
821
- resolve(true);
822
- }
823
- });
824
- });
825
- return tabExists;
826
- }
827
- async function getPageSize(chromeProxy, tabId) {
828
- if (!tabId) {
829
- tabId = await getCurrentTabId(chromeProxy);
830
- }
831
- let injectionResult = await chromeProxy.scripting.executeScript({
832
- target: { tabId: tabId },
833
- func: () => [
834
- window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth,
835
- window.innerHeight || document.documentElement.clientHeight || document.body.clientHeight,
836
- ],
837
- });
838
- return [injectionResult[0].result[0], injectionResult[0].result[1]];
839
- }
840
- function sleep(time) {
841
- return new Promise((resolve) => setTimeout(() => resolve(), time));
842
- }
843
- async function injectScript(chromeProxy, tabId, filename) {
844
- let files = ['eko/script/common.js'];
845
- if (filename) {
846
- files.push('eko/script/' + filename);
847
- }
848
- await chromeProxy.scripting.executeScript({
849
- target: { tabId },
850
- files: files,
851
- });
852
- }
853
- class MsgEvent {
854
- constructor() {
855
- this.eventMap = {};
856
- }
857
- addListener(callback, id) {
858
- if (!id) {
859
- id = new Date().getTime() + '' + Math.floor(Math.random() * 10000);
860
- }
861
- this.eventMap[id] = callback;
862
- return id;
863
- }
864
- removeListener(id) {
865
- delete this.eventMap[id];
866
- }
867
- async publish(msg) {
868
- let values = Object.values(this.eventMap);
869
- for (let i = 0; i < values.length; i++) {
870
- try {
871
- let result = values[i](msg);
872
- if (isPromise(result)) {
873
- await result;
874
- }
875
- }
876
- catch (e) {
877
- logger.error(e);
878
- }
879
- }
880
- }
881
- }
882
- /**
883
- * Counter (Function: Wait for all asynchronous tasks to complete)
884
- */
885
- class CountDownLatch {
886
- constructor(count) {
887
- this.resolve = undefined;
888
- this.currentCount = count;
889
- }
890
- countDown() {
891
- this.currentCount = this.currentCount - 1;
892
- if (this.currentCount <= 0) {
893
- this.resolve && this.resolve();
894
- }
895
- }
896
- await(timeout) {
897
- const $this = this;
898
- return new Promise((_resolve, reject) => {
899
- let resolve = _resolve;
900
- if (timeout > 0) {
901
- let timeId = setTimeout(reject, timeout);
902
- resolve = () => {
903
- clearTimeout(timeId);
904
- _resolve();
905
- };
906
- }
907
- $this.resolve = resolve;
908
- if ($this.currentCount <= 0) {
909
- resolve();
910
- }
911
- });
912
- }
913
- }
914
- function isPromise(obj) {
915
- return (!!obj &&
916
- (typeof obj === 'object' || typeof obj === 'function') &&
917
- typeof obj.then === 'function');
918
- }
919
-
920
- var utils = /*#__PURE__*/Object.freeze({
921
- __proto__: null,
922
- CountDownLatch: CountDownLatch,
923
- MsgEvent: MsgEvent,
924
- doesTabExists: doesTabExists,
925
- executeScript: executeScript,
926
- getCurrentTabId: getCurrentTabId,
927
- getPageSize: getPageSize,
928
- getTabId: getTabId,
929
- getWindowId: getWindowId,
930
- injectScript: injectScript,
931
- isPromise: isPromise,
932
- open_new_tab: open_new_tab,
933
- sleep: sleep,
934
- waitForTabComplete: waitForTabComplete
935
- });
936
-
937
- function isFellouBrowser(chromeProxy) {
938
- const result = typeof chromeProxy.browseruse == 'object';
939
- logger.debug("isFellouBrowser", result);
940
- return result;
941
- }
942
- async function type(chromeProxy, tabId, text, coordinate) {
943
- const isFellou = isFellouBrowser(chromeProxy);
944
- logger.debug('Sending type message to tab:', tabId, { text, coordinate }, isFellou ? ' > fellou' : '');
945
- try {
946
- if (!coordinate) {
947
- coordinate = (await cursor_position(chromeProxy, tabId)).coordinate;
948
- }
949
- await mouse_move(chromeProxy, tabId, coordinate);
950
- let response;
951
- if (isFellou) {
952
- let enter = false;
953
- if (text.endsWith('\n')) {
954
- enter = true;
955
- text = text.substring(0, text.length - 1);
956
- }
957
- response = await chromeProxy.browseruse.type(tabId, text);
958
- if (enter) {
959
- await chromeProxy.browseruse.keyboard.press(tabId, 'Enter');
960
- }
961
- }
962
- else {
963
- response = await chromeProxy.tabs.sendMessage(tabId, {
964
- type: 'computer:type',
965
- text,
966
- coordinate,
967
- });
968
- }
969
- logger.debug('type Got response:', response);
970
- return response;
971
- }
972
- catch (e) {
973
- logger.error('Failed to send type message:', e);
974
- throw e;
975
- }
976
- }
977
- async function type_by(chromeProxy, tabId, text, xpath, highlightIndex) {
978
- const isFellou = isFellouBrowser(chromeProxy);
979
- logger.debug('Sending type_by message to tab:', tabId, { text, xpath, highlightIndex }, isFellou ? ' > fellou' : '');
980
- try {
981
- let response;
982
- if (isFellou) {
983
- let enter = false;
984
- if (text.endsWith('\n')) {
985
- enter = true;
986
- text = text.substring(0, text.length - 1);
987
- }
988
- response = await chromeProxy.browseruse.handle.type(tabId, build_fellou_handle_js(xpath, highlightIndex), text);
989
- if (enter) {
990
- await chromeProxy.browseruse.keyboard.press(tabId, 'Enter');
991
- }
992
- }
993
- else {
994
- response = await chromeProxy.tabs.sendMessage(tabId, {
995
- type: 'computer:type',
996
- text,
997
- xpath,
998
- highlightIndex,
999
- });
1000
- }
1001
- logger.debug('type_by Got response:', response);
1002
- return response;
1003
- }
1004
- catch (e) {
1005
- logger.error('Failed to send type message:', e);
1006
- throw e;
1007
- }
1008
- }
1009
- async function enter_by(chromeProxy, tabId, xpath, highlightIndex) {
1010
- const isFellou = isFellouBrowser(chromeProxy);
1011
- logger.debug('Sending enter_by message to tab:', tabId, { xpath, highlightIndex }, isFellou ? ' > fellou' : '');
1012
- try {
1013
- let response;
1014
- if (isFellou) {
1015
- response = await chromeProxy.browseruse.keyboard.press(tabId, 'Enter');
1016
- }
1017
- else {
1018
- response = await chromeProxy.tabs.sendMessage(tabId, {
1019
- type: 'computer:type',
1020
- text: '\n',
1021
- xpath,
1022
- highlightIndex,
1023
- });
1024
- }
1025
- logger.debug('enter_by Got response:', response);
1026
- return response;
1027
- }
1028
- catch (e) {
1029
- logger.error('Failed to send enter_by message:', e);
1030
- throw e;
1031
- }
1032
- }
1033
- async function clear_input(chromeProxy, tabId, coordinate) {
1034
- const isFellou = isFellouBrowser(chromeProxy);
1035
- logger.debug('Sending clear_input message to tab:', tabId, { coordinate }, isFellou ? ' > fellou' : '');
1036
- try {
1037
- if (!coordinate) {
1038
- coordinate = (await cursor_position(chromeProxy, tabId)).coordinate;
1039
- }
1040
- await mouse_move(chromeProxy, tabId, coordinate);
1041
- let response;
1042
- if (isFellou) {
1043
- await chromeProxy.browseruse.mouse.click(tabId, coordinate[0], coordinate[1], { count: 3 });
1044
- response = await chromeProxy.browseruse.keyboard.press(tabId, 'Backspace');
1045
- }
1046
- else {
1047
- response = await chromeProxy.tabs.sendMessage(tabId, {
1048
- type: 'computer:type',
1049
- text: '',
1050
- coordinate,
1051
- });
1052
- }
1053
- logger.debug('clear_input Got response:', response);
1054
- return response;
1055
- }
1056
- catch (e) {
1057
- logger.error('Failed to send clear_input message:', e);
1058
- throw e;
1059
- }
1060
- }
1061
- async function clear_input_by(chromeProxy, tabId, xpath, highlightIndex) {
1062
- const isFellou = isFellouBrowser(chromeProxy);
1063
- logger.debug('Sending clear_input_by message to tab:', tabId, { xpath, highlightIndex }, isFellou ? ' > fellou' : '');
1064
- try {
1065
- let response;
1066
- if (isFellou) {
1067
- await chromeProxy.browseruse.handle.click(tabId, build_fellou_handle_js(xpath, highlightIndex), { count: 3 });
1068
- response = await chromeProxy.browseruse.keyboard.press(tabId, 'Backspace');
1069
- }
1070
- else {
1071
- response = await chromeProxy.tabs.sendMessage(tabId, {
1072
- type: 'computer:type',
1073
- text: '',
1074
- xpath,
1075
- highlightIndex,
1076
- });
1077
- }
1078
- logger.debug('clear_input_by Got response:', response);
1079
- return response;
1080
- }
1081
- catch (e) {
1082
- logger.error('Failed to send clear_input_by message:', e);
1083
- throw e;
1084
- }
1085
- }
1086
- async function mouse_move(chromeProxy, tabId, coordinate) {
1087
- const isFellou = isFellouBrowser(chromeProxy);
1088
- logger.debug('Sending mouse_move message to tab:', tabId, { coordinate }, isFellou ? ' > fellou' : '');
1089
- let response;
1090
- if (isFellou) {
1091
- response = await chromeProxy.browseruse.mouse.move(tabId, coordinate[0], coordinate[1]);
1092
- }
1093
- else {
1094
- response = await chromeProxy.tabs.sendMessage(tabId, {
1095
- type: 'computer:mouse_move',
1096
- coordinate,
1097
- });
1098
- }
1099
- logger.debug('mouse_move Got response:', response);
1100
- return response;
1101
- }
1102
- async function left_click(chromeProxy, tabId, coordinate) {
1103
- const isFellou = isFellouBrowser(chromeProxy);
1104
- logger.debug('Sending left_click message to tab:', tabId, { coordinate }, isFellou ? ' > fellou' : '');
1105
- if (!coordinate) {
1106
- coordinate = (await cursor_position(chromeProxy, tabId)).coordinate;
1107
- }
1108
- let response;
1109
- if (isFellou) {
1110
- response = await chromeProxy.browseruse.mouse.click(tabId, coordinate[0], coordinate[1]);
1111
- }
1112
- else {
1113
- response = await chromeProxy.tabs.sendMessage(tabId, {
1114
- type: 'computer:left_click',
1115
- coordinate,
1116
- });
1117
- }
1118
- logger.debug('left_click Got response:', response);
1119
- return response;
1120
- }
1121
- async function left_click_by(chromeProxy, tabId, xpath, highlightIndex) {
1122
- const isFellou = isFellouBrowser(chromeProxy);
1123
- logger.debug('Sending left_click_by message to tab:', tabId, { xpath, highlightIndex }, isFellou ? ' > fellou' : '');
1124
- let response;
1125
- if (isFellou) {
1126
- response = await chromeProxy.browseruse.handle.click(tabId, build_fellou_handle_js(xpath, highlightIndex));
1127
- }
1128
- else {
1129
- response = await chromeProxy.tabs.sendMessage(tabId, {
1130
- type: 'computer:left_click',
1131
- xpath,
1132
- highlightIndex,
1133
- });
1134
- }
1135
- logger.debug('left_click_by Got response:', response);
1136
- return response;
1137
- }
1138
- async function right_click(chromeProxy, tabId, coordinate) {
1139
- const isFellou = isFellouBrowser(chromeProxy);
1140
- logger.debug('Sending right_click message to tab:', tabId, { coordinate }, isFellou ? ' > fellou' : '');
1141
- if (!coordinate) {
1142
- coordinate = (await cursor_position(chromeProxy, tabId)).coordinate;
1143
- }
1144
- let response;
1145
- if (isFellou) {
1146
- response = await chromeProxy.browseruse.mouse.click(tabId, coordinate[0], coordinate[1], { button: 'right' });
1147
- }
1148
- else {
1149
- await chromeProxy.tabs.sendMessage(tabId, {
1150
- type: 'computer:right_click',
1151
- coordinate,
1152
- });
1153
- }
1154
- logger.debug('right_click Got response:', response);
1155
- return response;
1156
- }
1157
- async function right_click_by(chromeProxy, tabId, xpath, highlightIndex) {
1158
- const isFellou = isFellouBrowser(chromeProxy);
1159
- logger.debug('Sending right_click_by message to tab:', tabId, { xpath, highlightIndex }, isFellou ? ' > fellou' : '');
1160
- let response;
1161
- if (isFellou) {
1162
- response = await chromeProxy.browseruse.handle.click(tabId, build_fellou_handle_js(xpath, highlightIndex), { button: 'right' });
1163
- }
1164
- else {
1165
- await chromeProxy.tabs.sendMessage(tabId, {
1166
- type: 'computer:right_click',
1167
- xpath,
1168
- highlightIndex,
1169
- });
1170
- }
1171
- logger.debug('right_click_by Got response:', response);
1172
- return response;
1173
- }
1174
- async function double_click(chromeProxy, tabId, coordinate) {
1175
- const isFellou = isFellouBrowser(chromeProxy);
1176
- logger.debug('Sending double_click message to tab:', tabId, { coordinate }, isFellou ? ' > fellou' : '');
1177
- if (!coordinate) {
1178
- coordinate = (await cursor_position(chromeProxy, tabId)).coordinate;
1179
- }
1180
- let response;
1181
- if (isFellou) {
1182
- response = await chromeProxy.browseruse.mouse.click(tabId, coordinate[0], coordinate[1], { count: 2 });
1183
- }
1184
- else {
1185
- response = await chromeProxy.tabs.sendMessage(tabId, {
1186
- type: 'computer:double_click',
1187
- coordinate,
1188
- });
1189
- }
1190
- logger.debug('double_click Got response:', response);
1191
- return response;
1192
- }
1193
- async function double_click_by(chromeProxy, tabId, xpath, highlightIndex) {
1194
- const isFellou = isFellouBrowser(chromeProxy);
1195
- logger.debug('Sending double_click_by message to tab:', tabId, { xpath, highlightIndex }, isFellou ? ' > fellou' : '');
1196
- let response;
1197
- if (isFellou) {
1198
- response = await chromeProxy.browseruse.mouse.click(tabId, build_fellou_handle_js(xpath, highlightIndex), { count: 2 });
1199
- }
1200
- else {
1201
- response = await chromeProxy.tabs.sendMessage(tabId, {
1202
- type: 'computer:double_click',
1203
- xpath,
1204
- highlightIndex,
1205
- });
1206
- }
1207
- logger.debug('double_click_by Got response:', response);
1208
- return response;
1209
- }
1210
- async function screenshot(chromeProxy, windowId, compress) {
1211
- logger.debug('Taking screenshot of window:', windowId, { compress });
1212
- try {
1213
- let dataUrl;
1214
- if (compress) {
1215
- dataUrl = await chromeProxy.tabs.captureVisibleTab(windowId, {
1216
- format: 'jpeg',
1217
- quality: 60, // 0-100
1218
- });
1219
- dataUrl = await compress_image(dataUrl, 0.7, 1);
1220
- }
1221
- else {
1222
- dataUrl = await chromeProxy.tabs.captureVisibleTab(windowId, {
1223
- format: 'jpeg',
1224
- quality: 50,
1225
- });
1226
- }
1227
- let data = dataUrl.substring(dataUrl.indexOf('base64,') + 7);
1228
- const result = {
1229
- image: {
1230
- type: 'base64',
1231
- media_type: dataUrl.indexOf('image/png') > -1 ? 'image/png' : 'image/jpeg',
1232
- data: data,
1233
- },
1234
- };
1235
- logger.debug('screenshot Got screenshot result:', result);
1236
- if (!data || data.length < 30) {
1237
- throw new Error('image error');
1238
- }
1239
- return result;
1240
- }
1241
- catch (e) {
1242
- if (isFellouBrowser(chromeProxy)) {
1243
- logger.debug('Failed to take screenshot, try fellou...');
1244
- const tabId = await getCurrentTabId(chromeProxy, windowId);
1245
- const base64 = await chromeProxy.browseruse.screenshot(tabId, {
1246
- type: 'jpeg',
1247
- quality: 60,
1248
- encoding: 'base64',
1249
- });
1250
- const result = {
1251
- image: {
1252
- type: 'base64',
1253
- media_type: 'image/jpeg',
1254
- data: base64,
1255
- },
1256
- };
1257
- logger.debug('screenshot Got screenshot result, try fellou:', result);
1258
- return result;
1259
- }
1260
- logger.error('Failed to take screenshot:', e);
1261
- throw e;
1262
- }
1263
- }
1264
- async function compress_image(dataUrl, scale = 0.8, quality = 0.8) {
1265
- logger.debug('Compressing image', { scale, quality });
1266
- try {
1267
- const bitmap = await createImageBitmap(await (await fetch(dataUrl)).blob());
1268
- let width = bitmap.width * scale;
1269
- let height = bitmap.height * scale;
1270
- const canvas = new OffscreenCanvas(width, height);
1271
- const ctx = canvas.getContext('2d');
1272
- ctx.drawImage(bitmap, 0, 0, width, height);
1273
- const blob = await canvas.convertToBlob({
1274
- type: 'image/jpeg',
1275
- quality: quality,
1276
- });
1277
- return new Promise((resolve) => {
1278
- const reader = new FileReader();
1279
- reader.onloadend = () => {
1280
- const result = reader.result;
1281
- logger.debug('Got compressed image result (sliced):', result.slice(0, 200));
1282
- resolve(result);
1283
- };
1284
- reader.onerror = () => {
1285
- resolve(dataUrl);
1286
- };
1287
- reader.readAsDataURL(blob);
1288
- });
1289
- }
1290
- catch (e) {
1291
- logger.error('Failed to compress image:', e);
1292
- return dataUrl;
1293
- }
1294
- }
1295
- async function scroll_to(chromeProxy, tabId, coordinate) {
1296
- logger.debug('Sending scroll_to message to tab:', tabId, { coordinate });
1297
- let from_coordinate = (await cursor_position(chromeProxy, tabId)).coordinate;
1298
- const response = await chromeProxy.tabs.sendMessage(tabId, {
1299
- type: 'computer:scroll_to',
1300
- from_coordinate,
1301
- to_coordinate: coordinate,
1302
- });
1303
- logger.debug('scroll_to Got response:', response);
1304
- return response;
1305
- }
1306
- async function scroll_to_by(chromeProxy, tabId, xpath, highlightIndex) {
1307
- logger.debug('Sending scroll_to_by message to tab:', tabId, { xpath, highlightIndex });
1308
- const response = await chromeProxy.tabs.sendMessage(tabId, {
1309
- type: 'computer:scroll_to',
1310
- xpath,
1311
- highlightIndex,
1312
- });
1313
- logger.debug('scroll_to_by Got response:', response);
1314
- return response;
1315
- }
1316
- async function get_dropdown_options(chromeProxy, tabId, xpath, highlightIndex) {
1317
- logger.debug('Sending get_dropdown_options message to tab:', tabId, { xpath, highlightIndex });
1318
- try {
1319
- const response = await chromeProxy.tabs.sendMessage(tabId, {
1320
- type: 'computer:get_dropdown_options',
1321
- xpath,
1322
- highlightIndex,
1323
- });
1324
- logger.debug('get_dropdown_options Got response:', response);
1325
- return response;
1326
- }
1327
- catch (e) {
1328
- logger.error('Failed to send get_dropdown_options message:', e);
1329
- throw e;
1330
- }
1331
- }
1332
- async function select_dropdown_option(chromeProxy, tabId, text, xpath, highlightIndex) {
1333
- logger.debug('Sending select_dropdown_option message to tab:', tabId, { text, xpath, highlightIndex });
1334
- try {
1335
- const response = await chromeProxy.tabs.sendMessage(tabId, {
1336
- type: 'computer:select_dropdown_option',
1337
- text,
1338
- xpath,
1339
- highlightIndex,
1340
- });
1341
- logger.debug('select_dropdown_option Got response:', response);
1342
- return response;
1343
- }
1344
- catch (e) {
1345
- logger.error('Failed to send select_dropdown_option message:', e);
1346
- throw e;
1347
- }
1348
- }
1349
- async function cursor_position(chromeProxy, tabId) {
1350
- logger.debug('Sending cursor_position message to tab:', tabId);
1351
- try {
1352
- let result = await chromeProxy.tabs.sendMessage(tabId, {
1353
- type: 'computer:cursor_position',
1354
- });
1355
- logger.debug('Got cursor position:', result.coordinate);
1356
- return { coordinate: result.coordinate };
1357
- }
1358
- catch (e) {
1359
- logger.error('Failed to send cursor_position message:', e);
1360
- throw e;
1361
- }
1362
- }
1363
- async function size(chromeProxy, tabId) {
1364
- logger.debug('Getting page size for tab:', tabId);
1365
- try {
1366
- const pageSize = await getPageSize(chromeProxy, tabId);
1367
- logger.debug('Got page size:', pageSize);
1368
- return pageSize;
1369
- }
1370
- catch (e) {
1371
- logger.error('Failed to get page size:', e);
1372
- throw e;
1373
- }
1374
- }
1375
- function build_fellou_handle_js(xpath, highlightIndex) {
1376
- if (highlightIndex != undefined) {
1377
- return `get_highlight_element(${highlightIndex})`;
1378
- }
1379
- else {
1380
- return `document.evaluate('${xpath}', document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue`;
1381
- }
1382
- }
1383
-
1384
- var browser = /*#__PURE__*/Object.freeze({
1385
- __proto__: null,
1386
- clear_input: clear_input,
1387
- clear_input_by: clear_input_by,
1388
- compress_image: compress_image,
1389
- cursor_position: cursor_position,
1390
- double_click: double_click,
1391
- double_click_by: double_click_by,
1392
- enter_by: enter_by,
1393
- get_dropdown_options: get_dropdown_options,
1394
- left_click: left_click,
1395
- left_click_by: left_click_by,
1396
- mouse_move: mouse_move,
1397
- right_click: right_click,
1398
- right_click_by: right_click_by,
1399
- screenshot: screenshot,
1400
- scroll_to: scroll_to,
1401
- scroll_to_by: scroll_to_by,
1402
- select_dropdown_option: select_dropdown_option,
1403
- size: size,
1404
- type: type,
1405
- type_by: type_by
1406
- });
1407
-
1408
- class ToolReturnsScreenshot {
1409
- async execute(context, params) {
1410
- const realResult = await this.realExecute(context, params);
1411
- logger.debug("debug realResult...");
1412
- logger.debug(realResult);
1413
- await sleep(3000); // wait for page loding
1414
- let instance = new BrowserAction();
1415
- const image = await instance.realExecute(context, { action: "screenshot_extract_element" });
1416
- return image;
1417
- }
1418
- }
1419
-
1420
- /**
1421
- * Browser Use for general
1422
- */
1423
- class BrowserAction extends ToolReturnsScreenshot {
1424
- constructor() {
1425
- super();
1426
- this.name = 'browser_action';
1427
- this.description = `Use structured commands to interact with the browser, manipulating page elements through screenshots and webpage element extraction.
1428
- * This is a browser GUI interface where you need to analyze webpages by taking screenshots and extracting page element structures, and specify action sequences to complete designated tasks.
1429
- * Before any operation, you must first call the \`screenshot_extract_element\` command, which will return the browser page screenshot and structured element information, both specially processed.
1430
- * ELEMENT INTERACTION:
1431
- - Only use indexes that exist in the provided element list
1432
- - Each element has a unique index number (e.g., "[33]:<button>")
1433
- - Elements marked with "[]:" are non-interactive (for context only)
1434
- * NAVIGATION & ERROR HANDLING:
1435
- - If no suitable elements exist, use other functions to complete the task
1436
- - If stuck, try alternative approaches
1437
- - Handle popups/cookies by accepting or closing them
1438
- - Use scroll to find elements you are looking for`;
1439
- this.input_schema = {
1440
- type: 'object',
1441
- properties: {
1442
- action: {
1443
- type: 'string',
1444
- description: `The action to perform. The available actions are:
1445
- * \`screenshot_extract_element\`: Take a screenshot of the web page and extract operable elements.
1446
- - Screenshots are used to understand page layouts, with labeled bounding boxes corresponding to element indexes. Each bounding box and its label share the same color, with labels typically positioned in the top-right corner of the box.
1447
- - Screenshots help verify element positions and relationships. Labels may sometimes overlap, so extracted elements are used to verify the correct elements.
1448
- - In addition to screenshots, simplified information about interactive elements is returned, with element indexes corresponding to those in the screenshots.
1449
- - This tool can ONLY screenshot the VISIBLE content. If a complete content is required, use 'extract_content' instead.
1450
- * \`input_text\`: Enter a string in the interactive element, If you need to press the Enter key, please end with '\\n'. For search tasks, you MUST end with '\\n' to simulate pressing the Enter key.
1451
- * \`click\`: Click to element.
1452
- * \`right_click\`: Right-click on the element.
1453
- * \`double_click\`: Double-click on the element.
1454
- * \`scroll_to\`: Scroll to the specified element.
1455
- * \`extract_content\`: Extract the text content of the current webpage.
1456
- * \`get_dropdown_options\`: Get all options from a native dropdown element.
1457
- * \`select_dropdown_option\`: Select dropdown option for interactive element index by the text of the option you want to select.`,
1458
- enum: [
1459
- 'screenshot_extract_element',
1460
- 'input_text',
1461
- 'click',
1462
- 'right_click',
1463
- 'double_click',
1464
- 'scroll_to',
1465
- 'extract_content',
1466
- 'get_dropdown_options',
1467
- 'select_dropdown_option',
1468
- ],
1469
- },
1470
- index: {
1471
- type: 'integer',
1472
- description: 'index of element, Operation elements must pass the corresponding index of the element',
1473
- },
1474
- text: {
1475
- type: 'string',
1476
- description: 'Required by `action=input_text` and `action=select_dropdown_option`',
1477
- },
1478
- },
1479
- required: ['action'],
1480
- };
1481
- }
1482
- /**
1483
- * browser
1484
- *
1485
- * @param {*} params { action: 'input_text', index: 1, text: 'string' }
1486
- * @returns > { success: true, image?: { type: 'base64', media_type: 'image/jpeg', data: '/9j...' }, text?: string }
1487
- */
1488
- async realExecute(context, params) {
1489
- var _a;
1490
- logger.debug("debug 'browser_action'...");
1491
- logger.debug(params);
1492
- try {
1493
- if (params === null || !params.action) {
1494
- throw new Error('Invalid parameters. Expected an object with a "action" property.');
1495
- }
1496
- let tabId;
1497
- try {
1498
- tabId = await getTabId(context);
1499
- logger.debug(tabId);
1500
- if (!tabId || !Number.isInteger(tabId)) {
1501
- throw new Error('Could not get valid tab ID');
1502
- }
1503
- }
1504
- catch (e) {
1505
- logger.error('Tab ID error:', e);
1506
- return { success: false, error: 'Could not access browser tab' };
1507
- }
1508
- let windowId = await getWindowId(context);
1509
- let selector_map = context.selector_map;
1510
- let selector_xpath;
1511
- if (params.index != null && selector_map) {
1512
- selector_xpath = (_a = selector_map[params.index]) === null || _a === void 0 ? void 0 : _a.xpath;
1513
- if (!selector_xpath) {
1514
- throw new Error('Element does not exist');
1515
- }
1516
- }
1517
- let result;
1518
- logger.debug("switch cases...");
1519
- switch (params.action) {
1520
- case 'input_text':
1521
- if (params.index == null) {
1522
- throw new Error('index parameter is required');
1523
- }
1524
- if (params.text == null) {
1525
- throw new Error('text parameter is required');
1526
- }
1527
- await clear_input_by(context.ekoConfig.chromeProxy, tabId, selector_xpath, params.index);
1528
- result = await type_by(context.ekoConfig.chromeProxy, tabId, params.text, selector_xpath, params.index);
1529
- await sleep(200);
1530
- break;
1531
- case 'click':
1532
- if (params.index == null) {
1533
- throw new Error('index parameter is required');
1534
- }
1535
- result = await left_click_by(context.ekoConfig.chromeProxy, tabId, selector_xpath, params.index);
1536
- await sleep(100);
1537
- break;
1538
- case 'right_click':
1539
- if (params.index == null) {
1540
- throw new Error('index parameter is required');
1541
- }
1542
- result = await right_click_by(context.ekoConfig.chromeProxy, tabId, selector_xpath, params.index);
1543
- await sleep(100);
1544
- break;
1545
- case 'double_click':
1546
- if (params.index == null) {
1547
- throw new Error('index parameter is required');
1548
- }
1549
- result = await double_click_by(context.ekoConfig.chromeProxy, tabId, selector_xpath, params.index);
1550
- await sleep(100);
1551
- break;
1552
- case 'scroll_to':
1553
- if (params.index == null) {
1554
- throw new Error('index parameter is required');
1555
- }
1556
- result = await scroll_to_by(context.ekoConfig.chromeProxy, tabId, selector_xpath, params.index);
1557
- await sleep(500);
1558
- break;
1559
- case 'extract_content':
1560
- let tab = await context.ekoConfig.chromeProxy.tabs.get(tabId);
1561
- await injectScript(context.ekoConfig.chromeProxy, tabId);
1562
- await sleep(200);
1563
- let content = await executeScript(context.ekoConfig.chromeProxy, tabId, () => {
1564
- return eko.extractHtmlContent();
1565
- }, []);
1566
- result = {
1567
- title: tab.title,
1568
- url: tab.url,
1569
- content: content,
1570
- };
1571
- break;
1572
- case 'get_dropdown_options':
1573
- if (params.index == null) {
1574
- throw new Error('index parameter is required');
1575
- }
1576
- result = await get_dropdown_options(context.ekoConfig.chromeProxy, tabId, selector_xpath, params.index);
1577
- break;
1578
- case 'select_dropdown_option':
1579
- if (params.index == null) {
1580
- throw new Error('index parameter is required');
1581
- }
1582
- if (params.text == null) {
1583
- throw new Error('text parameter is required');
1584
- }
1585
- result = await select_dropdown_option(context.ekoConfig.chromeProxy, tabId, params.text, selector_xpath, params.index);
1586
- break;
1587
- case 'screenshot_extract_element':
1588
- logger.debug("execute 'screenshot_extract_element'...");
1589
- await sleep(100);
1590
- logger.debug("injectScript...");
1591
- await injectScript(context.ekoConfig.chromeProxy, tabId, 'build_dom_tree.js');
1592
- await sleep(100);
1593
- try {
1594
- logger.debug("executeScript...");
1595
- let element_result = await executeScript(context.ekoConfig.chromeProxy, tabId, () => {
1596
- return window.get_clickable_elements(true);
1597
- }, []);
1598
- context.selector_map = element_result.selector_map;
1599
- logger.debug("browser.screenshot...");
1600
- let screenshot$1 = await screenshot(context.ekoConfig.chromeProxy, windowId, true);
1601
- result = { image: screenshot$1.image, text: element_result.element_str };
1602
- }
1603
- finally {
1604
- await sleep(500);
1605
- logger.debug("executeScript #2...");
1606
- await executeScript(context.ekoConfig.chromeProxy, tabId, () => {
1607
- return window.remove_highlight();
1608
- }, []);
1609
- }
1610
- logger.debug("execute 'screenshot_extract_element'...done");
1611
- break;
1612
- default:
1613
- throw Error(`Invalid parameters. The "${params.action}" value is not included in the "action" enumeration.`);
1614
- }
1615
- logger.debug(`execute 'browser_action'...done, result=${result}`);
1616
- return result;
1617
- }
1618
- catch (e) {
1619
- logger.error('Browser use error:', e);
1620
- return { success: false, error: e === null || e === void 0 ? void 0 : e.message };
1621
- }
1622
- }
1623
- destroy(context) {
1624
- delete context.selector_map;
1625
- }
1626
- }
1627
-
1628
- function exportFile(filename, type, content) {
1629
- const blob = new Blob([content], { type: type });
1630
- const link = document.createElement('a');
1631
- link.href = URL.createObjectURL(blob);
1632
- link.download = filename;
1633
- document.body.appendChild(link);
1634
- link.click();
1635
- document.body.removeChild(link);
1636
- URL.revokeObjectURL(link.href);
1637
- }
1638
-
1639
- /**
1640
- * Export file
1641
- */
1642
- class ExportFile {
1643
- constructor() {
1644
- this.name = 'export_file';
1645
- this.description = 'Export a text file with content. You should call this tool ONLY when user requires to export a file.';
1646
- this.input_schema = {
1647
- type: 'object',
1648
- properties: {
1649
- fileType: {
1650
- type: 'string',
1651
- description: 'File format type',
1652
- enum: ['txt', 'csv', 'md', 'html', 'js', 'xml', 'json', 'yml', 'sql'],
1653
- },
1654
- content: {
1655
- type: 'string',
1656
- description: 'Export file content',
1657
- },
1658
- filename: {
1659
- type: 'string',
1660
- description: 'File name',
1661
- },
1662
- },
1663
- required: ['fileType', 'content'],
1664
- };
1665
- }
1666
- /**
1667
- * export
1668
- *
1669
- * @param {*} params { fileType: 'csv', content: 'field1,field2\ndata1,data2' }
1670
- * @returns > { success: true }
1671
- */
1672
- async execute(context, params) {
1673
- var _a, _b, _c, _d, _e, _f;
1674
- if (typeof params !== 'object' || params === null || !('content' in params)) {
1675
- throw new Error('Invalid parameters. Expected an object with a "content" property.');
1676
- }
1677
- await ((_c = (_b = (_a = context.callback) === null || _a === void 0 ? void 0 : _a.hooks) === null || _b === void 0 ? void 0 : _b.onExportFile) === null || _c === void 0 ? void 0 : _c.call(_b, params));
1678
- let type = 'text/plain';
1679
- switch (params.fileType) {
1680
- case 'csv':
1681
- type = 'text/csv';
1682
- break;
1683
- case 'md':
1684
- type = 'text/markdown';
1685
- break;
1686
- case 'html':
1687
- type = 'text/html';
1688
- break;
1689
- case 'js':
1690
- type = 'application/javascript';
1691
- break;
1692
- case 'xml':
1693
- type = 'text/xml';
1694
- break;
1695
- case 'json':
1696
- type = 'application/json';
1697
- break;
1698
- }
1699
- let filename;
1700
- if (!params.filename) {
1701
- filename = new Date().getTime() + '.' + params.fileType;
1702
- }
1703
- else if (!(params.filename + '').endsWith(params.fileType)) {
1704
- filename = params.filename + '.' + params.fileType;
1705
- }
1706
- else {
1707
- filename = params.filename;
1708
- }
1709
- try {
1710
- let tabId = await getTabId(context);
1711
- await context.ekoConfig.chromeProxy.scripting.executeScript({
1712
- target: { tabId: tabId },
1713
- func: exportFile,
1714
- args: [filename, type, params.content],
1715
- });
1716
- }
1717
- catch (e) {
1718
- let tab;
1719
- const url = 'https://www.google.com';
1720
- if (context.ekoConfig.workingWindowId) {
1721
- tab = await open_new_tab(context.ekoConfig.chromeProxy, url, context.ekoConfig.workingWindowId);
1722
- }
1723
- else {
1724
- tab = await open_new_tab(context.ekoConfig.chromeProxy, url);
1725
- }
1726
- (_f = (_e = (_d = context.callback) === null || _d === void 0 ? void 0 : _d.hooks) === null || _e === void 0 ? void 0 : _e.onTabCreated) === null || _f === void 0 ? void 0 : _f.call(_e, tab.id);
1727
- let tabId = tab.id;
1728
- await context.ekoConfig.chromeProxy.scripting.executeScript({
1729
- target: { tabId: tabId },
1730
- func: exportFile,
1731
- args: [filename, type, params.content],
1732
- });
1733
- await sleep(5000);
1734
- await context.ekoConfig.chromeProxy.tabs.remove(tabId);
1735
- }
1736
- return { success: true };
1737
- }
1738
- }
1739
-
1740
- /**
1741
- * Extract Page Content
1742
- */
1743
- class ExtractContent {
1744
- constructor() {
1745
- this.name = 'extract_content';
1746
- this.description = 'Extract the complete text content of the current webpage';
1747
- this.input_schema = {
1748
- type: 'object',
1749
- properties: {},
1750
- };
1751
- }
1752
- /**
1753
- * Extract Page Content
1754
- *
1755
- * @param {*} params {}
1756
- * @returns > { tabId, result: { title, url, content }, success: true }
1757
- */
1758
- async execute(context, params) {
1759
- let tabId = await getTabId(context);
1760
- let tab = await context.ekoConfig.chromeProxy.tabs.get(tabId);
1761
- await injectScript(context.ekoConfig.chromeProxy, tabId);
1762
- await sleep(500);
1763
- let content = await executeScript(context.ekoConfig.chromeProxy, tabId, () => {
1764
- return eko.extractHtmlContent();
1765
- }, []);
1766
- return {
1767
- tabId,
1768
- result: {
1769
- title: tab.title,
1770
- url: tab.url,
1771
- content: content,
1772
- }
1773
- };
1774
- }
1775
- }
1776
-
1777
- class GetAllTabs {
1778
- constructor() {
1779
- this.name = 'get_all_tabs';
1780
- this.description = 'Get the tabId, title, url and content from current all tabs without opening new tab.';
1781
- this.input_schema = {
1782
- type: 'object',
1783
- properties: {},
1784
- };
1785
- }
1786
- async execute(context, params) {
1787
- const currentWindow = await context.ekoConfig.chromeProxy.windows.getCurrent();
1788
- const windowId = currentWindow.id;
1789
- const tabs = await context.ekoConfig.chromeProxy.tabs.query({ windowId });
1790
- const tabsInfo = [];
1791
- for (const tab of tabs) {
1792
- if (tab.id === undefined) {
1793
- logger.warn(`Tab ID is undefined for tab with URL: ${tab.url}`);
1794
- continue;
1795
- }
1796
- await injectScript(context.ekoConfig.chromeProxy, tab.id);
1797
- await sleep(500);
1798
- let content = await executeScript(context.ekoConfig.chromeProxy, tab.id, () => {
1799
- return eko.extractHtmlContent();
1800
- }, []);
1801
- // Use title as description, but requirement may evolve
1802
- let description = tab.title ? tab.title : "No description available.";
1803
- const tabInfo = {
1804
- id: tab.id,
1805
- url: tab.url,
1806
- title: tab.title,
1807
- content: content,
1808
- description: description,
1809
- };
1810
- logger.debug(tabInfo);
1811
- tabsInfo.push(tabInfo);
1812
- }
1813
- return tabsInfo;
1814
- }
1815
- }
1816
-
1817
- /**
1818
- * Open Url
1819
- */
1820
- class OpenUrl extends ToolReturnsScreenshot {
1821
- constructor() {
1822
- super();
1823
- this.name = 'open_url';
1824
- this.description = 'Open the specified URL link in browser window';
1825
- this.input_schema = {
1826
- type: 'object',
1827
- properties: {
1828
- url: {
1829
- type: 'string',
1830
- description: 'URL link address',
1831
- },
1832
- newWindow: {
1833
- type: 'boolean',
1834
- description: 'true: Open in a new window; false: Open in the current window.',
1835
- },
1836
- },
1837
- required: ['url'],
1838
- };
1839
- }
1840
- /**
1841
- * Open Url
1842
- *
1843
- * @param {*} params { url: 'https://www.google.com', newWindow: true }
1844
- * @returns > { tabId, windowId, title, success: true }
1845
- */
1846
- async realExecute(context, params) {
1847
- var _a, _b, _c, _d, _e, _f;
1848
- // 参数验证
1849
- if (typeof params !== 'object' || params === null || !params.url) {
1850
- logger.error('Invalid parameters. Expected an object with a "url" property.');
1851
- throw new Error('Invalid parameters. Expected an object with a "url" property.');
1852
- }
1853
- // 提取参数
1854
- let url = params.url.trim();
1855
- let newWindow = params.newWindow;
1856
- logger.debug('URL to open:', url);
1857
- logger.debug('Initial newWindow value:', newWindow);
1858
- // 根据上下文调整 newWindow 的值
1859
- if (context.ekoConfig.workingWindowId) {
1860
- logger.debug('Working window ID exists in context, setting newWindow to false.');
1861
- newWindow = false;
1862
- }
1863
- else if (!newWindow && !context.variables.get('windowId') && !context.variables.get('tabId')) {
1864
- // First mandatory opening of a new window
1865
- logger.debug('No existing window or tab ID found, forcing newWindow to true.');
1866
- newWindow = true;
1867
- }
1868
- logger.debug('Final newWindow value:', newWindow);
1869
- // 打开新标签页
1870
- let tab;
1871
- if (newWindow) {
1872
- logger.debug('Opening new tab in a new window.');
1873
- tab = await open_new_tab(context.ekoConfig.chromeProxy, url);
1874
- (_c = (_b = (_a = context.callback) === null || _a === void 0 ? void 0 : _a.hooks) === null || _b === void 0 ? void 0 : _b.onTabCreated) === null || _c === void 0 ? void 0 : _c.call(_b, tab.id);
1875
- logger.debug('New tab created in a new window:', tab.id);
1876
- }
1877
- else {
1878
- let windowId = context.ekoConfig.workingWindowId ? context.ekoConfig.workingWindowId : await getWindowId(context);
1879
- logger.debug('Using existing window with ID:', windowId);
1880
- try {
1881
- tab = await open_new_tab(context.ekoConfig.chromeProxy, url, windowId);
1882
- logger.debug("Calling hook...");
1883
- (_f = (_e = (_d = context.callback) === null || _d === void 0 ? void 0 : _d.hooks) === null || _e === void 0 ? void 0 : _e.onTabCreated) === null || _f === void 0 ? void 0 : _f.call(_e, tab.id);
1884
- logger.debug('New tab created in existing window:', tab.id);
1885
- }
1886
- catch (e) {
1887
- logger.error("An error occurs when `open_url`", e);
1888
- throw e;
1889
- }
1890
- }
1891
- // 获取窗口和标签 ID
1892
- let windowId = tab.windowId;
1893
- let tabId = tab.id;
1894
- logger.debug('Tab ID:', tabId, 'Window ID:', windowId);
1895
- // 更新上下文变量
1896
- context.variables.set('windowId', windowId);
1897
- context.variables.set('tabId', tabId);
1898
- logger.debug('Updated context variables:', context.variables);
1899
- // 处理新窗口的 windowIds
1900
- if (newWindow) {
1901
- let windowIds = context.variables.get('windowIds');
1902
- if (windowIds) {
1903
- logger.debug('Existing window IDs:', windowIds);
1904
- windowIds.push(windowId);
1905
- logger.debug('Updated window IDs:', windowIds);
1906
- }
1907
- else {
1908
- logger.debug('No existing window IDs found, creating new array.');
1909
- context.variables.set('windowIds', [windowId]);
1910
- }
1911
- }
1912
- // 返回结果
1913
- let result = {
1914
- tabId,
1915
- windowId,
1916
- title: tab.title,
1917
- };
1918
- logger.debug('Returning result:', result);
1919
- return result;
1920
- }
1921
- }
1922
-
1923
- /**
1924
- * Current Page Screenshot
1925
- */
1926
- class Screenshot {
1927
- constructor() {
1928
- this.name = 'screenshot';
1929
- this.description = 'Screenshot the current webpage window';
1930
- this.input_schema = {
1931
- type: 'object',
1932
- properties: {},
1933
- };
1934
- }
1935
- /**
1936
- * Current Page Screenshot
1937
- *
1938
- * @param {*} params {}
1939
- * @returns > { image: { type: 'base64', media_type: 'image/png', data } }
1940
- */
1941
- async execute(context, params) {
1942
- let windowId = await getWindowId(context);
1943
- return await screenshot(context.ekoConfig.chromeProxy, windowId);
1944
- }
1945
- }
1946
-
1947
- /**
1948
- * Browser tab management
1949
- */
1950
- class TabManagement {
1951
- constructor() {
1952
- this.name = 'tab_management';
1953
- this.description = 'Browser tab management, view and operate tabs.You can use this tool to' +
1954
- 'View all tabs with the tabId and title.Get current tab information (tabId, url, title).' +
1955
- 'Go back to the previous page in the current tab. And Close the current tab.';
1956
- this.input_schema = {
1957
- type: 'object',
1958
- properties: {
1959
- command: {
1960
- type: 'string',
1961
- description: `The command to perform. The available commands are:
1962
- * \`tab_all\`: View all tabs and return the tabId and title.
1963
- * \`go_back\`: Go back to the previous page in the current tab.
1964
- * \`switch_tab\`: Switch to the specified tab by tabId.`,
1965
- enum: ['tab_all', 'go_back', 'switch_tab'],
1966
- },
1967
- tabId: {
1968
- type: 'integer',
1969
- description: "Tab id. Only needed when using 'switch_tab'",
1970
- },
1971
- },
1972
- required: ['command'],
1973
- };
1974
- }
1975
- async execute(context, params) {
1976
- if (params === null || !params.command) {
1977
- throw new Error('Invalid parameters. Expected an object with a "command" property.');
1978
- }
1979
- if (params.command == 'tab_all') ;
1980
- else if (params.command == 'go_back') {
1981
- let tabId = await getTabId(context);
1982
- await context.ekoConfig.chromeProxy.tabs.goBack(tabId);
1983
- }
1984
- else if (params.command == "switch_tab") {
1985
- await context.ekoConfig.chromeProxy.tabs.select(params.tabId);
1986
- }
1987
- else if (params.command == 'close_tab') {
1988
- let closedTabId = await getTabId(context);
1989
- await context.ekoConfig.chromeProxy.tabs.remove(closedTabId);
1990
- await sleep(100);
1991
- let tabs = await context.ekoConfig.chromeProxy.tabs.query({ active: true, currentWindow: true });
1992
- if (tabs.length == 0) {
1993
- tabs = await context.ekoConfig.chromeProxy.tabs.query({ status: 'complete', currentWindow: true });
1994
- }
1995
- let tab = tabs[tabs.length - 1];
1996
- if (!tab.active) {
1997
- await context.ekoConfig.chromeProxy.tabs.update(tab.id, { active: true });
1998
- }
1999
- context.variables.set('tabId', tab.id);
2000
- context.variables.set('windowId', tab.windowId);
2001
- }
2002
- else {
2003
- throw Error('Unknown command: ' + params.command);
2004
- }
2005
- // build return value
2006
- let tabs = await context.ekoConfig.chromeProxy.tabs.query({});
2007
- tabs = tabs.filter((tab) => tab.title && tab.url);
2008
- if (tabs.length > 0) {
2009
- let result = "After operation, the existing tabs are as follows:\n";
2010
- for (const tab of tabs) {
2011
- result += `<tab><id>${tab.id}</id><title>${tab.title}</title><url>${tab.url}</url></tab>\n`;
2012
- }
2013
- let currentTabId = await getTabId(context);
2014
- let currentTab = await context.ekoConfig.chromeProxy.tabs.get(currentTabId);
2015
- result += `The current active tab: <tab><id>${currentTab.id}</id><title>${currentTab.title}</title><url>${currentTab.url}</url></tab>`;
2016
- return result;
2017
- }
2018
- else {
2019
- return "No existing tab. Use 'open_url' to open a new tab";
2020
- }
2021
- }
2022
- destroy(context) {
2023
- let windowIds = context.variables.get('windowIds');
2024
- if (windowIds) {
2025
- for (let i = 0; i < windowIds.length; i++) {
2026
- context.ekoConfig.chromeProxy.windows.remove(windowIds[i]);
2027
- }
2028
- }
2029
- }
2030
- }
2031
-
2032
- /**
2033
- * Web Search
2034
- */
2035
- class WebSearch {
2036
- constructor() {
2037
- this.name = 'web_search';
2038
- this.description = 'Search the web based on keywords and return relevant extracted content from webpages.';
2039
- this.input_schema = {
2040
- type: 'object',
2041
- properties: {
2042
- url: {
2043
- type: 'string',
2044
- description: 'the URL of search engine, like https://www.bing.com'
2045
- },
2046
- query: {
2047
- type: 'string',
2048
- description: 'search for keywords',
2049
- },
2050
- maxResults: {
2051
- type: 'integer',
2052
- description: 'Maximum search results, default 5',
2053
- },
2054
- },
2055
- required: ['query'],
2056
- };
2057
- }
2058
- /**
2059
- * search
2060
- *
2061
- * @param {*} params { url: 'https://www.google.com', query: 'ai agent', maxResults: 5 }
2062
- * @returns > [{ title, url, content }]
2063
- */
2064
- async execute(context, params) {
2065
- var _a, _b;
2066
- if (typeof params !== 'object' || params === null || !params.query) {
2067
- throw new Error('Invalid parameters. Expected an object with a "query" property.');
2068
- }
2069
- let url = (_a = params.url) === null || _a === void 0 ? void 0 : _a.trim();
2070
- let query = params.query;
2071
- let maxResults = params.maxResults;
2072
- if (!url) {
2073
- url = 'https://www.bing.com';
2074
- }
2075
- let taskId = new Date().getTime() + '';
2076
- let searchs = [{ url: url, keyword: query }];
2077
- let searchInfo = await deepSearch(context, taskId, searchs, maxResults || 5, context.ekoConfig.workingWindowId);
2078
- let links = ((_b = searchInfo.result[0]) === null || _b === void 0 ? void 0 : _b.links) || [];
2079
- return links.filter((s) => s.content.slice(0, 8000));
2080
- }
2081
- }
2082
- const deepSearchInjects = {
2083
- 'bing.com': {
2084
- filename: 'bing.js',
2085
- buildSearchUrl: function (url, keyword) {
2086
- return 'https://bing.com/search?q=' + encodeURI(keyword);
2087
- },
2088
- },
2089
- 'duckduckgo.com': {
2090
- filename: 'duckduckgo.js',
2091
- buildSearchUrl: function (url, keyword) {
2092
- return 'https://duckduckgo.com/?q=' + encodeURI(keyword);
2093
- },
2094
- },
2095
- 'google.com': {
2096
- filename: 'google.js',
2097
- buildSearchUrl: function (url, keyword) {
2098
- return 'https://www.google.com/search?q=' + encodeURI(keyword);
2099
- },
2100
- },
2101
- default: {
2102
- filename: 'google.js',
2103
- buildSearchUrl: function (url, keyword) {
2104
- url = url.trim();
2105
- let idx = url.indexOf('//');
2106
- if (idx > -1) {
2107
- url = url.substring(idx + 2);
2108
- }
2109
- idx = url.indexOf('/', 2);
2110
- if (idx > -1) {
2111
- url = url.substring(0, idx);
2112
- }
2113
- keyword = 'site:' + url + ' ' + keyword;
2114
- return 'https://www.google.com/search?q=' + encodeURIComponent(keyword);
2115
- },
2116
- },
2117
- };
2118
- function buildDeepSearchUrl(url, keyword) {
2119
- let idx = url.indexOf('/', url.indexOf('//') + 2);
2120
- let baseUrl = idx > -1 ? url.substring(0, idx) : url;
2121
- let domains = Object.keys(deepSearchInjects);
2122
- let inject = null;
2123
- for (let j = 0; j < domains.length; j++) {
2124
- let domain = domains[j];
2125
- if (baseUrl == domain || baseUrl.endsWith('.' + domain) || baseUrl.endsWith('/' + domain)) {
2126
- inject = deepSearchInjects[domain];
2127
- break;
2128
- }
2129
- }
2130
- if (!inject) {
2131
- inject = deepSearchInjects['default'];
2132
- }
2133
- return {
2134
- filename: inject.filename,
2135
- url: inject.buildSearchUrl(url, keyword),
2136
- };
2137
- }
2138
- // Event
2139
- const tabsUpdateEvent = new MsgEvent();
2140
- // TODO: replace `chrome` with `context.ekoConfig.chromeProxy`
2141
- if (typeof chrome !== 'undefined' && typeof chrome.tabs !== 'undefined') {
2142
- chrome.tabs.onUpdated.addListener(async function (tabId, changeInfo, tab) {
2143
- await tabsUpdateEvent.publish({ tabId, changeInfo, tab });
2144
- });
2145
- }
2146
- /**
2147
- * deep search
2148
- *
2149
- * @param {string} taskId task id
2150
- * @param {array} searchs search list => [{ url: 'https://bing.com', keyword: 'ai' }]
2151
- * @param {number} detailsMaxNum Maximum crawling quantity per search detail page
2152
- */
2153
- async function deepSearch(context, taskId, searchs, detailsMaxNum, windowId) {
2154
- let closeWindow = false;
2155
- if (!windowId) {
2156
- // open new window
2157
- let window = await context.ekoConfig.chromeProxy.windows.create({
2158
- type: 'normal',
2159
- state: 'maximized',
2160
- url: null,
2161
- });
2162
- windowId = window.id;
2163
- closeWindow = true;
2164
- }
2165
- windowId = windowId;
2166
- // crawler the search page details page link
2167
- // [{ links: [{ title, url }] }]
2168
- let detailLinkGroups = await doDetailLinkGroups(context, taskId, searchs, detailsMaxNum, windowId);
2169
- // crawler all details page content and comments
2170
- let searchInfo = await doPageContent(context, taskId, detailLinkGroups, windowId);
2171
- logger.debug('searchInfo: ', searchInfo);
2172
- // close window
2173
- closeWindow && context.ekoConfig.chromeProxy.windows.remove(windowId);
2174
- return searchInfo;
2175
- }
2176
- /**
2177
- * crawler the search page details page link
2178
- *
2179
- * @param {string} taskId task id
2180
- * @param {array} searchs search list => [{ url: 'https://bing.com', keyword: 'ai' }]
2181
- * @param {number} detailsMaxNum Maximum crawling quantity per search detail page
2182
- * @param {*} window
2183
- * @returns [{ links: [{ title, url }] }]
2184
- */
2185
- async function doDetailLinkGroups(context, taskId, searchs, detailsMaxNum, windowId) {
2186
- var _a, _b, _c;
2187
- let detailLinkGroups = [];
2188
- let countDownLatch = new CountDownLatch(searchs.length);
2189
- for (let i = 0; i < searchs.length; i++) {
2190
- try {
2191
- // script name & build search URL
2192
- const { filename, url } = buildDeepSearchUrl(searchs[i].url, searchs[i].keyword);
2193
- // open new Tab
2194
- let tab = await context.ekoConfig.chromeProxy.tabs.create({
2195
- url: url,
2196
- windowId,
2197
- });
2198
- (_c = (_b = (_a = context.callback) === null || _a === void 0 ? void 0 : _a.hooks) === null || _b === void 0 ? void 0 : _b.onTabCreated) === null || _c === void 0 ? void 0 : _c.call(_b, tab.id);
2199
- let eventId = taskId + '_' + i;
2200
- // monitor Tab status
2201
- tabsUpdateEvent.addListener(async function (obj) {
2202
- if (obj.tabId != tab.id) {
2203
- return;
2204
- }
2205
- if (obj.changeInfo.status === 'complete') {
2206
- tabsUpdateEvent.removeListener(eventId);
2207
- // inject js
2208
- await injectScript(context.ekoConfig.chromeProxy, tab.id, filename);
2209
- await sleep(1000);
2210
- // crawler the search page details page
2211
- // { links: [{ title, url }] }
2212
- let detailLinks = await context.ekoConfig.chromeProxy.tabs.sendMessage(tab.id, {
2213
- type: 'page:getDetailLinks',
2214
- keyword: searchs[i].keyword,
2215
- });
2216
- logger.debug('detailLinks: ', detailLinks);
2217
- if (!detailLinks || !detailLinks.links) {
2218
- logger.error("detailLinks is empty");
2219
- throw new Error("An error occurs when calling `web_search`, please try again.");
2220
- }
2221
- let links = detailLinks.links.slice(0, detailsMaxNum);
2222
- detailLinkGroups.push({ url, links, filename });
2223
- countDownLatch.countDown();
2224
- context.ekoConfig.chromeProxy.tabs.remove(tab.id);
2225
- }
2226
- else if (obj.changeInfo.status === 'unloaded') {
2227
- countDownLatch.countDown();
2228
- context.ekoConfig.chromeProxy.tabs.remove(tab.id);
2229
- tabsUpdateEvent.removeListener(eventId);
2230
- }
2231
- }, eventId);
2232
- }
2233
- catch (e) {
2234
- logger.error(e);
2235
- countDownLatch.countDown();
2236
- }
2237
- }
2238
- await countDownLatch.await(30000);
2239
- return detailLinkGroups;
2240
- }
2241
- /**
2242
- * page content
2243
- *
2244
- * @param {string} taskId task id
2245
- * @param {array} detailLinkGroups details page group
2246
- * @param {*} window
2247
- * @returns search info
2248
- */
2249
- async function doPageContent(context, taskId, detailLinkGroups, windowId) {
2250
- var _a, _b, _c;
2251
- const searchInfo = {
2252
- total: 0,
2253
- running: 0,
2254
- succeed: 0,
2255
- failed: 0,
2256
- failedLinks: [],
2257
- result: detailLinkGroups,
2258
- };
2259
- for (let i = 0; i < detailLinkGroups.length; i++) {
2260
- let links = detailLinkGroups[i].links;
2261
- searchInfo.total += links.length;
2262
- }
2263
- let countDownLatch = new CountDownLatch(searchInfo.total);
2264
- for (let i = 0; i < detailLinkGroups.length; i++) {
2265
- let filename = detailLinkGroups[i].filename;
2266
- let links = detailLinkGroups[i].links;
2267
- for (let j = 0; j < links.length; j++) {
2268
- let link = links[j];
2269
- // open new tab
2270
- let tab = await context.ekoConfig.chromeProxy.tabs.create({
2271
- url: link.url,
2272
- windowId,
2273
- });
2274
- (_c = (_b = (_a = context.callback) === null || _a === void 0 ? void 0 : _a.hooks) === null || _b === void 0 ? void 0 : _b.onTabCreated) === null || _c === void 0 ? void 0 : _c.call(_b, tab.id);
2275
- searchInfo.running++;
2276
- let eventId = taskId + '_' + i + '_' + j;
2277
- // Create a timeout promise
2278
- const timeoutPromise = new Promise((_, reject) => {
2279
- setTimeout(() => reject(new Error('Page load timeout')), 10000); // Timeout after 10 seconds
2280
- });
2281
- // Create a tab monitoring promise
2282
- const monitorTabPromise = new Promise(async (resolve, reject) => {
2283
- tabsUpdateEvent.addListener(async function onTabUpdated(obj) {
2284
- if (obj.tabId !== tab.id)
2285
- return;
2286
- if (obj.changeInfo.status === 'complete') {
2287
- tabsUpdateEvent.removeListener(eventId);
2288
- try {
2289
- // Inject script and get page content
2290
- await injectScript(context.ekoConfig.chromeProxy, tab.id, filename);
2291
- await sleep(1000);
2292
- let result = await context.ekoConfig.chromeProxy.tabs.sendMessage(tab.id, {
2293
- type: 'page:getContent',
2294
- });
2295
- if (!result)
2296
- throw new Error('No Result');
2297
- link.content = result.content;
2298
- link.page_title = result.title;
2299
- searchInfo.succeed++;
2300
- resolve(); // Resolve the promise if successful
2301
- }
2302
- catch (error) {
2303
- searchInfo.failed++;
2304
- searchInfo.failedLinks.push(link);
2305
- reject(error); // Reject the promise on error
2306
- }
2307
- finally {
2308
- searchInfo.running--;
2309
- countDownLatch.countDown();
2310
- context.ekoConfig.chromeProxy.tabs.remove(tab.id);
2311
- tabsUpdateEvent.removeListener(eventId);
2312
- }
2313
- }
2314
- else if (obj.changeInfo.status === 'unloaded') {
2315
- searchInfo.running--;
2316
- countDownLatch.countDown();
2317
- context.ekoConfig.chromeProxy.tabs.remove(tab.id);
2318
- tabsUpdateEvent.removeListener(eventId);
2319
- reject(new Error('Tab unloaded')); // Reject if the tab is unloaded
2320
- }
2321
- }, eventId);
2322
- });
2323
- // Use Promise.race to enforce the timeout
2324
- try {
2325
- await Promise.race([monitorTabPromise, timeoutPromise]);
2326
- }
2327
- catch (e) {
2328
- logger.error(`${link.title} failed:`, e);
2329
- searchInfo.running--;
2330
- searchInfo.failed++;
2331
- searchInfo.failedLinks.push(link);
2332
- countDownLatch.countDown();
2333
- context.ekoConfig.chromeProxy.tabs.remove(tab.id); // Clean up tab on failure
2334
- }
2335
- }
2336
- }
2337
- await countDownLatch.await(60000);
2338
- return searchInfo;
2339
- }
2340
-
2341
- class RequestLogin {
2342
- constructor() {
2343
- this.name = 'request_login';
2344
- this.description =
2345
- 'Login to this website, assist with identity verification when manual intervention is needed, guide users through the login process, and wait for their confirmation of successful login.';
2346
- this.input_schema = {
2347
- type: 'object',
2348
- properties: {},
2349
- };
2350
- }
2351
- async execute(context, params) {
2352
- if (!params.force && await this.isLoginIn(context)) {
2353
- return true;
2354
- }
2355
- let tabId = await getTabId(context);
2356
- let task_id = 'login_required_' + tabId;
2357
- const request_user_help = async () => {
2358
- await context.ekoConfig.chromeProxy.tabs.sendMessage(tabId, {
2359
- type: 'request_user_help',
2360
- task_id,
2361
- failure_type: 'login_required',
2362
- failure_message: 'Access page require user authentication.',
2363
- });
2364
- };
2365
- const login_interval = setInterval(async () => {
2366
- try {
2367
- request_user_help();
2368
- }
2369
- catch (e) {
2370
- clearInterval(login_interval);
2371
- }
2372
- }, 2000);
2373
- try {
2374
- return await this.awaitLogin(context.ekoConfig.chromeProxy, tabId, task_id);
2375
- }
2376
- finally {
2377
- clearInterval(login_interval);
2378
- }
2379
- }
2380
- async awaitLogin(chromeProxy, tabId, task_id) {
2381
- return new Promise((resolve) => {
2382
- const checkTabClosedInterval = setInterval(async () => {
2383
- const tabExists = await doesTabExists(chromeProxy, tabId);
2384
- if (!tabExists) {
2385
- clearInterval(checkTabClosedInterval);
2386
- resolve(false);
2387
- chromeProxy.runtime.onMessage.removeListener(listener);
2388
- }
2389
- }, 1000);
2390
- const listener = (message) => {
2391
- if (message.type === 'issue_resolved' && message.task_id === task_id) {
2392
- resolve(true);
2393
- clearInterval(checkTabClosedInterval);
2394
- }
2395
- };
2396
- chromeProxy.runtime.onMessage.addListener(listener);
2397
- });
2398
- }
2399
- async isLoginIn(context) {
2400
- let windowId = await getWindowId(context);
2401
- let screenshot_result = await screenshot(context.ekoConfig.chromeProxy, windowId, true);
2402
- let messages = [
2403
- {
2404
- role: 'user',
2405
- content: [
2406
- {
2407
- type: 'image',
2408
- source: screenshot_result.image,
2409
- },
2410
- {
2411
- type: 'text',
2412
- text: 'Check if the current website is logged in. If not logged in, output `NOT_LOGIN`. If logged in, output `LOGGED_IN`. Output directly without explanation.',
2413
- },
2414
- ],
2415
- },
2416
- ];
2417
- let response = await context.llmProvider.generateText(messages, { maxTokens: 256 });
2418
- let text = response.textContent;
2419
- if (!text) {
2420
- text = JSON.stringify(response.content);
2421
- }
2422
- return text.indexOf('LOGGED_IN') > -1;
2423
- }
2424
- }
2425
-
2426
- class SwitchTab {
2427
- constructor() {
2428
- this.name = 'switch_tab';
2429
- this.description = 'Switch to the specified tab using tabId';
2430
- this.input_schema = {
2431
- type: 'object',
2432
- properties: {
2433
- tabId: {
2434
- type: 'integer',
2435
- description: 'The tabId to switch to',
2436
- },
2437
- },
2438
- required: ['tabId'],
2439
- };
2440
- }
2441
- async execute(context, params) {
2442
- if (params === null || !params.tabId) {
2443
- throw new Error('Invalid parameters. Expected an object with a "tabId" property.');
2444
- }
2445
- let result;
2446
- let tabId = parseInt(String(params.tabId));
2447
- let tab = await context.ekoConfig.chromeProxy.tabs.update(tabId, { active: true });
2448
- context.variables.set('tabId', tab.id);
2449
- context.variables.set('windowId', tab.windowId);
2450
- let tabInfo = { tabId, windowId: tab.windowId, title: tab.title, url: tab.url };
2451
- result = tabInfo;
2452
- return result;
2453
- }
2454
- }
2455
-
2456
- class CancelWorkflow {
2457
- constructor() {
2458
- this.name = 'cancel_workflow';
2459
- this.description = 'Cancel the workflow when encountering critical errors that cannot be resolved through user interaction or retry. This should only be used when the workflow is in an unrecoverable state. ';
2460
- this.input_schema = {
2461
- type: 'object',
2462
- properties: {
2463
- reason: {
2464
- type: 'string',
2465
- description: 'Why the workflow should be cancelled.',
2466
- },
2467
- },
2468
- required: ['reason'],
2469
- };
2470
- }
2471
- async execute(context, params) {
2472
- var _a;
2473
- if (typeof params !== 'object' || params === null || !params.reason) {
2474
- throw new Error('Invalid parameters. Expected an object with a "reason" property.');
2475
- }
2476
- const reason = params.reason;
2477
- logger.info("The workflow has been cancelled because: " + reason);
2478
- await ((_a = context.workflow) === null || _a === void 0 ? void 0 : _a.cancel());
2479
- return;
2480
- }
2481
- }
2482
-
2483
- class HumanInputText {
2484
- constructor() {
2485
- this.name = 'human_input_text';
2486
- this.description = 'When you are unsure about the details of your next action or need the user to perform a local action, call me and ask the user for details in the "question" field. The user will provide you with a text as an answer.';
2487
- this.input_schema = {
2488
- type: 'object',
2489
- properties: {
2490
- question: {
2491
- type: 'string',
2492
- description: 'Ask the user here. Should follow the format: "Please input ...".',
2493
- },
2494
- },
2495
- required: ['question'],
2496
- };
2497
- }
2498
- async execute(context, params) {
2499
- var _a;
2500
- if (typeof params !== 'object' || params === null || !params.question) {
2501
- throw new Error('Invalid parameters. Expected an object with a "question" property.');
2502
- }
2503
- const question = params.question;
2504
- logger.debug("question: " + question);
2505
- let onHumanInputText = (_a = context.callback) === null || _a === void 0 ? void 0 : _a.hooks.onHumanInputText;
2506
- if (onHumanInputText) {
2507
- let answer;
2508
- try {
2509
- answer = await onHumanInputText(question);
2510
- }
2511
- catch (e) {
2512
- logger.warn(e);
2513
- return { status: "Error: Cannot get user's answer.", answer: "" };
2514
- }
2515
- logger.debug("answer: " + answer);
2516
- return { status: "OK", answer: answer };
2517
- }
2518
- else {
2519
- logger.error("`onHumanInputText` not implemented");
2520
- return { status: "Error: Cannot get user's answer.", answer: "" };
2521
- }
2522
- }
2523
- }
2524
- class HumanInputSingleChoice {
2525
- constructor() {
2526
- this.name = 'human_input_single_choice';
2527
- this.description = 'When you are unsure about the details of your next action, call me and ask the user for details in the "question" field with at least 2 choices. The user will provide you with ONE choice as an answer.';
2528
- this.input_schema = {
2529
- type: 'object',
2530
- properties: {
2531
- question: {
2532
- type: 'string',
2533
- description: 'Ask the user here. Should follow the format: "Please select ...".',
2534
- },
2535
- choices: {
2536
- type: 'array',
2537
- description: 'All of the choices.',
2538
- items: {
2539
- type: 'object',
2540
- properties: {
2541
- choice: {
2542
- type: 'string',
2543
- }
2544
- }
2545
- }
2546
- }
2547
- },
2548
- required: ['question', 'choices'],
2549
- };
2550
- }
2551
- async execute(context, params) {
2552
- var _a;
2553
- if (typeof params !== 'object' || params === null || !params.question || !params.choices) {
2554
- throw new Error('Invalid parameters. Expected an object with a "question" and "choices" property.');
2555
- }
2556
- const question = params.question;
2557
- const choices = params.choices.map((e) => e.choice);
2558
- logger.debug("question: " + question);
2559
- logger.debug("choices: " + choices);
2560
- let onHumanInputSingleChoice = (_a = context.callback) === null || _a === void 0 ? void 0 : _a.hooks.onHumanInputSingleChoice;
2561
- if (onHumanInputSingleChoice) {
2562
- let answer;
2563
- try {
2564
- answer = await onHumanInputSingleChoice(question, choices);
2565
- }
2566
- catch (e) {
2567
- logger.warn(e);
2568
- return { status: "Error: Cannot get user's answer.", answer: "" };
2569
- }
2570
- logger.debug("answer: " + answer);
2571
- return { status: "OK", answer: answer };
2572
- }
2573
- else {
2574
- logger.error("`onHumanInputSingleChoice` not implemented");
2575
- return { status: "Error: Cannot get user's answer.", answer: "" };
2576
- }
2577
- }
2578
- }
2579
- class HumanInputMultipleChoice {
2580
- constructor() {
2581
- this.name = 'human_input_multiple_choice';
2582
- this.description = 'When you are unsure about the details of your next action, call me and ask the user for details in the "question" field with at least 2 choices. The user will provide you with ONE or MORE choice as an answer.';
2583
- this.input_schema = {
2584
- type: 'object',
2585
- properties: {
2586
- question: {
2587
- type: 'string',
2588
- description: 'Ask the user here. Should follow the format: "Please select ...".',
2589
- },
2590
- choices: {
2591
- type: 'array',
2592
- description: 'All of the choices.',
2593
- items: {
2594
- type: 'object',
2595
- properties: {
2596
- choice: {
2597
- type: 'string',
2598
- }
2599
- }
2600
- }
2601
- }
2602
- },
2603
- required: ['question', 'choices'],
2604
- };
2605
- }
2606
- async execute(context, params) {
2607
- var _a;
2608
- if (typeof params !== 'object' || params === null || !params.question || !params.choices) {
2609
- throw new Error('Invalid parameters. Expected an object with a "question" and "choices" property.');
2610
- }
2611
- const question = params.question;
2612
- const choices = params.choices.map((e) => e.choice);
2613
- logger.debug("question: " + question);
2614
- logger.debug("choices: " + choices);
2615
- let onHumanInputMultipleChoice = (_a = context.callback) === null || _a === void 0 ? void 0 : _a.hooks.onHumanInputMultipleChoice;
2616
- if (onHumanInputMultipleChoice) {
2617
- let answer;
2618
- try {
2619
- answer = await onHumanInputMultipleChoice(question, choices);
2620
- }
2621
- catch (e) {
2622
- logger.warn(e);
2623
- return { status: "Error: Cannot get user's answer.", answer: [] };
2624
- }
2625
- logger.debug("answer: " + answer);
2626
- return { status: "OK", answer: answer };
2627
- }
2628
- else {
2629
- logger.error("`onHumanInputMultipleChoice` not implemented");
2630
- return { status: "Error: Cannot get user's answer.", answer: [] };
2631
- }
2632
- }
2633
- }
2634
- class HumanOperate {
2635
- constructor() {
2636
- this.name = 'human_operate';
2637
- this.description = `Use this tool when one of following appears:
2638
- 1. Authentication (such as logging in, entering a verification code, etc.)
2639
- 2. External system operations (such as uploading files, selecting a file save location, scanning documents, taking photos, paying, authorization, etc.)
2640
-
2641
- NOTE: You should ONLY use this tool in the scenarios above.
2642
-
2643
- When calling this tool to transfer control to the user, please explain in detail:
2644
- 1. Why user intervention is required
2645
- 2. What operations the user needs to perform`;
2646
- this.input_schema = {
2647
- type: 'object',
2648
- properties: {
2649
- reason: {
2650
- type: 'string',
2651
- description: 'The reason why you need to transfer control. Should follow the format: "Please ..., and click the "Completed" button to continue.".',
2652
- },
2653
- },
2654
- required: ['reason'],
2655
- };
2656
- }
2657
- async execute(context, params) {
2658
- var _a;
2659
- if (typeof params !== 'object' || params === null || !params.reason) {
2660
- throw new Error('Invalid parameters. Expected an object with a "reason" property.');
2661
- }
2662
- const reason = params.reason;
2663
- logger.debug("reason: " + reason);
2664
- let onHumanOperate = (_a = context.callback) === null || _a === void 0 ? void 0 : _a.hooks.onHumanOperate;
2665
- if (onHumanOperate) {
2666
- let userOperation;
2667
- try {
2668
- userOperation = await onHumanOperate(reason);
2669
- }
2670
- catch (e) {
2671
- logger.warn(e);
2672
- return { status: "Error: Cannot get user's operation.", userOperation: "" };
2673
- }
2674
- logger.debug("userOperation: " + userOperation);
2675
- if (userOperation == "") {
2676
- return { status: "OK", userOperation: "Done. Please take a screenshot to ensure the result." };
2677
- }
2678
- else {
2679
- return { status: "OK", userOperation: userOperation + "\n\nPlease take a screenshot to ensure the result." };
2680
- }
2681
- }
2682
- else {
2683
- logger.error("`onHumanOperate` not implemented");
2684
- return { status: "Error: Cannot get user's operation.", userOperation: "" };
2685
- }
2686
- }
2687
- }
2688
-
2689
- class DocumentAgentTool {
2690
- constructor() {
2691
- this.name = 'document_agent';
2692
- this.description = 'A document agent that can help you write document or long text, e.g. research report, email draft, summary.';
2693
- this.input_schema = {
2694
- "type": "object",
2695
- "properties": {
2696
- "type": {
2697
- "type": "string",
2698
- "description": "The type of document to be created (e.g., 'report', 'presentation', 'article')."
2699
- },
2700
- "title": {
2701
- "type": "string",
2702
- "description": "The title of the document."
2703
- },
2704
- "background": {
2705
- "type": "string",
2706
- "description": "The background information or target for the document."
2707
- },
2708
- "keypoints": {
2709
- "type": "string",
2710
- "description": "A summary of the key points or main ideas to be included in the document."
2711
- },
2712
- "style": {
2713
- "type": "string",
2714
- "description": "The desired style or tone of the document (e.g., 'formal', 'casual', 'academic')."
2715
- },
2716
- },
2717
- "required": ["type", "title", "background", "keypoints"],
2718
- };
2719
- }
2720
- async execute(context, params) {
2721
- params.references = context.variables;
2722
- const messages = [
2723
- {
2724
- role: 'system',
2725
- content: 'You are an excellent writer, skilled at composing various types of copywriting and texts in different styles. You can draft documents based on the title, background, or reference materials provided by clients. Now, the client will provide you with a lot of information, including the type of copywriting, title, background, key points, style, and reference materials. Please write a document in Markdown format.',
2726
- },
2727
- {
2728
- role: 'user',
2729
- content: JSON.stringify(params),
2730
- },
2731
- ];
2732
- const llmParams = { maxTokens: 8192 };
2733
- const response = await context.llmProvider.generateText(messages, llmParams);
2734
- const content = typeof response.content == 'string' ? response.content : response.content[0].text;
2735
- context.variables.set("workflow_transcript", content);
2736
- return { status: "OK", content };
2737
- }
2738
- }
2739
-
2740
- var tools = /*#__PURE__*/Object.freeze({
2741
- __proto__: null,
2742
- BrowserAction: BrowserAction,
2743
- CancelWorkflow: CancelWorkflow,
2744
- DocumentAgentTool: DocumentAgentTool,
2745
- ExportFile: ExportFile,
2746
- ExtractContent: ExtractContent,
2747
- GetAllTabs: GetAllTabs,
2748
- HumanInputMultipleChoice: HumanInputMultipleChoice,
2749
- HumanInputSingleChoice: HumanInputSingleChoice,
2750
- HumanInputText: HumanInputText,
2751
- HumanOperate: HumanOperate,
2752
- OpenUrl: OpenUrl,
2753
- RequestLogin: RequestLogin,
2754
- Screenshot: Screenshot,
2755
- SwitchTab: SwitchTab,
2756
- TabManagement: TabManagement,
2757
- WebSearch: WebSearch
2758
- });
2759
-
2760
- async function pub(chromeProxy, tabId, event, params) {
2761
- return await chromeProxy.tabs.sendMessage(tabId, {
2762
- type: 'eko:message',
2763
- event,
2764
- params,
2765
- });
2766
- }
2767
- async function getLLMConfig(chromeProxy, name = 'llmConfig') {
2768
- let result = await chromeProxy.storage.sync.get([name]);
2769
- return result[name];
2770
- }
2771
- function loadTools() {
2772
- let toolsMap = new Map();
2773
- for (const key in tools) {
2774
- let tool = tools[key];
2775
- if (typeof tool === 'function' && tool.prototype && 'execute' in tool.prototype) {
2776
- try {
2777
- let instance = new tool();
2778
- toolsMap.set(instance.name || key, instance);
2779
- }
2780
- catch (e) {
2781
- logger.error(`Failed to instantiate ${key}:`, e);
2782
- }
2783
- }
2784
- }
2785
- return toolsMap;
2786
- }
2787
-
2788
- exports.browser = browser;
2789
- exports.getLLMConfig = getLLMConfig;
2790
- exports.loadTools = loadTools;
2791
- exports.pub = pub;
2792
- exports.tools = tools;
2793
- exports.utils = utils;