Skip to content

Commit d36742e

Browse files
authored
Merge branch 'main' into test-schema
2 parents 8ebaa0d + 18711d3 commit d36742e

File tree

20 files changed

+645
-1
lines changed

20 files changed

+645
-1
lines changed

.eslintignore

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,4 +8,5 @@ templates
88
scripts/agent-evals/output
99
scripts/agent-evals/node_modules
1010
scripts/agent-evals/lib
11-
scripts/agent-evals/templates
11+
scripts/agent-evals/templates
12+
julesbot
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
name: Jules Bot Action
2+
3+
on:
4+
issues:
5+
types: [opened]
6+
7+
jobs:
8+
run_agent:
9+
if: github.event.action == 'opened'
10+
runs-on: ubuntu-latest
11+
permissions:
12+
issues: write
13+
steps:
14+
- name: Checkout repository
15+
uses: actions/checkout@v3
16+
17+
- name: Set up Python
18+
uses: actions/setup-python@v4
19+
with:
20+
python-version: "3.14"
21+
22+
- name: Install dependencies
23+
run: |
24+
python -m pip install --upgrade pip
25+
pip install google-adk requests
26+
27+
- name: Run root agent
28+
env:
29+
JULES_KEY: ${{ secrets.JULES_KEY }}
30+
GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }}
31+
GOOGLE_API_KEY: ${{ secrets.GEMINI_API_KEY }}
32+
ISSUE_TITLE: ${{ github.event.issue.title }}
33+
ISSUE_NUMBER: ${{ github.event.issue.number }}
34+
ISSUE_BODY: ${{ github.event.issue.body }}
35+
ISSUE_URL: ${{ github.event.issue.html_url }}
36+
run: |
37+
python julesbot/issues_call.py --prompt "Triage this new issue: $ISSUE_TITLE $ISSUE_NUMBER $ISSUE_BODY $ISSUE_URL"

julesbot/.gitignore

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
.venv
2+
firebase-debug.log
3+
__pycache__
4+
venv
5+
.env
6+
session.db
7+
.adk/

julesbot/README.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
## Local Setup
2+
3+
- Install python 3.14 or 3.13
4+
- Install a venv using `python3 -m venv venv`
5+
- Start the venv using `source venv/bin/activate`
6+
- Install the adk using `pip install google-adk`
7+
- Set the environment variables `JULES_KEY` and `GITHUB_PAT`
8+
- Run the agent using `adk run issue_to_jules_agent` or `adk web`
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
from . import agent
Lines changed: 180 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,180 @@
1+
from google.adk.agents.llm_agent import Agent
2+
from google.adk.tools.mcp_tool import McpToolset, StreamableHTTPConnectionParams
3+
from google.adk.tools.agent_tool import AgentTool
4+
from google.adk.agents.sequential_agent import SequentialAgent
5+
from issue_to_jules_agent.subagents.spam_agent.agent import spam_agent
6+
from issue_to_jules_agent.subagents.label_agent.agent import label_agent
7+
from issue_to_jules_agent.subagents.complexity_scoping_agent.agent import complexity_scoping_agent
8+
from issue_to_jules_agent.subagents.issue_type_agent.agent import issue_type_agent
9+
10+
import requests
11+
import json
12+
13+
import os
14+
15+
JULES_KEY = os.environ.get("JULES_KEY")
16+
GITHUB_PAT = os.environ.get("GITHUB_PAT")
17+
18+
IS_SPAM = AgentTool(
19+
agent=spam_agent,
20+
)
21+
22+
LABELER = AgentTool(
23+
agent=label_agent
24+
)
25+
26+
COMPLEXITY_SCORE = AgentTool(
27+
agent=complexity_scoping_agent,
28+
)
29+
30+
ISSUE_TYPE = AgentTool(
31+
agent=issue_type_agent,
32+
)
33+
34+
github_toolset = McpToolset(
35+
connection_params=StreamableHTTPConnectionParams(
36+
url="https://api.githubcopilot.com/mcp",
37+
headers={"Authorization": "Bearer " + GITHUB_PAT},
38+
),
39+
tool_filter=[
40+
"get_file_contents",
41+
"get_commit",
42+
"search_repositories",
43+
"search_issues",
44+
"search_code",
45+
"list_issues",
46+
"list_issue_types",
47+
"list_commits",
48+
"issue_read",
49+
"issue_write",
50+
],
51+
)
52+
53+
54+
def jules_create_session(prompt: str, title: str) -> dict:
55+
"""
56+
Creates a new Jules session to address a specific prompt within a GitHub repository.
57+
58+
Args:
59+
prompt (str): The detailed prompt or description of the task for Jules.
60+
title (str): The title for the Jules session.
61+
62+
Returns:
63+
dict: A dictionary with 'status' ('success' or 'failure') and 'report' keys.
64+
If successful, 'report' contains the JSON response from the API.
65+
If failed, 'report' contains an error message.
66+
"""
67+
url = "https://jules.googleapis.com/v1alpha/sessions"
68+
headers = {"Content-Type": "application/json", "X-Goog-Api-Key": JULES_KEY}
69+
payload = {
70+
"prompt": prompt,
71+
"sourceContext": {
72+
"source": "sources/github/firebase/firebase-tools",
73+
"githubRepoContext": {"startingBranch": "main"},
74+
},
75+
"title": title,
76+
}
77+
78+
response = None
79+
try:
80+
response = requests.post(url, headers=headers, data=json.dumps(payload))
81+
response.raise_for_status() # Raise an exception for bad status codes
82+
response_json = response.json()
83+
print("Jules Session Created Successfully:")
84+
print(json.dumps(response_json, indent=2))
85+
return {"status": "success", "report": response_json}
86+
except requests.exceptions.RequestException as e:
87+
error_message = f"Error creating Jules session: {e}"
88+
print(error_message)
89+
if response is not None:
90+
error_message += f"\nResponse status code: {response.status_code}"
91+
error_message += f"\nResponse body: {response.text}"
92+
print(f"Response status code: {response.status_code}")
93+
print(f"Response body: {response.text}")
94+
return {"status": "failure", "report": error_message}
95+
96+
97+
jules_agent = Agent(
98+
model="gemini-3-pro-preview",
99+
name="jules_agent",
100+
description="Formats a task for jules, a code agent to help solve a GitHub issue based on the information provided",
101+
instruction="""
102+
### System Instructions
103+
You are an expert assistant for a software development team. Your role is to process bug reports and feature requests, and then create a clear, structured, and actionable task for an AI developer named Jules.
104+
105+
### Task
106+
Based on the provided issue details, generate a complete, markdown-formatted task description for Jules.
107+
108+
### Instructions
109+
1. Read the `issue_body` and any `discussion_body` provided.
110+
2. **Summarize the Issue:** Create a concise summary of the problem and include a link to the original issue.
111+
3. **Define the Task:** Write a clear and direct task for Jules to solve the problem.
112+
4. **Handle Reproduction Steps:**
113+
* If `reproduction_steps` are provided in the input, include them under the "Reproduction" heading.
114+
* If `reproduction_steps` are empty or not provided, add the following instruction for Jules: "Please attempt to reproduce the issue first so that you can verify the fix."
115+
5. **Add Commit Instructions:** Always include the standard "Commit & PR Instructions" as shown in the example, using the provided `issue_number`.
116+
117+
### Input Placeholders
118+
- `{{issue_body}}`: The raw text of the issue report.
119+
- `{{discussion_body}}`: (Optional) The raw text of the discussion.
120+
- `{{original_link}}`: The URL to the original issue.
121+
- `{{issue_number}}`: The numerical ID of the issue.
122+
- `{{reproduction_steps}}`: (Optional) Pre-written steps to reproduce the issue.
123+
124+
### Output Template & Example
125+
126+
---
127+
128+
#### Example Input:
129+
```json
130+
{
131+
"issue_body": "The login button looks weird on my phone. It's all the way on the right and hard to click. I'm using Safari.",
132+
"discussion_body": "User @dev1 confirmed this on iOS 15. It looks like a flexbox alignment problem in `container.css`. Should be a quick fix.",
133+
"original_link": "https://github.com/example/project/issues/123",
134+
"issue_number": "123",
135+
"reproduction_steps": ""
136+
}
137+
```
138+
139+
#### Corresponding Desired Output:
140+
```markdown
141+
### Issue Summary
142+
The login button is misaligned on mobile browsers, specifically Safari on iOS, likely due to a flexbox alignment problem.
143+
144+
Original Issue: https://github.com/example/project/issues/123
145+
146+
### Task for Jules
147+
Please fix the CSS for the login page to ensure the login button is correctly aligned within its container on mobile browsers, especially Safari.
148+
149+
### Reproduction
150+
Please attempt to reproduce the issue first so that you can verify the fix.
151+
152+
### Commit & PR Instructions
153+
- Revert any changes to `npm-shrinkwrap.json` before committing.
154+
- If this change is user-facing, please write a `CHANGELOG.md` entry.
155+
- Ensure your PR description includes the line: `fixes #123`
156+
```
157+
158+
---
159+
160+
Now, generate the task description for the user's input.
161+
""",
162+
tools=[jules_create_session],
163+
)
164+
165+
root_agent = Agent(
166+
model="gemini-3-pro-preview",
167+
name="root_agent",
168+
description="An agent designed to help with GitHub issues",
169+
instruction="""
170+
Your job is to triage a GitHub issue. The tasks you should perform are:
171+
1. Determine if an issue is spam using the is_spam agent. If it is spam, use the issue_write tool to update the issue state to "closed" and then you are done.
172+
2. If it is not spam, hand off the issue to the LABELER tool (labeler_agent). When the LABELER tool is done, use the issue_write tool to update the issue with the suggested labels and add a label called 'Triaged by JulesBot'.
173+
3. Use the issue_type_agent to determine the type of issue. If it is a support request or feature request, report back and you are done.
174+
4. If you have not done so yet, use the issue_read tool to get the comments on the issue, to help inform the next steps
175+
5. If it is a bug, use the complexity_scoping_agent to determine the complexity of the issue.
176+
6. If it is a bug with complexity of less than 30, use the jules_agent to submit it to Jules.
177+
""",
178+
tools=[github_toolset, IS_SPAM, ISSUE_TYPE, COMPLEXITY_SCORE, LABELER],
179+
sub_agents=[jules_agent],
180+
)

julesbot/issue_to_jules_agent/subagents/__init__.py

Whitespace-only changes.
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
from . import agent
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
from google.adk.agents.llm_agent import Agent
2+
from issue_to_jules_agent.subagents.complexity_scoping_agent import prompt
3+
from pydantic import BaseModel, Field
4+
5+
class IssueComplexityOutput(BaseModel):
6+
complexity_score: int = Field(description="The complexity of the issue on a scale from 1-100, where 1 is the easiest and 100 is the most complex.")
7+
explanation: str = Field(description="The reason why the score was chosen.")
8+
9+
complexity_scoping_agent = Agent(
10+
model="gemini-3-pro-preview",
11+
name="complexity_agent",
12+
description="An agent that estimates the complexity of fixing a Github Issue",
13+
instruction=prompt.COMPLEXITY_INSTR,
14+
output_schema=IssueComplexityOutput
15+
)
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
COMPLEXITY_INSTR = """
2+
### Role
3+
Your job is to rate the likelihood that Jules will be able to fix an issue based on a scale of 1-100, 1 being the most likely and 100 being the least likely.
4+
5+
### Context
6+
Signs that an issue should have a low score:
7+
- A potential fix is suggested in the issue
8+
- There is a clear error message with a stack trace (ie a crash caused by reading properties of undefined)
9+
10+
Signs that an issue should have a high score:
11+
- A fix would require a API change
12+
- The error described happens intermittently
13+
- There is not a clear reproduction provided.
14+
- It includes Java or Golang stack traces - this suggests that the error is coming from an emulator binary, which is difficult for Jules to fix.
15+
"""

0 commit comments

Comments
 (0)