4b6817381b
CI (OpenClaw E2E) / openclaw test (push) Has been cancelled
CI / coverage-report (push) Has been cancelled
CI / test-kubernetes (push) Has been cancelled
CI / should-run-thorough (push) Has been cancelled
CI / test-thorough (cloudwatch-demo) (push) Has been cancelled
CI / test-thorough (flink-ecs) (push) Has been cancelled
CI / test-thorough (upstream-lambda) (push) Has been cancelled
CI / test-thorough (prefect-ecs-fargate) (push) Has been cancelled
Release / build-binaries (zip, opensre.exe, onefile, windows-latest, windows-x64) (push) Has been cancelled
Benchmark image — build + push to ECR (any adapter) / build + push (push) Has been cancelled
CI / quality (ubuntu-latest) (push) Has been cancelled
CI / test (tools-runtime) (push) Has been cancelled
CI / test (e2e-general) (push) Has been cancelled
CI / test (cli-runtime) (push) Has been cancelled
CI / test (e2e-provider-and-openclaw) (push) Has been cancelled
CI / test (integrations-and-misc) (push) Has been cancelled
Release / verify (push) Has been cancelled
Release / build-python-dist (push) Has been cancelled
Release / build-binaries (tar.gz, opensre, onedir, macos-15-intel, darwin-x64) (push) Has been cancelled
Release / build-binaries (tar.gz, opensre, onedir, macos-latest, darwin-arm64) (push) Has been cancelled
Release / build-binaries (tar.gz, opensre, onedir, ubuntu-22.04, linux-x64) (push) Has been cancelled
Release / publish-release (push) Has been cancelled
Release / publish-main-release (push) Has been cancelled
Interactive Shell Live (PR + post-merge) / turn-checks (no-LLM) (push) Has been cancelled
CodeQL / Analyze (python) (push) Has been cancelled
Interactive Shell Live (PR + post-merge) / turn-live shard ${{ matrix.shard_index }} (push) Has been cancelled
Release / prepare (push) Has been cancelled
Release / build-binaries (tar.gz, opensre, onedir, ubuntu-22.04-arm, linux-arm64) (push) Has been cancelled
Synthetic Deterministic Tests / Synthetic offline (deterministic) (push) Has been cancelled
140 lines
5.4 KiB
Python
140 lines
5.4 KiB
Python
"""Action tool: dispatch a natural-language "fix this Sentry issue" request.
|
|
|
|
This is the intake-routing half of the Sentry issue-fix flow. It exposes the
|
|
``fix_sentry_issue`` capability to the interactive-shell **action agent** as a
|
|
proper AgentTool, so a request like *"fix this Sentry issue <url> and open a
|
|
PR"* is dispatched by the action LLM (semantic intent) rather than by any
|
|
regex/keyword shortcut. The tool is only offered when the fix capability is
|
|
opted in (``PI_ISSUE_FIX_ENABLED``); the PR-shipping gate + token check stay
|
|
inside ``fix_sentry_issue`` itself.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
from typing import Any
|
|
|
|
from core.agent_harness.tools.tool_context import (
|
|
ActionToolContext,
|
|
execute_with_action_context,
|
|
object_schema,
|
|
string_property,
|
|
)
|
|
from core.tool_framework.registered_tool import RegisteredTool
|
|
from tools.cross_vendor.fix_sentry_issue import fix_sentry_issue
|
|
from tools.cross_vendor.fix_sentry_issue.runner import is_issue_fix_enabled
|
|
|
|
|
|
def _render_result(console: Any, out: dict[str, Any]) -> None:
|
|
"""Print a concise, human-readable summary of the tool result."""
|
|
if not out.get("success"):
|
|
console.print(
|
|
f"[red]Could not fix the Sentry issue[/] "
|
|
f"({out.get('error_kind') or 'error'}): {out.get('error') or ''}"
|
|
)
|
|
# Point the user at their fix so they can recover manually, with guidance
|
|
# matched to how far shipping got on the new branch:
|
|
# commit_failed -> on the branch but NOT committed (edits staged only)
|
|
# push_failed -> committed but not pushed
|
|
# pr_failed -> pushed, only the PR call failed
|
|
branch = out.get("branch_name")
|
|
if branch:
|
|
kind = out.get("error_kind")
|
|
if kind == "commit_failed":
|
|
console.print(
|
|
f"[dim]Your changes are on branch [cyan]{branch}[/] but not committed — "
|
|
"commit them, push, and open the PR manually.[/]"
|
|
)
|
|
elif kind == "pr_failed":
|
|
console.print(
|
|
f"[dim]Your fix is pushed to branch [cyan]{branch}[/] — "
|
|
"open the PR manually.[/]"
|
|
)
|
|
else:
|
|
console.print(
|
|
f"[dim]Your fix is committed on branch [cyan]{branch}[/] — "
|
|
"push it and open the PR manually.[/]"
|
|
)
|
|
elif out.get("changed_files"):
|
|
console.print("[dim]The proposed fix is still in your working tree.[/]")
|
|
return
|
|
|
|
console.print(f"[green]Fixed Sentry issue {out.get('issue_id')}[/].")
|
|
if out.get("summary"):
|
|
console.print(str(out["summary"]))
|
|
for path in out.get("changed_files") or []:
|
|
console.print(f" • {path}")
|
|
if out.get("pr_url"):
|
|
console.print(
|
|
f"[bold]Opened pull request:[/] {out['pr_url']} "
|
|
f"(branch [cyan]{out.get('branch_name')}[/])"
|
|
)
|
|
else:
|
|
console.print("[dim]Diff left in your working tree (no PR requested).[/]")
|
|
|
|
|
|
def execute_sentry_fix_tool(args: dict[str, Any], ctx: ActionToolContext) -> bool:
|
|
sentry_url = str(args.get("sentry_url", "")).strip()
|
|
if not sentry_url:
|
|
return False
|
|
open_pr = bool(args.get("open_pr", False))
|
|
|
|
ctx.console.print(
|
|
f"[bold]Fixing Sentry issue[/] {sentry_url}"
|
|
+ (" and opening a pull request…" if open_pr else "…")
|
|
)
|
|
out = fix_sentry_issue.run(sentry_url=sentry_url, open_pr=open_pr)
|
|
_render_result(ctx.console, out)
|
|
return True
|
|
|
|
|
|
def run_sentry_fix(*, sentry_url: str, context: Any, open_pr: bool = False) -> dict[str, Any]:
|
|
return execute_with_action_context(
|
|
{"sentry_url": sentry_url, "open_pr": open_pr},
|
|
context,
|
|
execute_sentry_fix_tool,
|
|
)
|
|
|
|
|
|
fix_sentry_issue_start_tool = RegisteredTool(
|
|
name="fix_sentry_issue_start",
|
|
description=(
|
|
"Fix a Sentry issue in code with a coding agent, given a Sentry issue URL. "
|
|
"Use whenever the user asks to FIX, patch, resolve in code, or open/raise a pull "
|
|
"request for a Sentry issue and provides a Sentry issue URL — e.g. 'fix this sentry "
|
|
"issue <url>' or 'fix <url> and open a PR'. Set open_pr=true when they ask to "
|
|
"open/create/raise a PR or to ship the fix; otherwise false to only produce a diff. "
|
|
"Do NOT use for investigate/RCA/diagnose/analyze requests (use investigation_start), "
|
|
"for non-Sentry URLs, or when no Sentry issue URL is provided."
|
|
),
|
|
input_schema=object_schema(
|
|
properties={
|
|
"sentry_url": string_property(
|
|
description="The Sentry issue URL to fix (e.g. https://<org>.sentry.io/issues/<id>/).",
|
|
min_length=1,
|
|
),
|
|
"open_pr": {
|
|
"type": "boolean",
|
|
"description": (
|
|
"True when the user asks to open/create/raise a pull request or to ship "
|
|
"the fix; false to only produce a reviewable diff."
|
|
),
|
|
},
|
|
},
|
|
required=("sentry_url",),
|
|
),
|
|
source="interactive_shell",
|
|
surfaces=("action",),
|
|
side_effect_level="mutating",
|
|
parallel_safe=False,
|
|
accepts_runtime_context=True,
|
|
is_available=lambda _sources: is_issue_fix_enabled(),
|
|
run=run_sentry_fix,
|
|
)
|
|
|
|
|
|
__all__ = [
|
|
"execute_sentry_fix_tool",
|
|
"fix_sentry_issue_start_tool",
|
|
"run_sentry_fix",
|
|
]
|