From 604bf9d5ac13d3c54a516163e56c5afc3163c025 Mon Sep 17 00:00:00 2001 From: Kartikeya <176560021+karti-ai@users.noreply.github.com> Date: Sun, 28 Jun 2026 02:17:32 -0700 Subject: [PATCH] feat(live-conversation): add git-history tools to repo intelligence Adds repo_recent_commits (history/authorship, optional path or author) and repo_find_commits (by commit message or pickaxe code search) so the voice agent can answer who-changed-what and which-commit-introduced-X over the local karti-ai/podman checkout. Co-Authored-By: Claude Opus 4.8 --- agents/podman-live-conversation/agent.py | 88 ++++++++++++++++++++++++ 1 file changed, 88 insertions(+) diff --git a/agents/podman-live-conversation/agent.py b/agents/podman-live-conversation/agent.py index 06b2437..2ba1857 100644 --- a/agents/podman-live-conversation/agent.py +++ b/agents/podman-live-conversation/agent.py @@ -54,6 +54,8 @@ Use PodMan tools before making claims about current work, git state, collisions, team memory, or recent decisions. Keep spoken answers short. Prefer one useful next step. If a critical collision event arrives, stop the current turn and state the alert immediately. To find code, files, symbols, or how something is implemented in the repository, call search_repo. +For git commit history, authorship, recent changes, or which commit introduced something, call +repo_recent_commits or repo_find_commits. For complex repository, terminal, GitHub, MongoDB, build, install, deploy, or multi-step tasks, call delegate_to_hermes. Do not run those actions directly. If the user says stop, wait, cancel, or change of plans while Hermes is running, call abort_active_hermes_job immediately. @@ -90,6 +92,25 @@ def request_json(path: str, *, method: str = "GET", body: dict[str, Any] | None raise RuntimeError(f"PodMan backend returned {exc.code}: {detail}") from exc +async def _run_git(args: list[str], timeout: float = 15.0) -> tuple[int, str, str]: + """Run a read-only git command inside the repo checkout and capture its output.""" + try: + proc = await asyncio.create_subprocess_exec( + "git", + "-C", + REPO_ROOT, + *args, + stdout=asyncio.subprocess.PIPE, + stderr=asyncio.subprocess.PIPE, + ) + out, err = await asyncio.wait_for(proc.communicate(), timeout=timeout) + except asyncio.TimeoutError: + return 124, "", "git command timed out" + except FileNotFoundError: + return 127, "", "git is not available on this host" + return proc.returncode, out.decode("utf-8", "replace"), err.decode("utf-8", "replace") + + class PodManLiveAgent(Agent): def __init__(self, pod_id: str, identity: str, session_id: str, conversation_room: str) -> None: super().__init__(instructions=INSTRUCTIONS) @@ -212,6 +233,73 @@ class PodManLiveAgent(Agent): body = "\n".join(lines) return f'Matches for "{cleaned}" in {REPO_SLUG} (path:line):\n{body}'[:7000] + @function_tool() + async def repo_recent_commits( + self, context: RunContext, path: str = "", author: str = "", limit: int = 15 + ) -> str: + """Show recent git commit history for github.com/karti-ai/podman: who committed what and when. + Optionally scope to a file or folder (path) or filter by author name/email (author). + Use this for questions about recent changes, authorship, or a specific file's history. + """ + n = max(1, min(int(limit or 15), 50)) + args = [ + "log", + f"--max-count={n}", + "--no-color", + "--date=short", + "--pretty=format:%h | %an | %ad | %s", + ] + if author.strip(): + args.append(f"--author={author.strip()}") + if path.strip(): + args += ["--", path.strip()] + code, out, err = await _run_git(args) + if code != 0: + return f"Git history lookup failed: {err.strip()[:300] or 'unknown error'}" + out = out.strip() + if not out: + scope = f" for {path.strip()}" if path.strip() else "" + who = f" by {author.strip()}" if author.strip() else "" + return f"No commits found{scope}{who}." + return f"Recent commits in {REPO_SLUG} (hash | author | date | subject):\n{out}"[:7000] + + @function_tool() + async def repo_find_commits( + self, context: RunContext, query: str, by: str = "message", limit: int = 15 + ) -> str: + """Find commits in github.com/karti-ai/podman. by='message' searches commit messages; + by='code' finds commits that added or removed the query text in the code (pickaxe). + Use by='code' for "which commit introduced X"; use by='message' for "commits about X". + """ + cleaned = " ".join(query.split()).strip() + if not cleaned: + return "Provide a non-empty query." + n = max(1, min(int(limit or 15), 50)) + args = [ + "log", + f"--max-count={n}", + "--no-color", + "--date=short", + "--pretty=format:%h | %an | %ad | %s", + ] + mode = by.strip().lower() + if mode == "code": + args.append(f"-S{cleaned}") + else: + mode = "message" + args += ["-i", f"--grep={cleaned}"] + code, out, err = await _run_git(args) + if code != 0: + return f"Commit search failed: {err.strip()[:300] or 'unknown error'}" + out = out.strip() + if not out: + return f'No commits found matching "{cleaned}" (by {mode}).' + return ( + f'Commits in {REPO_SLUG} matching "{cleaned}" (by {mode}) — hash | author | date | subject:\n{out}'[ + :7000 + ] + ) + @function_tool() async def delegate_to_hermes( self,