feat: generate improvement proposals
This commit is contained in:
@@ -2,8 +2,8 @@
|
|||||||
"schema_version": "2026-06-04",
|
"schema_version": "2026-06-04",
|
||||||
"language": "python",
|
"language": "python",
|
||||||
"name": "agent-reviewer",
|
"name": "agent-reviewer",
|
||||||
"description": "Audit an A2A agent's source before deploy. Reads the target repo from Gitea, applies security / best-practice / grant-scope skill bundles, and returns a structured ReviewReport.",
|
"description": "Pre-deploy audit of an A2A agent's source — security, scope, ergonomics.",
|
||||||
"version": "0.1.1",
|
"version": "0.1.2",
|
||||||
"entrypoint": {
|
"entrypoint": {
|
||||||
"module": "agent",
|
"module": "agent",
|
||||||
"class_name": "AgentReviewer",
|
"class_name": "AgentReviewer",
|
||||||
@@ -56,6 +56,9 @@
|
|||||||
"type": "null"
|
"type": "null"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
},
|
||||||
|
"mode": {
|
||||||
|
"type": "string"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"required": [
|
"required": [
|
||||||
@@ -83,6 +86,7 @@
|
|||||||
},
|
},
|
||||||
"runtime": {
|
"runtime": {
|
||||||
"lifecycle": "ephemeral",
|
"lifecycle": "ephemeral",
|
||||||
|
"availability": "on_demand",
|
||||||
"state": "none",
|
"state": "none",
|
||||||
"sandbox": "microsandbox",
|
"sandbox": "microsandbox",
|
||||||
"resources": {
|
"resources": {
|
||||||
@@ -115,6 +119,7 @@
|
|||||||
"memory": null,
|
"memory": null,
|
||||||
"databases": []
|
"databases": []
|
||||||
},
|
},
|
||||||
|
"endpoints": [],
|
||||||
"apt_packages": []
|
"apt_packages": []
|
||||||
},
|
},
|
||||||
"template_lineage": null,
|
"template_lineage": null,
|
||||||
@@ -151,7 +156,7 @@
|
|||||||
"source": "python-a2a-pack",
|
"source": "python-a2a-pack",
|
||||||
"project_manifest": {
|
"project_manifest": {
|
||||||
"name": "agent-reviewer",
|
"name": "agent-reviewer",
|
||||||
"version": "0.1.1",
|
"version": "0.1.2",
|
||||||
"entrypoint": "agent:AgentReviewer"
|
"entrypoint": "agent:AgentReviewer"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ returns a typed `ReviewReport`.
|
|||||||
## Skill: `review`
|
## Skill: `review`
|
||||||
|
|
||||||
```
|
```
|
||||||
review(agent_name: str, ref: str = "main", owner: str | None = None) -> ReviewReport
|
review(agent_name: str, ref: str = "main", owner: str | None = None, mode: str = "audit") -> ReviewReport
|
||||||
```
|
```
|
||||||
|
|
||||||
Workflow:
|
Workflow:
|
||||||
@@ -19,6 +19,10 @@ Workflow:
|
|||||||
(`a2a card`, `ruff`), produce findings.
|
(`a2a card`, `ruff`), produce findings.
|
||||||
4. Release the Gitea token in `finally`.
|
4. Release the Gitea token in `finally`.
|
||||||
|
|
||||||
|
`mode="improvements"` keeps the same read-only checks and additionally asks
|
||||||
|
for at most three source-specific robustness, test, tool-usability, or
|
||||||
|
operator-ergonomics ideas. Agent Studio uses that mode for its daily review.
|
||||||
|
|
||||||
## Output
|
## Output
|
||||||
|
|
||||||
`ReviewReport`:
|
`ReviewReport`:
|
||||||
|
|||||||
2
a2a.yaml
2
a2a.yaml
@@ -1,5 +1,5 @@
|
|||||||
name: agent-reviewer
|
name: agent-reviewer
|
||||||
version: 0.1.1
|
version: 0.1.2
|
||||||
entrypoint: agent:AgentReviewer
|
entrypoint: agent:AgentReviewer
|
||||||
description: Pre-deploy audit of an A2A agent's source — security, scope, ergonomics.
|
description: Pre-deploy audit of an A2A agent's source — security, scope, ergonomics.
|
||||||
expose:
|
expose:
|
||||||
|
|||||||
20
agent.py
20
agent.py
@@ -8,8 +8,9 @@ from typing import Any
|
|||||||
|
|
||||||
from pydantic import BaseModel
|
from pydantic import BaseModel
|
||||||
|
|
||||||
|
import a2a_pack as a2a
|
||||||
from a2a_pack import (
|
from a2a_pack import (
|
||||||
A2AAgent, LLMProvisioning, NoAuth, Pricing, RunContext, skill,
|
A2AAgent, LLMProvisioning, NoAuth, Pricing, RunContext,
|
||||||
)
|
)
|
||||||
|
|
||||||
from agent_reviewer import ReviewerContext, build_reviewer_graph
|
from agent_reviewer import ReviewerContext, build_reviewer_graph
|
||||||
@@ -30,7 +31,7 @@ class AgentReviewer(A2AAgent[ReviewerConfig, NoAuth]):
|
|||||||
"repo from Gitea, applies security / best-practice / grant-scope "
|
"repo from Gitea, applies security / best-practice / grant-scope "
|
||||||
"skill bundles, and returns a structured ReviewReport."
|
"skill bundles, and returns a structured ReviewReport."
|
||||||
)
|
)
|
||||||
version = "0.1.1"
|
version = "0.1.2"
|
||||||
|
|
||||||
config_model = ReviewerConfig
|
config_model = ReviewerConfig
|
||||||
auth_model = NoAuth
|
auth_model = NoAuth
|
||||||
@@ -46,7 +47,7 @@ class AgentReviewer(A2AAgent[ReviewerConfig, NoAuth]):
|
|||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
@skill(
|
@a2a.tool(
|
||||||
description=(
|
description=(
|
||||||
"Audit an agent's source. Pass the target ``agent_name`` "
|
"Audit an agent's source. Pass the target ``agent_name`` "
|
||||||
"(kebab-case) and optional ``ref`` (defaults to ``main``). "
|
"(kebab-case) and optional ``ref`` (defaults to ``main``). "
|
||||||
@@ -63,6 +64,7 @@ class AgentReviewer(A2AAgent[ReviewerConfig, NoAuth]):
|
|||||||
agent_name: str,
|
agent_name: str,
|
||||||
ref: str = "main",
|
ref: str = "main",
|
||||||
owner: str | None = None,
|
owner: str | None = None,
|
||||||
|
mode: str = "audit",
|
||||||
) -> dict[str, Any]:
|
) -> dict[str, Any]:
|
||||||
if not _is_valid_slug(agent_name):
|
if not _is_valid_slug(agent_name):
|
||||||
return {"error": f"invalid agent_name {agent_name!r} — use kebab-case"}
|
return {"error": f"invalid agent_name {agent_name!r} — use kebab-case"}
|
||||||
@@ -120,11 +122,21 @@ class AgentReviewer(A2AAgent[ReviewerConfig, NoAuth]):
|
|||||||
completion_box=completion_box,
|
completion_box=completion_box,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
improvement_brief = (
|
||||||
|
" This is a daily improvement-discovery review. In addition to real "
|
||||||
|
"defects, return at most three high-confidence, source-specific ideas "
|
||||||
|
"that improve robustness, test coverage, tool usability, or operator "
|
||||||
|
"ergonomics. Represent an idea as an info/ergonomics finding and put "
|
||||||
|
"the concrete implementation in suggestion. Do not invent work for a "
|
||||||
|
"clean agent."
|
||||||
|
if str(mode).strip().lower() == "improvements"
|
||||||
|
else ""
|
||||||
|
)
|
||||||
user_msg = (
|
user_msg = (
|
||||||
f"Review the agent at ``{gitea_owner}/{agent_name}`` ref ``{ref}``. "
|
f"Review the agent at ``{gitea_owner}/{agent_name}`` ref ``{ref}``. "
|
||||||
"Read the source, consult the bundled skills, run the sandbox checks, "
|
"Read the source, consult the bundled skills, run the sandbox checks, "
|
||||||
"then call ``submit_review_report`` exactly once with the structured "
|
"then call ``submit_review_report`` exactly once with the structured "
|
||||||
"report."
|
f"report.{improvement_brief}"
|
||||||
)
|
)
|
||||||
|
|
||||||
async def _heartbeat() -> None:
|
async def _heartbeat() -> None:
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ from agent_reviewer.config import load_settings # noqa: E402
|
|||||||
|
|
||||||
def test_class_metadata() -> None:
|
def test_class_metadata() -> None:
|
||||||
assert AgentReviewer.name == "agent-reviewer"
|
assert AgentReviewer.name == "agent-reviewer"
|
||||||
assert AgentReviewer.version == "0.1.1"
|
assert AgentReviewer.version == "0.1.2"
|
||||||
assert AgentReviewer.wants_cp_jwt is True
|
assert AgentReviewer.wants_cp_jwt is True
|
||||||
assert AgentReviewer.pricing.price_per_call_usd == 0.05
|
assert AgentReviewer.pricing.price_per_call_usd == 0.05
|
||||||
assert AgentReviewer.pricing.caller_pays_llm is True
|
assert AgentReviewer.pricing.caller_pays_llm is True
|
||||||
|
|||||||
Reference in New Issue
Block a user