From 24309a822aa56e624f280a095b9d92d32f8c18bb Mon Sep 17 00:00:00 2001 From: Joel Kronqvist Date: Sun, 11 Oct 2026 23:26:03 +0300 Subject: feat: webgrep --- actions.py | 61 ++++++++++++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 50 insertions(+), 11 deletions(-) (limited to 'actions.py') diff --git a/actions.py b/actions.py index 589dd51..a6051ed 100644 --- a/actions.py +++ b/actions.py @@ -2,7 +2,9 @@ from pathlib import Path from typing import Optional, Callable, Dict from dataclasses import dataclass import subprocess +import re from llm import AgentConfig, JSON +from web_utils import fetch_and_markdownify, FetchSuccess, FetchError @dataclass @@ -108,16 +110,42 @@ def _shell(args: JSON, config: AgentConfig) -> JSON: def _mypy(args: JSON, config: AgentConfig) -> JSON: '{"action": "mypy", "path": PATH} - run mypy type checking on PATH' - try: - res = subprocess.run( - ["mypy", args["path"]], - cwd=config.workdir, - capture_output=True, - text=True, - ) - return {"status": "success", "stdout": res.stdout, "stderr": res.stderr} - except Exception as e: - return {"status": "error", "reason": f"An unexpected error occurred: {e}"} + + def inner(path: Path): + try: + res = subprocess.run( + ["mypy", str(path)], cwd=config.workdir, capture_output=True, text=True + ) + if res.returncode == 0: + return {"status": "success", "stdout": res.stdout} + else: + return {"status": "error", "stderr": res.stderr} + except Exception as e: + return {"status": "error", "reason": f"An unexpected error occurred: {e}"} + + return _path_helper(args["path"], inner, cwd=config.workdir) + + +def _webgrep(args: JSON, config: AgentConfig) -> JSON: + '{"action": "webgrep", "url": URL, "keywords": KEYWORD_LIST} - find case-insensitive matches in markdownified content of URL for keywords in KEYWORD_LIST plus some context on both sides' + + match fetch_and_markdownify(args["url"]): + case FetchError(e): + return {"status": "error", "reason": e} + case FetchSuccess(content): + matches = map( + lambda m: content[ + max(0, m.start() - config.search_padding) : min( + len(content), m.end() + config.search_padding + ) + ], + re.finditer( + "|".join(map(lambda kw: re.escape(kw), args["keywords"])), + content, + re.IGNORECASE, + ), + ) + return {"status": "success", "matches": list(matches)} ls = Action("ls", _ls.__doc__ or "", _ls) @@ -135,4 +163,15 @@ shell = Action( _shell, formatter=lambda args: f"shell command `{args['command']}`", ) -mypy = Action("mypy", _mypy.__doc__ or "", _mypy) +mypy = Action( + "mypy", + _mypy.__doc__ or "", + _mypy, + formatter=lambda args: f"type check {args['path']}", +) +webgrep = Action( + "webgrep", + _webgrep.__doc__ or "", + _webgrep, + formatter=lambda args: f"search {args['url']}", +) -- cgit v1.3.1