@johpaz/hive-sdk 0.0.12 → 0.0.15
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/CODEOWNERS +9 -0
- package/.github/workflows/publish.yml +89 -0
- package/.github/workflows/version-bump.yml +102 -0
- package/CHANGELOG.md +38 -0
- package/README.md +158 -0
- package/bun.lock +543 -0
- package/bunfig.toml +7 -0
- package/docs/API-AGENTS.md +316 -0
- package/docs/API-CONTEXT-COMPILER.md +252 -0
- package/docs/API-DAG-SCHEDULER.md +273 -0
- package/docs/API-TOOLS-SKILLS-CHANNELS.md +293 -0
- package/docs/API-WORKERS-EVENTS.md +152 -0
- package/docs/INDEX.md +141 -0
- package/docs/README.md +68 -0
- package/package.json +54 -105
- package/packages/cli/package.json +17 -0
- package/packages/cli/src/commands/init.ts +56 -0
- package/packages/cli/src/commands/run.ts +45 -0
- package/packages/cli/src/commands/test.ts +42 -0
- package/packages/cli/src/commands/trace.ts +55 -0
- package/packages/cli/src/index.ts +43 -0
- package/packages/core/package.json +58 -0
- package/packages/core/src/ace/Curator.ts +158 -0
- package/packages/core/src/ace/Reflector.ts +200 -0
- package/packages/core/src/ace/Tracer.ts +100 -0
- package/packages/core/src/ace/index.ts +4 -0
- package/packages/core/src/agent/AgentRunner.ts +699 -0
- package/packages/core/src/agent/Compaction.ts +221 -0
- package/packages/core/src/agent/ContextCompiler.ts +567 -0
- package/packages/core/src/agent/ContextGuard.ts +91 -0
- package/packages/core/src/agent/ConversationStore.ts +244 -0
- package/packages/core/src/agent/Hooks.ts +166 -0
- package/packages/core/src/agent/NativeTools.ts +31 -0
- package/packages/core/src/agent/PromptBuilder.ts +169 -0
- package/packages/core/src/agent/Service.ts +267 -0
- package/packages/core/src/agent/StuckLoop.ts +133 -0
- package/packages/core/src/agent/index.ts +12 -0
- package/packages/core/src/agent/providers/LLMClient.ts +149 -0
- package/packages/core/src/agent/providers/anthropic.ts +212 -0
- package/packages/core/src/agent/providers/gemini.ts +215 -0
- package/packages/core/src/agent/providers/index.ts +199 -0
- package/packages/core/src/agent/providers/interface.ts +195 -0
- package/packages/core/src/agent/providers/ollama.ts +175 -0
- package/packages/core/src/agent/providers/openai-compat.ts +231 -0
- package/packages/core/src/agent/providers.ts +1 -0
- package/packages/core/src/agent/selectors/PlaybookSelector.ts +147 -0
- package/packages/core/src/agent/selectors/SkillSelector.ts +478 -0
- package/packages/core/src/agent/selectors/ToolSelector.ts +577 -0
- package/packages/core/src/agent/selectors/index.ts +6 -0
- package/packages/core/src/api/createAgent.test.ts +48 -0
- package/packages/core/src/api/createAgent.ts +122 -0
- package/packages/core/src/api/index.ts +2 -0
- package/packages/core/src/canvas/CanvasManager.ts +390 -0
- package/packages/core/src/canvas/a2ui-tools.ts +255 -0
- package/packages/core/src/canvas/canvas-tools.ts +448 -0
- package/packages/core/src/canvas/emitter.ts +149 -0
- package/packages/core/src/canvas/index.ts +6 -0
- package/packages/core/src/config/index.ts +2 -0
- package/packages/core/src/config/loader.ts +554 -0
- package/packages/core/src/ethics/EthicsGuard.test.ts +54 -0
- package/packages/core/src/ethics/EthicsGuard.ts +66 -0
- package/packages/core/src/ethics/index.ts +2 -0
- package/packages/core/src/gateway/channel-notify.test.ts +14 -0
- package/packages/core/src/gateway/channel-notify.ts +12 -0
- package/packages/core/src/gateway/index.ts +1 -0
- package/packages/core/src/index.ts +37 -0
- package/packages/core/src/mcp/MCPClient.ts +439 -0
- package/packages/core/src/mcp/MCPToolAdapter.ts +176 -0
- package/packages/core/src/mcp/config.ts +13 -0
- package/packages/core/src/mcp/hot-reload.ts +147 -0
- package/packages/core/src/mcp/index.ts +11 -0
- package/packages/core/src/mcp/logger.ts +42 -0
- package/packages/core/src/mcp/singleton.ts +21 -0
- package/packages/core/src/mcp/transports/index.ts +67 -0
- package/packages/core/src/mcp/transports/sse.ts +241 -0
- package/packages/core/src/mcp/transports/websocket.ts +159 -0
- package/packages/core/src/memory/Scratchpad.test.ts +47 -0
- package/packages/core/src/memory/Scratchpad.ts +37 -0
- package/packages/core/src/memory/Storage.ts +6 -0
- package/packages/core/src/memory/index.ts +2 -0
- package/packages/core/src/multimodal/VisionService.ts +293 -0
- package/packages/core/src/multimodal/index.ts +2 -0
- package/packages/core/src/multimodal/types.ts +28 -0
- package/packages/core/src/security/Pairing.ts +250 -0
- package/packages/core/src/security/RateLimit.ts +270 -0
- package/packages/core/src/security/index.ts +4 -0
- package/packages/core/src/skills/SkillLoader.ts +388 -0
- package/packages/core/src/skills/bundled-data.generated.ts +3332 -0
- package/packages/core/src/skills/defineSkill.ts +18 -0
- package/packages/core/src/skills/index.ts +4 -0
- package/packages/core/src/state/index.ts +2 -0
- package/packages/core/src/state/store.ts +312 -0
- package/packages/core/src/storage/SQLiteStorage.ts +407 -0
- package/packages/core/src/storage/crypto.ts +101 -0
- package/packages/core/src/storage/index.ts +10 -0
- package/packages/core/src/storage/onboarding.ts +1603 -0
- package/packages/core/src/storage/schema.ts +689 -0
- package/packages/core/src/storage/seed.ts +740 -0
- package/packages/core/src/storage/usage.ts +374 -0
- package/packages/core/src/swarm/AgentBus.ts +460 -0
- package/packages/core/src/swarm/AgentExecutor.ts +53 -0
- package/packages/core/src/swarm/Coordinator.ts +251 -0
- package/packages/core/src/swarm/EventBridge.ts +122 -0
- package/packages/core/src/swarm/EventBus.ts +169 -0
- package/packages/core/src/swarm/TaskGraph.ts +192 -0
- package/packages/core/src/swarm/TaskNode.ts +97 -0
- package/packages/core/src/swarm/TaskResult.ts +22 -0
- package/packages/core/src/swarm/WorkerPool.ts +236 -0
- package/packages/core/src/swarm/errors.ts +37 -0
- package/packages/core/src/swarm/index.ts +30 -0
- package/packages/core/src/swarm/presets/HiveLearnPreset.ts +99 -0
- package/packages/core/src/swarm/presets/ResearchPreset.ts +97 -0
- package/packages/core/src/swarm/presets/index.ts +4 -0
- package/packages/core/src/swarm/strategies/ParallelStrategy.ts +21 -0
- package/packages/core/src/swarm/strategies/PriorityStrategy.ts +46 -0
- package/packages/core/src/swarm/strategies/index.ts +3 -0
- package/packages/core/src/swarm/types.ts +164 -0
- package/packages/core/src/tools/ToolExecutor.ts +58 -0
- package/packages/core/src/tools/ToolRegistry.test.ts +98 -0
- package/packages/core/src/tools/ToolRegistry.ts +61 -0
- package/packages/core/src/tools/agents/get-available-models.ts +118 -0
- package/packages/core/src/tools/agents/index.ts +715 -0
- package/packages/core/src/tools/bridge-events.ts +26 -0
- package/packages/core/src/tools/canvas/index.ts +375 -0
- package/packages/core/src/tools/cli/index.ts +142 -0
- package/packages/core/src/tools/codebridge/index.ts +342 -0
- package/packages/core/src/tools/core/index.ts +476 -0
- package/packages/core/src/tools/cron/index.ts +626 -0
- package/packages/core/src/tools/filesystem/fs-delete.ts +78 -0
- package/packages/core/src/tools/filesystem/fs-edit.ts +106 -0
- package/packages/core/src/tools/filesystem/fs-exists.ts +63 -0
- package/packages/core/src/tools/filesystem/fs-glob.ts +108 -0
- package/packages/core/src/tools/filesystem/fs-list.ts +129 -0
- package/packages/core/src/tools/filesystem/fs-read.ts +72 -0
- package/packages/core/src/tools/filesystem/fs-write.ts +67 -0
- package/packages/core/src/tools/filesystem/index.ts +34 -0
- package/packages/core/src/tools/filesystem/workspace-guard.ts +62 -0
- package/packages/core/src/tools/index.ts +231 -0
- package/packages/core/src/tools/meeting/index.ts +363 -0
- package/packages/core/src/tools/office/index.ts +47 -0
- package/packages/core/src/tools/office/office-escribir-docx.ts +192 -0
- package/packages/core/src/tools/office/office-escribir-pdf.ts +172 -0
- package/packages/core/src/tools/office/office-escribir-pptx.ts +174 -0
- package/packages/core/src/tools/office/office-escribir-xlsx.ts +116 -0
- package/packages/core/src/tools/office/office-leer-docx.ts +93 -0
- package/packages/core/src/tools/office/office-leer-pdf.ts +114 -0
- package/packages/core/src/tools/office/office-leer-pptx.ts +136 -0
- package/packages/core/src/tools/office/office-leer-xlsx.ts +124 -0
- package/packages/core/src/tools/projects/index.ts +37 -0
- package/packages/core/src/tools/projects/project-create.ts +94 -0
- package/packages/core/src/tools/projects/project-done.ts +66 -0
- package/packages/core/src/tools/projects/project-fail.ts +66 -0
- package/packages/core/src/tools/projects/project-list.ts +96 -0
- package/packages/core/src/tools/projects/project-update.ts +72 -0
- package/packages/core/src/tools/projects/task-create.ts +68 -0
- package/packages/core/src/tools/projects/task-evaluate.ts +93 -0
- package/packages/core/src/tools/projects/task-update.ts +93 -0
- package/packages/core/src/tools/types.ts +39 -0
- package/packages/core/src/tools/voice/index.ts +104 -0
- package/packages/core/src/tools/web/browser-click.ts +78 -0
- package/packages/core/src/tools/web/browser-extract.ts +139 -0
- package/packages/core/src/tools/web/browser-navigate.ts +106 -0
- package/packages/core/src/tools/web/browser-screenshot.ts +87 -0
- package/packages/core/src/tools/web/browser-script.ts +88 -0
- package/packages/core/src/tools/web/browser-service.ts +554 -0
- package/packages/core/src/tools/web/browser-type.ts +101 -0
- package/packages/core/src/tools/web/browser-wait.ts +136 -0
- package/packages/core/src/tools/web/index.ts +41 -0
- package/packages/core/src/tools/web/web-fetch.ts +78 -0
- package/packages/core/src/tools/web/web-search.ts +123 -0
- package/packages/core/src/utils/benchmark.ts +80 -0
- package/packages/core/src/utils/crypto.ts +73 -0
- package/packages/core/src/utils/date.ts +42 -0
- package/packages/core/src/utils/index.ts +10 -0
- package/packages/core/src/utils/logger.ts +389 -0
- package/packages/core/src/utils/retry.ts +70 -0
- package/packages/core/src/utils/toon.ts +253 -0
- package/packages/core/src/voice/index.ts +656 -0
- package/test/setup-db.ts +216 -0
- package/tsconfig.json +39 -0
- package/src/agents.ts +0 -1
- package/src/canvas.ts +0 -1
- package/src/channels.ts +0 -1
- package/src/config.ts +0 -1
- package/src/events.ts +0 -1
- package/src/gateway.ts +0 -1
- package/src/index.ts +0 -304
- package/src/mcp.ts +0 -1
- package/src/multimodal.ts +0 -1
- package/src/scheduler.ts +0 -1
- package/src/security.ts +0 -1
- package/src/skills.ts +0 -1
- package/src/state.ts +0 -1
- package/src/storage.ts +0 -1
- package/src/tools.ts +0 -1
- package/src/tts.ts +0 -1
- package/src/types.ts +0 -82
- package/src/utils.ts +0 -1
- package/src/voice.ts +0 -1
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* browser_click - Click on a web page element
|
|
3
|
+
*
|
|
4
|
+
* @category web
|
|
5
|
+
* @seedId browser_click
|
|
6
|
+
* @spanish hacer clic, botón, enlace, interactuar
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import type { Tool } from "../types.ts";
|
|
10
|
+
import { logger } from "../../utils/logger.ts";
|
|
11
|
+
import { getBrowserService } from "./browser-service.ts";
|
|
12
|
+
|
|
13
|
+
const log = logger.child("browser-click");
|
|
14
|
+
|
|
15
|
+
export const browserClickTool: Tool = {
|
|
16
|
+
name: "browser_click",
|
|
17
|
+
description: "Click on a web page element. Spanish: hacer clic, botón, enlace, interactuar",
|
|
18
|
+
parameters: {
|
|
19
|
+
type: "object",
|
|
20
|
+
properties: {
|
|
21
|
+
selector: {
|
|
22
|
+
type: "string",
|
|
23
|
+
description: "CSS selector of the element to click",
|
|
24
|
+
},
|
|
25
|
+
url: {
|
|
26
|
+
type: "string",
|
|
27
|
+
description: "URL to navigate to before clicking (optional)",
|
|
28
|
+
},
|
|
29
|
+
timeout: {
|
|
30
|
+
type: "number",
|
|
31
|
+
description: "Timeout in milliseconds (default: 30000)",
|
|
32
|
+
},
|
|
33
|
+
},
|
|
34
|
+
required: ["selector"],
|
|
35
|
+
},
|
|
36
|
+
execute: async (params: Record<string, unknown>) => {
|
|
37
|
+
const selector = params.selector as string;
|
|
38
|
+
const url = params.url as string | undefined;
|
|
39
|
+
const timeout = (params.timeout as number) ?? 30000;
|
|
40
|
+
|
|
41
|
+
const browserService = getBrowserService();
|
|
42
|
+
if (!browserService?.isAvailable()) {
|
|
43
|
+
log.warn("Browser not available");
|
|
44
|
+
return {
|
|
45
|
+
ok: false,
|
|
46
|
+
error: "Browser automation not available. Install Chrome/Chromium.",
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
log.info(`Clicking: ${selector}${url ? ` on ${url}` : ""}`);
|
|
51
|
+
|
|
52
|
+
try {
|
|
53
|
+
const view = await browserService.getView();
|
|
54
|
+
if (!view) return { ok: false, error: "Browser automation not available. Install Chrome/Chromium." };
|
|
55
|
+
|
|
56
|
+
if (url) {
|
|
57
|
+
await view.navigate(url);
|
|
58
|
+
await Bun.sleep(500);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// click(selector) already waits for element actionability
|
|
62
|
+
await view.click(selector, { timeout });
|
|
63
|
+
|
|
64
|
+
const currentUrl = view.url;
|
|
65
|
+
log.info(`Click successful: ${selector} on ${currentUrl}`);
|
|
66
|
+
|
|
67
|
+
return {
|
|
68
|
+
ok: true,
|
|
69
|
+
message: `Successfully clicked element: ${selector}`,
|
|
70
|
+
selector,
|
|
71
|
+
url: currentUrl,
|
|
72
|
+
};
|
|
73
|
+
} catch (error) {
|
|
74
|
+
log.error(`Click failed: ${(error as Error).message}`);
|
|
75
|
+
return { ok: false, error: `Failed to click: ${(error as Error).message}` };
|
|
76
|
+
}
|
|
77
|
+
},
|
|
78
|
+
};
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* browser_extract - Extract data from web page using selectors
|
|
3
|
+
*
|
|
4
|
+
* @category web
|
|
5
|
+
* @seedId browser_extract
|
|
6
|
+
* @spanish extraer datos, obtener información, scraping, selectores
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import type { Tool } from "../types.ts";
|
|
10
|
+
import { logger } from "../../utils/logger.ts";
|
|
11
|
+
import { getBrowserService, waitForSelector, waitForCondition } from "./browser-service.ts";
|
|
12
|
+
|
|
13
|
+
const log = logger.child("browser-extract");
|
|
14
|
+
|
|
15
|
+
export const browserExtractTool: Tool = {
|
|
16
|
+
name: "browser_extract",
|
|
17
|
+
description: "Extract text, links, or structured data from page using CSS selectors or XPath. Spanish: extraer datos, obtener información, scraping, selectores",
|
|
18
|
+
parameters: {
|
|
19
|
+
type: "object",
|
|
20
|
+
properties: {
|
|
21
|
+
url: {
|
|
22
|
+
type: "string",
|
|
23
|
+
description: "URL to navigate to before extraction (optional)",
|
|
24
|
+
},
|
|
25
|
+
selector: {
|
|
26
|
+
type: "string",
|
|
27
|
+
description: "CSS selector or XPath (prefix with 'xpath:') to match elements",
|
|
28
|
+
},
|
|
29
|
+
attribute: {
|
|
30
|
+
type: "string",
|
|
31
|
+
description: "Attribute to extract (href, src, alt, text, innerHTML). Default: text",
|
|
32
|
+
},
|
|
33
|
+
all: {
|
|
34
|
+
type: "boolean",
|
|
35
|
+
description: "Extract all matches (default: true) or just first (false)",
|
|
36
|
+
},
|
|
37
|
+
timeout: {
|
|
38
|
+
type: "number",
|
|
39
|
+
description: "Timeout in milliseconds (default: 30000)",
|
|
40
|
+
},
|
|
41
|
+
},
|
|
42
|
+
required: ["selector"],
|
|
43
|
+
},
|
|
44
|
+
execute: async (params: Record<string, unknown>) => {
|
|
45
|
+
const url = params.url as string | undefined;
|
|
46
|
+
const selector = params.selector as string;
|
|
47
|
+
const attribute = (params.attribute as string) ?? "text";
|
|
48
|
+
const all = (params.all as boolean) ?? true;
|
|
49
|
+
const timeout = (params.timeout as number) ?? 30000;
|
|
50
|
+
|
|
51
|
+
const browserService = getBrowserService();
|
|
52
|
+
if (!browserService?.isAvailable()) {
|
|
53
|
+
log.warn("Browser not available");
|
|
54
|
+
return {
|
|
55
|
+
ok: false,
|
|
56
|
+
error: "Browser automation not available. Install Chrome/Chromium.",
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
log.info(`Extracting: ${selector}${url ? ` from ${url}` : ""}`);
|
|
61
|
+
|
|
62
|
+
try {
|
|
63
|
+
const view = await browserService.getView();
|
|
64
|
+
if (!view) return { ok: false, error: "Browser automation not available. Install Chrome/Chromium." };
|
|
65
|
+
|
|
66
|
+
if (url) {
|
|
67
|
+
await view.navigate(url);
|
|
68
|
+
await Bun.sleep(500);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
const isXPath = selector.startsWith("xpath:");
|
|
72
|
+
const actualSelector = isXPath ? selector.slice(6) : selector;
|
|
73
|
+
|
|
74
|
+
// Esperar el elemento — si no aparece, continuar igual
|
|
75
|
+
try {
|
|
76
|
+
if (isXPath) {
|
|
77
|
+
const xpathExpr = `(() => {
|
|
78
|
+
const r = document.evaluate(
|
|
79
|
+
${JSON.stringify(actualSelector)}, document, null,
|
|
80
|
+
XPathResult.FIRST_ORDERED_NODE_TYPE, null
|
|
81
|
+
);
|
|
82
|
+
return r.singleNodeValue !== null;
|
|
83
|
+
})()`;
|
|
84
|
+
await waitForCondition(view, xpathExpr, Math.min(timeout, 10000));
|
|
85
|
+
} else {
|
|
86
|
+
await waitForSelector(view, actualSelector, Math.min(timeout, 10000));
|
|
87
|
+
}
|
|
88
|
+
} catch {
|
|
89
|
+
log.warn(`Selector "${actualSelector}" not found within timeout — attempting extraction anyway`);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
const extracted = await view.evaluate(`
|
|
93
|
+
(() => {
|
|
94
|
+
const isXPath = ${JSON.stringify(isXPath)};
|
|
95
|
+
const sel = ${JSON.stringify(actualSelector)};
|
|
96
|
+
const attr = ${JSON.stringify(attribute)};
|
|
97
|
+
const all = ${JSON.stringify(all)};
|
|
98
|
+
const elements = [];
|
|
99
|
+
|
|
100
|
+
if (isXPath) {
|
|
101
|
+
const result = document.evaluate(sel, document, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
|
|
102
|
+
for (let i = 0; i < result.snapshotLength; i++) {
|
|
103
|
+
const node = result.snapshotItem(i);
|
|
104
|
+
if (node.nodeType === Node.ELEMENT_NODE) elements.push(node);
|
|
105
|
+
}
|
|
106
|
+
} else {
|
|
107
|
+
document.querySelectorAll(sel).forEach(el => elements.push(el));
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
if (!all && elements.length > 0) elements.length = 1;
|
|
111
|
+
|
|
112
|
+
return elements.map(el => {
|
|
113
|
+
if (attr === "text") return (el.textContent || "").trim();
|
|
114
|
+
if (attr === "innerHTML") return el.innerHTML;
|
|
115
|
+
return el.getAttribute(attr) || "";
|
|
116
|
+
});
|
|
117
|
+
})()
|
|
118
|
+
`) as string[];
|
|
119
|
+
|
|
120
|
+
const currentUrl = view.url;
|
|
121
|
+
log.info(`Extracted ${extracted.length} element(s) from ${currentUrl}`);
|
|
122
|
+
|
|
123
|
+
return {
|
|
124
|
+
ok: true,
|
|
125
|
+
url: currentUrl,
|
|
126
|
+
selector,
|
|
127
|
+
attribute,
|
|
128
|
+
count: extracted.length,
|
|
129
|
+
data: extracted,
|
|
130
|
+
};
|
|
131
|
+
} catch (error) {
|
|
132
|
+
log.error(`Extraction failed: ${(error as Error).message}`);
|
|
133
|
+
return {
|
|
134
|
+
ok: false,
|
|
135
|
+
error: `Failed to extract: ${(error as Error).message}`,
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
},
|
|
139
|
+
};
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* browser_navigate - Navigate to URL and get rendered content
|
|
3
|
+
*
|
|
4
|
+
* @category web
|
|
5
|
+
* @seedId browser_navigate
|
|
6
|
+
* @spanish navegar a url, abrir página, sitio web
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import type { Tool } from "../types.ts";
|
|
10
|
+
import { logger } from "../../utils/logger.ts";
|
|
11
|
+
import { getBrowserService, waitForSelector } from "./browser-service.ts";
|
|
12
|
+
|
|
13
|
+
const log = logger.child("browser-navigate");
|
|
14
|
+
|
|
15
|
+
export const browserNavigateTool: Tool = {
|
|
16
|
+
name: "browser_navigate",
|
|
17
|
+
description: "Navigate browser to URL, get rendered page content (supports JS). Spanish: navegar a url, abrir página, sitio web",
|
|
18
|
+
parameters: {
|
|
19
|
+
type: "object",
|
|
20
|
+
properties: {
|
|
21
|
+
url: {
|
|
22
|
+
type: "string",
|
|
23
|
+
description: "The URL to navigate to",
|
|
24
|
+
},
|
|
25
|
+
waitFor: {
|
|
26
|
+
type: "string",
|
|
27
|
+
description: "CSS selector to wait for before returning (optional)",
|
|
28
|
+
},
|
|
29
|
+
timeout: {
|
|
30
|
+
type: "number",
|
|
31
|
+
description: "Timeout in milliseconds (default: 30000)",
|
|
32
|
+
},
|
|
33
|
+
},
|
|
34
|
+
required: ["url"],
|
|
35
|
+
},
|
|
36
|
+
execute: async (params: Record<string, unknown>) => {
|
|
37
|
+
const url = params.url as string;
|
|
38
|
+
const waitFor = params.waitFor as string | undefined;
|
|
39
|
+
const timeout = (params.timeout as number) ?? 30000;
|
|
40
|
+
|
|
41
|
+
const browserService = getBrowserService();
|
|
42
|
+
if (!browserService?.isAvailable()) {
|
|
43
|
+
log.warn("Browser not available");
|
|
44
|
+
return {
|
|
45
|
+
ok: false,
|
|
46
|
+
error: "Browser automation not available. Install Chrome/Chromium.",
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
log.info(`Navigating: ${url}${waitFor ? ` (waiting for: ${waitFor})` : ""}`);
|
|
51
|
+
|
|
52
|
+
try {
|
|
53
|
+
const view = await browserService.getView();
|
|
54
|
+
if (!view) return { ok: false, error: "Browser automation not available. Install Chrome/Chromium." };
|
|
55
|
+
|
|
56
|
+
await view.navigate(url);
|
|
57
|
+
|
|
58
|
+
// Esperar a que JS termine de ejecutar
|
|
59
|
+
await Bun.sleep(500);
|
|
60
|
+
|
|
61
|
+
if (waitFor) {
|
|
62
|
+
try {
|
|
63
|
+
await waitForSelector(view, waitFor, timeout);
|
|
64
|
+
} catch {
|
|
65
|
+
log.warn(`Selector "${waitFor}" not found within timeout`);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
const finalUrl = view.url;
|
|
70
|
+
|
|
71
|
+
// Extraer texto limpio del DOM
|
|
72
|
+
const content = await view.evaluate(`
|
|
73
|
+
(() => {
|
|
74
|
+
try {
|
|
75
|
+
document.querySelectorAll("script, style, noscript, meta, link, iframe").forEach(el => el.remove());
|
|
76
|
+
let text = document.body?.innerText || document.documentElement?.innerText || "";
|
|
77
|
+
text = text.replace(/\\s+/g, " ").trim();
|
|
78
|
+
return text.slice(0, 50000);
|
|
79
|
+
} catch (e) {
|
|
80
|
+
return "Error extracting content: " + e.message;
|
|
81
|
+
}
|
|
82
|
+
})()
|
|
83
|
+
`) as string;
|
|
84
|
+
|
|
85
|
+
log.info(`Navigation successful: ${finalUrl} (${content.length} chars)`);
|
|
86
|
+
|
|
87
|
+
return {
|
|
88
|
+
ok: true,
|
|
89
|
+
url,
|
|
90
|
+
finalUrl,
|
|
91
|
+
content,
|
|
92
|
+
length: content.length,
|
|
93
|
+
};
|
|
94
|
+
} catch (error) {
|
|
95
|
+
const msg = (error as Error).message;
|
|
96
|
+
|
|
97
|
+
if (msg.includes("timeout")) {
|
|
98
|
+
log.error(`Navigation timeout: ${url}`);
|
|
99
|
+
return { ok: false, error: `Timeout (${timeout}ms): la página tardó demasiado.` };
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
log.error(`Navigation failed: ${msg}`);
|
|
103
|
+
return { ok: false, error: `Failed to navigate: ${msg}` };
|
|
104
|
+
}
|
|
105
|
+
},
|
|
106
|
+
};
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* browser_screenshot - Take screenshot of current browser page
|
|
3
|
+
*
|
|
4
|
+
* @category web
|
|
5
|
+
* @seedId browser_screenshot
|
|
6
|
+
* @spanish captura de pantalla, screenshot, imagen de página
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import type { Tool } from "../types.ts";
|
|
10
|
+
import { logger } from "../../utils/logger.ts";
|
|
11
|
+
import { getBrowserService, screenshotElement } from "./browser-service.ts";
|
|
12
|
+
|
|
13
|
+
const log = logger.child("browser-screenshot");
|
|
14
|
+
|
|
15
|
+
export const browserScreenshotTool: Tool = {
|
|
16
|
+
name: "browser_screenshot",
|
|
17
|
+
description: "Take screenshot of current browser page. Spanish: captura de pantalla, screenshot, imagen de página",
|
|
18
|
+
parameters: {
|
|
19
|
+
type: "object",
|
|
20
|
+
properties: {
|
|
21
|
+
url: {
|
|
22
|
+
type: "string",
|
|
23
|
+
description: "URL to navigate to before screenshot (optional)",
|
|
24
|
+
},
|
|
25
|
+
fullPage: {
|
|
26
|
+
type: "boolean",
|
|
27
|
+
description: "Capture full page height (default: false)",
|
|
28
|
+
},
|
|
29
|
+
selector: {
|
|
30
|
+
type: "string",
|
|
31
|
+
description: "CSS selector of specific element to screenshot (optional)",
|
|
32
|
+
},
|
|
33
|
+
},
|
|
34
|
+
required: [],
|
|
35
|
+
},
|
|
36
|
+
execute: async (params: Record<string, unknown>) => {
|
|
37
|
+
const url = params.url as string | undefined;
|
|
38
|
+
const fullPage = (params.fullPage as boolean) ?? false;
|
|
39
|
+
const selector = params.selector as string | undefined;
|
|
40
|
+
|
|
41
|
+
const browserService = getBrowserService();
|
|
42
|
+
if (!browserService?.isAvailable()) {
|
|
43
|
+
log.warn("Browser not available");
|
|
44
|
+
return {
|
|
45
|
+
ok: false,
|
|
46
|
+
error: "Browser automation not available. Install Chrome/Chromium.",
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
log.info(`Taking screenshot${url ? ` of: ${url}` : ""}${selector ? ` (element: ${selector})` : ""}`);
|
|
51
|
+
|
|
52
|
+
try {
|
|
53
|
+
const view = await browserService.getView();
|
|
54
|
+
if (!view) return { ok: false, error: "Browser automation not available. Install Chrome/Chromium." };
|
|
55
|
+
|
|
56
|
+
if (url) {
|
|
57
|
+
await view.navigate(url);
|
|
58
|
+
await Bun.sleep(500);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
let screenshot: string;
|
|
62
|
+
|
|
63
|
+
if (selector) {
|
|
64
|
+
screenshot = await screenshotElement(view, selector);
|
|
65
|
+
} else {
|
|
66
|
+
screenshot = await view.screenshot({ encoding: "base64", format: "png" });
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
const currentUrl = view.url;
|
|
70
|
+
log.info(`Screenshot captured: ${currentUrl} (${screenshot.length} base64 chars)`);
|
|
71
|
+
|
|
72
|
+
return {
|
|
73
|
+
ok: true,
|
|
74
|
+
url: currentUrl,
|
|
75
|
+
screenshot,
|
|
76
|
+
format: "png",
|
|
77
|
+
encoding: "base64",
|
|
78
|
+
fullPage,
|
|
79
|
+
selector,
|
|
80
|
+
viewport: { width: 1280, height: 800 },
|
|
81
|
+
};
|
|
82
|
+
} catch (error) {
|
|
83
|
+
log.error(`Screenshot failed: ${(error as Error).message}`);
|
|
84
|
+
return { ok: false, error: `Failed to take screenshot: ${(error as Error).message}` };
|
|
85
|
+
}
|
|
86
|
+
},
|
|
87
|
+
};
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* browser_script - Execute arbitrary JavaScript in page context
|
|
3
|
+
*
|
|
4
|
+
* @category web
|
|
5
|
+
* @seedId browser_script
|
|
6
|
+
* @spanish ejecutar javascript, script, código, función, evaluar
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import type { Tool } from "../types.ts";
|
|
10
|
+
import { logger } from "../../utils/logger.ts";
|
|
11
|
+
import { getBrowserService } from "./browser-service.ts";
|
|
12
|
+
|
|
13
|
+
const log = logger.child("browser-script");
|
|
14
|
+
|
|
15
|
+
export const browserScriptTool: Tool = {
|
|
16
|
+
name: "browser_script",
|
|
17
|
+
description: "Execute arbitrary JavaScript in the browser page context and get the result. Spanish: ejecutar javascript, script, código, función, evaluar",
|
|
18
|
+
parameters: {
|
|
19
|
+
type: "object",
|
|
20
|
+
properties: {
|
|
21
|
+
url: {
|
|
22
|
+
type: "string",
|
|
23
|
+
description: "URL to navigate to before executing (optional)",
|
|
24
|
+
},
|
|
25
|
+
script: {
|
|
26
|
+
type: "string",
|
|
27
|
+
description: "JavaScript code to execute in page context",
|
|
28
|
+
},
|
|
29
|
+
timeout: {
|
|
30
|
+
type: "number",
|
|
31
|
+
description: "Timeout in milliseconds (default: 30000)",
|
|
32
|
+
},
|
|
33
|
+
},
|
|
34
|
+
required: ["script"],
|
|
35
|
+
},
|
|
36
|
+
execute: async (params: Record<string, unknown>) => {
|
|
37
|
+
const url = params.url as string | undefined;
|
|
38
|
+
const script = params.script as string;
|
|
39
|
+
const timeout = (params.timeout as number) ?? 30000;
|
|
40
|
+
|
|
41
|
+
const browserService = getBrowserService();
|
|
42
|
+
if (!browserService?.isAvailable()) {
|
|
43
|
+
log.warn("Browser not available");
|
|
44
|
+
return {
|
|
45
|
+
ok: false,
|
|
46
|
+
error: "Browser automation not available. Install Chrome/Chromium.",
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
log.info(`Executing script${url ? ` on ${url}` : ""} (${script.length} chars)`);
|
|
51
|
+
|
|
52
|
+
try {
|
|
53
|
+
const view = await browserService.getView();
|
|
54
|
+
if (!view) return { ok: false, error: "Browser automation not available. Install Chrome/Chromium." };
|
|
55
|
+
|
|
56
|
+
if (url) {
|
|
57
|
+
await view.navigate(url);
|
|
58
|
+
await Bun.sleep(500);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
const wrappedScript = `(async () => { try { return await (async () => { ${script} })(); } catch(e) { throw new Error('Script error: ' + e.message); } })()`;
|
|
62
|
+
const result = await view.evaluate(wrappedScript);
|
|
63
|
+
|
|
64
|
+
const currentUrl = view.url;
|
|
65
|
+
log.info(`Script executed successfully on ${currentUrl}`);
|
|
66
|
+
|
|
67
|
+
let serializedResult;
|
|
68
|
+
try {
|
|
69
|
+
serializedResult = JSON.parse(JSON.stringify(result));
|
|
70
|
+
} catch {
|
|
71
|
+
serializedResult = String(result);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
return {
|
|
75
|
+
ok: true,
|
|
76
|
+
url: currentUrl,
|
|
77
|
+
result: serializedResult,
|
|
78
|
+
scriptLength: script.length,
|
|
79
|
+
};
|
|
80
|
+
} catch (error) {
|
|
81
|
+
log.error(`Script execution failed: ${(error as Error).message}`);
|
|
82
|
+
return {
|
|
83
|
+
ok: false,
|
|
84
|
+
error: `Failed to execute script: ${(error as Error).message}`,
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
},
|
|
88
|
+
};
|