Skip to content

Commit c9657b8

Browse files
authored
Merge pull request #27 from naaa760/feat/analysis-agent
feat: implement repository analysis agent with recommendation API
2 parents a518bcb + 9b4c323 commit c9657b8

24 files changed

Lines changed: 2056 additions & 5 deletions

File tree

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
rules:
2+
- description: "Block merges when PRs change filter validation logic without failing on invalid inputs"
3+
enabled: true
4+
severity: "high"
5+
event_types: ["pull_request"]
6+
parameters:
7+
file_patterns:
8+
- "packages/core/src/**/vector-query.ts"
9+
- "packages/core/src/**/graph-rag.ts"
10+
- "packages/core/src/**/filters/*.ts"
11+
require_patterns:
12+
- "throw\\s+new\\s+Error"
13+
- "raise\\s+ValueError"
14+
forbidden_patterns:
15+
- "return\\s+.*filter\\s*$"
16+
how_to_fix: "Ensure invalid filters raise descriptive errors instead of silently returning unfiltered results."
17+
18+
- description: "Require regression tests when modifying tool schema validation or client tool execution"
19+
enabled: true
20+
severity: "medium"
21+
event_types: ["pull_request"]
22+
parameters:
23+
source_patterns:
24+
- "packages/core/src/**/tool*.ts"
25+
- "packages/core/src/agent/**"
26+
- "packages/client/**"
27+
test_patterns:
28+
- "packages/core/tests/**"
29+
- "tests/**"
30+
min_test_files: 1
31+
rationale: "Tool invocation changes have previously caused regressions in clientTools streaming."
32+
33+
- description: "Ensure every agent exposes a user-facing description for UI profiles"
34+
enabled: true
35+
severity: "low"
36+
event_types: ["pull_request"]
37+
parameters:
38+
file_patterns:
39+
- "packages/core/src/agent/**"
40+
required_text:
41+
- "description"
42+
message: "Add or update the agent description so downstream UIs can render capabilities."
43+
44+
- description: "Block merges when URL or asset handling changes bypass provider capability checks"
45+
enabled: true
46+
severity: "high"
47+
event_types: ["pull_request"]
48+
parameters:
49+
file_patterns:
50+
- "packages/core/src/agent/message-list/**"
51+
- "packages/core/src/llm/**"
52+
require_patterns:
53+
- "isUrlSupportedByModel"
54+
forbidden_patterns:
55+
- "downloadAssetsFromMessages\\(messages\\)"
56+
how_to_fix: "Preserve remote URLs for providers that support them natively; only download assets for unsupported providers."

docs/getting-started/configuration.md

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,52 @@ parameters:
111111
excluded_branches: ["feature/*", "hotfix/*"]
112112
```
113113

114+
### Diff-Aware Validators
115+
116+
Watchflow can now reason about pull-request diffs directly. The following parameter groups plug into diff-aware validators:
117+
118+
#### `diff_pattern`
119+
120+
Use this to require or forbid specific regex patterns inside matched files.
121+
122+
```yaml
123+
parameters:
124+
file_patterns:
125+
- "packages/core/src/**/vector-query.ts"
126+
require_patterns:
127+
- "throw\\s+new\\s+Error"
128+
forbidden_patterns:
129+
- "console\\.log"
130+
```
131+
132+
#### `related_tests`
133+
134+
Ensure core source changes include matching test updates.
135+
136+
```yaml
137+
parameters:
138+
source_patterns:
139+
- "packages/core/src/**"
140+
test_patterns:
141+
- "tests/**"
142+
- "packages/core/tests/**"
143+
min_test_files: 1
144+
```
145+
146+
#### `required_field_in_diff`
147+
148+
Verify that additions to certain files include a text fragment (for example, enforcing `description` on new agents).
149+
150+
```yaml
151+
parameters:
152+
file_patterns:
153+
- "packages/core/src/agent/**"
154+
required_text:
155+
- "description"
156+
```
157+
158+
These validators activate automatically when the parameters above are present, so you do not need to declare an `actions` block or manual mapping.
159+
114160
## Severity Levels
115161

116162
### Severity Configuration
@@ -219,6 +265,39 @@ rules:
219265
required_teams: ["senior-engineers"]
220266
```
221267

268+
## Diff-Aware Validators
269+
270+
Watchflow supports advanced validators that inspect actual PR diffs to enforce code-level patterns:
271+
272+
### diff_pattern
273+
Enforce regex requirements or prohibitions within file patches.
274+
275+
```yaml
276+
parameters:
277+
file_patterns: ["packages/core/src/**/vector-query.ts"]
278+
require_patterns: ["throw\\s+new\\s+Error"]
279+
forbid_patterns: ["silent.*skip"]
280+
```
281+
282+
### related_tests
283+
Require test file updates when core code changes.
284+
285+
```yaml
286+
parameters:
287+
file_patterns: ["packages/core/src/**"]
288+
require_test_updates: true
289+
min_test_files: 1
290+
```
291+
292+
### required_field_in_diff
293+
Ensure new additions include required fields (e.g., agent descriptions).
294+
295+
```yaml
296+
parameters:
297+
file_patterns: ["packages/core/src/agent/**"]
298+
required_text: "description"
299+
```
300+
222301
## Best Practices
223302

224303
### Rule Design

docs/reports/mastra-analysis.md

Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
1+
# Mastra Repository Analysis
2+
3+
Mastra (`mastra-ai/mastra`) is a TypeScript-first agent framework for building production-grade AI assistants. The project has roughly **280 contributors**, **134 open pull requests**, and active CI coverage via GitHub Actions. This document captures the agreed-upon analysis from November 2025 so we can align on rule proposals before shipping automation.
4+
5+
## Repository Snapshot
6+
7+
- **Focus**: AI agents with tooling, memory, workflows, and multi-step orchestration
8+
- **Primary language**: TypeScript with pnpm-based monorepo
9+
- **Governance signals**: Detailed `CONTRIBUTING.md`, CODEOWNERS, changeset automation, active doc set
10+
- **Pain points**: Complex LLM/provider integrations, repeated validation gaps, and regression risk in shared tooling layers
11+
12+
## Pull Request Sample (Nov 2025)
13+
14+
| PR | Title | Outcome | Notes |
15+
| --- | --- | --- | --- |
16+
| [#10180](https://github.com/mastra-ai/mastra/pull/10180) | feat: add custom model gateway support with automatic type generation | ✅ merged | Large feature: gateway registry, TS type generation, doc updates |
17+
| [#10269](https://github.com/mastra-ai/mastra/pull/10269) | AI SDK tripwire data chunks | ✅ merged | Fixes & changeset for SDK data chunking bug |
18+
| [#10141](https://github.com/mastra-ai/mastra/pull/10141) | fix: throw on invalid filter instead of silently skipping filtering | ✅ merged | Addressed regression where invalid filters returned unfiltered data |
19+
| [#10300](https://github.com/mastra-ai/mastra/pull/10300) | Add description to type | ✅ merged | Unblocked Agent profile UI by exposing description metadata |
20+
| [#9880](https://github.com/mastra-ai/mastra/pull/9880) | Fix clientjs clientTools execution | ✅ merged | Fixed client-side tool streaming regressions |
21+
| [#9941](https://github.com/mastra-ai/mastra/pull/9941) | fix(core): input tool validation with no schema | ✅ merged | Restored validation for schema-less tool inputs |
22+
23+
## Pattern Summary
24+
25+
- **Validation & safety gaps (≈40%)** – invalid filters or schema-less tools silently bypassed safeguards.
26+
- **Tooling & integration regressions (≈33%)** – clientTools streaming, AI SDK data chunking, URL handling.
27+
- **Experience polish gaps (≈17%)** – missing agent descriptions prevented UI consistency.
28+
- **High merge velocity** – most fixes merged quickly; reinforces need for automated guardrails so regressions are caught before release.
29+
30+
## Recommended Watchflow Rules
31+
32+
Rules intentionally avoid the optional `actions:` block so they remain compatible with the current loader. Enforcement intent is described in each `description` and reflected in `severity`.
33+
34+
```yaml
35+
rules:
36+
- description: "Block merges when PRs change filter validation logic without failing on invalid inputs"
37+
enabled: true
38+
severity: "high"
39+
event_types: ["pull_request"]
40+
parameters:
41+
file_patterns:
42+
- "packages/core/src/**/vector-query.ts"
43+
- "packages/core/src/**/graph-rag.ts"
44+
- "packages/core/src/**/filters/*.ts"
45+
require_patterns:
46+
- "throw\\s+new\\s+Error"
47+
- "raise\\s+ValueError"
48+
forbidden_patterns:
49+
- "return\\s+.*filter\\s*$"
50+
how_to_fix: "Ensure invalid filters raise descriptive errors instead of silently returning unfiltered results."
51+
52+
- description: "Require regression tests when modifying tool schema validation or client tool execution"
53+
enabled: true
54+
severity: "medium"
55+
event_types: ["pull_request"]
56+
parameters:
57+
source_patterns:
58+
- "packages/core/src/**/tool*.ts"
59+
- "packages/core/src/agent/**"
60+
- "packages/client/**"
61+
test_patterns:
62+
- "packages/core/tests/**"
63+
- "tests/**"
64+
min_test_files: 1
65+
rationale: "Tool invocation changes have previously caused regressions in clientTools streaming."
66+
67+
- description: "Ensure every agent exposes a user-facing description for UI profiles"
68+
enabled: true
69+
severity: "low"
70+
event_types: ["pull_request"]
71+
parameters:
72+
file_patterns:
73+
- "packages/core/src/agent/**"
74+
required_text:
75+
- "description"
76+
message: "Add or update the agent description so downstream UIs can render capabilities."
77+
78+
- description: "Block merges when URL or asset handling changes bypass provider capability checks"
79+
enabled: true
80+
severity: "high"
81+
event_types: ["pull_request"]
82+
parameters:
83+
file_patterns:
84+
- "packages/core/src/agent/message-list/**"
85+
- "packages/core/src/llm/**"
86+
require_patterns:
87+
- "isUrlSupportedByModel"
88+
forbidden_patterns:
89+
- "downloadAssetsFromMessages\\(messages\\)"
90+
how_to_fix: "Preserve remote URLs for providers that support them natively; only download assets for unsupported providers."
91+
```
92+
93+
These concrete rules rely on the diff-aware validators recently added to Watchflow:
94+
95+
- `diff_pattern` ensures critical patches keep throwing exceptions or performing capability checks.
96+
- `related_tests` requires PRs touching core modules to include matching test updates.
97+
- `required_field_in_diff` verifies additions to agent definitions include a `description` so downstream UIs stay in sync.
98+
99+
Because the PR processor now passes normalized diffs into the engine, these validators operate deterministically without LLM fallbacks.
100+
101+
## PR Template Snippet
102+
103+
```markdown
104+
## Repository Analysis Complete
105+
106+
We've analyzed your repository and identified key quality patterns based on recent PR history.
107+
108+
### Key Findings
109+
- 40% of recent fixes patched validation or data-safety gaps (filters, schema-less tools).
110+
- 33% addressed tool/LLM integration regressions (clientTools, AI SDK, URL handling).
111+
- Tests/documentation often lag behind critical fixes, creating follow-up churn.
112+
113+
### Recommended Rules
114+
- Block filter-validation changes that stop throwing on invalid inputs.
115+
- Require regression tests when modifying tool schemas or clientTools execution.
116+
- Enforce agent descriptions so UI consumers can present profiles.
117+
- Block URL/asset handling changes that skip provider capability checks.
118+
119+
### Installation
120+
1. Install the Watchflow GitHub App and grant access to `mastra-ai/mastra`.
121+
2. Add `.watchflow/rules.yaml` with the rules above (see snippet).
122+
3. Watchflow will start reporting violations through status checks immediately.
123+
124+
Questions? Reach out to the Watchflow team.
125+
```
126+
127+
## Validation Plan
128+
129+
1. Keep the rule definitions in `docs/samples/mastra-watchflow-rules.yaml`.
130+
2. Run `pytest tests/unit/test_mastra_rules_sample.py` to ensure every rule loads via `Rule.model_validate`.
131+
3. (Optional) Use the repository analysis agent once PR-diff ingestion ships to simulate Mastra commits before opening an automated PR with these rules.
132+
133+
This keeps the deliverable lightweight, fully tested, and ready for the PR template automation flow discussed with Dimitris.

mkdocs.yml

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,8 @@ nav:
6767
- Comparative Analysis: benchmarks.md
6868
- Architecture:
6969
- Overview: concepts/overview.md
70+
- Case Studies:
71+
- Mastra Repository Analysis: reports/mastra-analysis.md
7072

7173
# Plugins
7274
plugins:
@@ -132,6 +134,3 @@ extra:
132134
social:
133135
- icon: fontawesome/brands/github
134136
link: https://github.com/warestack/watchflow
135-
analytics:
136-
provider: google
137-
property: ${GOOGLE_ANALYTICS_KEY}

src/agents/engine_agent/prompts.py

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -177,7 +177,7 @@ def _extract_event_context(event_data: dict, event_type: str) -> str:
177177
context_parts = []
178178

179179
if event_type == "pull_request":
180-
pr = event_data.get("pull_request", {})
180+
pr = event_data.get("pull_request_details") or event_data.get("pull_request") or {}
181181
context_parts.extend(
182182
[
183183
f"Title: {pr.get('title', 'N/A')}",
@@ -188,6 +188,17 @@ def _extract_event_context(event_data: dict, event_type: str) -> str:
188188
]
189189
)
190190

191+
files = event_data.get("files", [])
192+
if files:
193+
top_files = [file.get("filename") for file in files[:5] if file.get("filename")]
194+
context_parts.append(
195+
f"Changed Files ({len(files)} total): {top_files if top_files else '[filenames unavailable]'}"
196+
)
197+
198+
diff_summary = event_data.get("diff_summary")
199+
if diff_summary:
200+
context_parts.append(f"Diff Summary:\n{diff_summary}")
201+
191202
elif event_type == "push":
192203
context_parts.extend(
193204
[

src/agents/factory.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
from src.agents.base import BaseAgent
1313
from src.agents.engine_agent import RuleEngineAgent
1414
from src.agents.feasibility_agent import RuleFeasibilityAgent
15+
from src.agents.repository_analysis_agent import RepositoryAnalysisAgent
1516

1617
logger = logging.getLogger(__name__)
1718

@@ -34,6 +35,7 @@ def get_agent(agent_type: str, **kwargs: Any) -> BaseAgent:
3435
>>> engine_agent = get_agent("engine")
3536
>>> feasibility_agent = get_agent("feasibility")
3637
>>> acknowledgment_agent = get_agent("acknowledgment")
38+
>>> analysis_agent = get_agent("repository_analysis")
3739
"""
3840
agent_type = agent_type.lower()
3941

@@ -43,6 +45,8 @@ def get_agent(agent_type: str, **kwargs: Any) -> BaseAgent:
4345
return RuleFeasibilityAgent(**kwargs)
4446
elif agent_type == "acknowledgment":
4547
return AcknowledgmentAgent(**kwargs)
48+
elif agent_type == "repository_analysis":
49+
return RepositoryAnalysisAgent(**kwargs)
4650
else:
47-
supported = ", ".join(["engine", "feasibility", "acknowledgment"])
51+
supported = ", ".join(["engine", "feasibility", "acknowledgment", "repository_analysis"])
4852
raise ValueError(f"Unsupported agent type: {agent_type}. Supported: {supported}")

0 commit comments

Comments
 (0)