0agent 1.0.9 → 1.0.11

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 (2) hide show
  1. package/dist/daemon.mjs +125 -0
  2. package/package.json +1 -1
package/dist/daemon.mjs CHANGED
@@ -1736,6 +1736,32 @@ var AGENT_TOOLS = [
1736
1736
  path: { type: "string", description: 'Directory path relative to working directory (default: ".")' }
1737
1737
  }
1738
1738
  }
1739
+ },
1740
+ {
1741
+ name: "web_search",
1742
+ description: "Search the web and return titles, URLs, and snippets. No API key needed. Use this first to find relevant pages, then scrape_url for full content.",
1743
+ input_schema: {
1744
+ type: "object",
1745
+ properties: {
1746
+ query: { type: "string", description: "Search query" },
1747
+ num_results: { type: "number", description: "Number of results (default 5, max 10)" }
1748
+ },
1749
+ required: ["query"]
1750
+ }
1751
+ },
1752
+ {
1753
+ name: "scrape_url",
1754
+ description: "Scrape a URL and return clean structured content. Handles JavaScript-rendered pages, auto-adapts to page structure, returns text/links/metadata. Better than shell curl for web pages.",
1755
+ input_schema: {
1756
+ type: "object",
1757
+ properties: {
1758
+ url: { type: "string", description: "URL to scrape" },
1759
+ mode: { type: "string", description: 'What to extract: "text" (default), "links", "tables", "full", "markdown"' },
1760
+ selector: { type: "string", description: "Optional CSS selector to target specific element" },
1761
+ wait_ms: { type: "number", description: "Wait N ms after page load (for JS-heavy pages, default 0)" }
1762
+ },
1763
+ required: ["url"]
1764
+ }
1739
1765
  }
1740
1766
  ];
1741
1767
  var LLMExecutor = class {
@@ -2135,6 +2161,18 @@ var AgentExecutor = class {
2135
2161
  return this.readFile(String(input.path ?? ""));
2136
2162
  case "list_dir":
2137
2163
  return this.listDir(input.path ? String(input.path) : void 0);
2164
+ case "web_search":
2165
+ return this.webSearch(
2166
+ String(input.query ?? ""),
2167
+ Math.min(10, Number(input.num_results ?? 5))
2168
+ );
2169
+ case "scrape_url":
2170
+ return this.scrapeUrl(
2171
+ String(input.url ?? ""),
2172
+ String(input.mode ?? "text"),
2173
+ input.selector ? String(input.selector) : void 0,
2174
+ Number(input.wait_ms ?? 0)
2175
+ );
2138
2176
  default:
2139
2177
  return `Unknown tool: ${name}`;
2140
2178
  }
@@ -2174,6 +2212,90 @@ var AgentExecutor = class {
2174
2212
  return content.length > 8e3 ? content.slice(0, 8e3) + `
2175
2213
  \u2026[truncated, ${content.length} total bytes]` : content;
2176
2214
  }
2215
+ async webSearch(query, numResults) {
2216
+ const url = `https://html.duckduckgo.com/html/?q=${encodeURIComponent(query)}&kl=us-en`;
2217
+ let html = "";
2218
+ try {
2219
+ const res = await fetch(url, {
2220
+ headers: {
2221
+ "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0 Safari/537.36",
2222
+ "Accept": "text/html,application/xhtml+xml",
2223
+ "Accept-Language": "en-US,en;q=0.9"
2224
+ },
2225
+ signal: AbortSignal.timeout(12e3)
2226
+ });
2227
+ html = await res.text();
2228
+ } catch (err) {
2229
+ return `Search request failed: ${err instanceof Error ? err.message : String(err)}`;
2230
+ }
2231
+ const results = [];
2232
+ const titleRe = /<a[^>]+class="result__a"[^>]+href="([^"]*)"[^>]*>([\s\S]*?)<\/a>/g;
2233
+ const snippetRe = /<a[^>]+class="result__snippet"[^>]*>([\s\S]*?)<\/a>/g;
2234
+ const titles = [];
2235
+ const snippets = [];
2236
+ let m;
2237
+ while ((m = titleRe.exec(html)) !== null) {
2238
+ let href = m[1];
2239
+ const title = m[2].replace(/<[^>]+>/g, "").replace(/&amp;/g, "&").replace(/&lt;/g, "<").replace(/&gt;/g, ">").trim();
2240
+ const uddg = href.match(/[?&]uddg=([^&]+)/);
2241
+ if (uddg) href = decodeURIComponent(uddg[1]);
2242
+ if (href.startsWith("http") && title && titles.length < numResults) {
2243
+ titles.push({ url: href, title });
2244
+ }
2245
+ }
2246
+ while ((m = snippetRe.exec(html)) !== null && snippets.length < numResults) {
2247
+ snippets.push(m[1].replace(/<[^>]+>/g, "").replace(/\s+/g, " ").trim());
2248
+ }
2249
+ if (titles.length === 0) {
2250
+ const plainText = html.replace(/<[^>]+>/g, " ").replace(/\s+/g, " ").slice(0, 1500);
2251
+ return `No results parsed. Raw content:
2252
+ ${plainText}`;
2253
+ }
2254
+ return titles.map(
2255
+ (t, i) => `${i + 1}. ${t.title}
2256
+ URL: ${t.url}${snippets[i] ? `
2257
+ ${snippets[i]}` : ""}`
2258
+ ).join("\n\n");
2259
+ }
2260
+ async scrapeUrl(url, mode, selector, waitMs) {
2261
+ if (!url.startsWith("http")) return "Error: URL must start with http:// or https://";
2262
+ const selectorLine = selector ? `element = page.find('${selector}')
2263
+ content = element.text if element else page.get_all_text()` : `content = page.get_all_text()`;
2264
+ const modeLine = mode === "links" ? `result = [a.attrib.get('href','') for a in page.find_all('a') if a.attrib.get('href','').startswith('http')]` : mode === "tables" ? `result = [str(t) for t in page.find_all('table')]` : mode === "markdown" ? `result = page.get_all_text()` : `result = page.get_all_text()`;
2265
+ const script = [
2266
+ `import sys`,
2267
+ `try:`,
2268
+ ` from scrapling import Fetcher`,
2269
+ `except ImportError:`,
2270
+ ` import subprocess, sys`,
2271
+ ` subprocess.run([sys.executable, '-m', 'pip', 'install', 'scrapling', '-q'], check=True)`,
2272
+ ` from scrapling import Fetcher`,
2273
+ `try:`,
2274
+ ` fetcher = Fetcher(auto_match=False)`,
2275
+ ` page = fetcher.get('${url}', timeout=20)`,
2276
+ ` ${modeLine}`,
2277
+ ` if isinstance(result, list):`,
2278
+ ` print('\\n'.join(str(r) for r in result[:50]))`,
2279
+ ` else:`,
2280
+ ` text = str(result).strip()`,
2281
+ ` print(text[:6000] + ('...[truncated]' if len(text)>6000 else ''))`,
2282
+ `except Exception as e:`,
2283
+ ` # Fallback to simple fetch if scrapling fails`,
2284
+ ` import urllib.request`,
2285
+ ` try:`,
2286
+ ` req = urllib.request.Request('${url}', headers={'User-Agent': 'Mozilla/5.0'})`,
2287
+ ` with urllib.request.urlopen(req, timeout=15) as resp:`,
2288
+ ` body = resp.read().decode('utf-8', errors='ignore')`,
2289
+ ` # Strip tags simply`,
2290
+ ` import re`,
2291
+ ` text = re.sub(r'<[^>]+>', ' ', body)`,
2292
+ ` text = re.sub(r'\\s+', ' ', text).strip()`,
2293
+ ` print(text[:5000])`,
2294
+ ` except Exception as e2:`,
2295
+ ` print(f'Scrape failed: {e} / {e2}', file=sys.stderr)`
2296
+ ].join("\n");
2297
+ return this.shellExec(`python3 -c "${script.replace(/"/g, '\\"').replace(/\n/g, ";")}"`, 3e4);
2298
+ }
2177
2299
  listDir(dirPath) {
2178
2300
  const safe = this.safePath(dirPath ?? ".");
2179
2301
  if (!safe) return "Error: path outside working directory";
@@ -2201,6 +2323,7 @@ var AgentExecutor = class {
2201
2323
  `- For npm/node projects: check package.json first with read_file or list_dir`,
2202
2324
  `- After write_file, verify with read_file if needed`,
2203
2325
  `- After shell_exec, check output for errors and retry if needed`,
2326
+ `- For research tasks: use web_search first, then scrape_url for full page content`,
2204
2327
  `- Use relative paths from the working directory`,
2205
2328
  `- Be concise in your final response: state what was done and where to find it`
2206
2329
  ];
@@ -2212,6 +2335,8 @@ var AgentExecutor = class {
2212
2335
  if (toolName === "write_file") return `"${input.path}"`;
2213
2336
  if (toolName === "read_file") return `"${input.path}"`;
2214
2337
  if (toolName === "list_dir") return `"${input.path ?? "."}"`;
2338
+ if (toolName === "web_search") return `"${String(input.query ?? "").slice(0, 60)}"`;
2339
+ if (toolName === "scrape_url") return `"${String(input.url ?? "").slice(0, 60)}" mode=${input.mode ?? "text"}`;
2215
2340
  return JSON.stringify(input).slice(0, 60);
2216
2341
  }
2217
2342
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "0agent",
3
- "version": "1.0.9",
3
+ "version": "1.0.11",
4
4
  "description": "A persistent, learning AI agent that runs on your machine. An agent that learns.",
5
5
  "private": false,
6
6
  "license": "Apache-2.0",