Skip to content

Commit 90e76c7

Browse files
committed
Update arch_mismatch_detector_agent to fetch job start and end times from GCS, and replace loki_query mcp function call by the grafana_loki_ query function call
1 parent 14f8d59 commit 90e76c7

File tree

2 files changed

+88
-31
lines changed

2 files changed

+88
-31
lines changed

sub_agents/arch_mismatch_detector/agent.py

Lines changed: 66 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -4,38 +4,94 @@
44
from google.adk.models.lite_llm import LiteLlm
55
from . import prompt
66
from google.adk.tools.mcp_tool.mcp_toolset import MCPToolset, StreamableHTTPConnectionParams
7+
from dotenv import load_dotenv
78

89

910
import asyncio
1011
import httpx
11-
import re
1212
import threading
1313
import concurrent.futures
14-
import re
1514
import os
16-
from typing import Dict, Any, Optional
15+
from typing import Dict, Any
16+
from datetime import datetime
1717

1818
GCS_URL = "https://gcsweb-ci.apps.ci.l2s4.p1.openshiftapps.com/gcs/test-platform-results/logs"
1919

2020
MODEL = os.environ.get("MODEL", "qwen3:4b")
2121

22+
load_dotenv()
23+
24+
def run_async_in_thread(coro):
25+
"""Run async function in a thread to avoid event loop conflicts."""
26+
27+
def run_in_thread():
28+
loop = asyncio.new_event_loop()
29+
asyncio.set_event_loop(loop)
30+
try:
31+
return loop.run_until_complete(coro)
32+
finally:
33+
loop.close()
34+
35+
with concurrent.futures.ThreadPoolExecutor() as executor:
36+
future = executor.submit(run_in_thread)
37+
return future.result()
38+
39+
def get_job_start_and_end_time_tool(job_name: str, build_id: str)-> Dict[str, Any]:
40+
"""Get the start and end time of a job."""
41+
return run_async_in_thread(get_job_start_and_end_time_async(job_name, build_id))
42+
43+
async def get_job_start_and_end_time_async(job_name: str, build_id: str)-> Dict[str, Any]:
44+
"""Get the start and end time of a job."""
45+
start_time = None
46+
end_time = None
47+
url_started = f"{GCS_URL}/{job_name}/{build_id}/started.json"
48+
url_finished = f"{GCS_URL}/{job_name}/{build_id}/finished.json"
49+
try:
50+
async with httpx.AsyncClient() as client:
51+
response_started = await client.get(url_started)
52+
response_started.raise_for_status()
53+
data_started = response_started.json()
54+
if not data_started:
55+
return {"error": "No response from Prow API for started.json"}
56+
start_time = data_started["timestamp"]
57+
async with httpx.AsyncClient() as client:
58+
response_finished = await client.get(url_finished)
59+
response_finished.raise_for_status()
60+
data_finished = response_finished.json()
61+
if not data_finished:
62+
return {"error": "No response from Prow API for finished.json"}
63+
end_time = data_finished["timestamp"]
64+
# Convert epoch timestamps to RFC 3339 format
65+
if start_time:
66+
start_time = datetime.fromtimestamp(start_time).strftime('%Y-%m-%dT%H:%M:%SZ')
67+
if end_time:
68+
end_time = datetime.fromtimestamp(end_time).strftime('%Y-%m-%dT%H:%M:%SZ')
69+
return {
70+
"start_time": start_time,
71+
"end_time": end_time
72+
}
73+
except Exception as e:
74+
return {"error": f"Failed to fetch job start and end time: {str(e)}"}
2275

2376
arch_mismatch_detector_agent = Agent(
2477
model=LiteLlm(model=MODEL),
78+
# model="gemini-2.0-flash",
2579
name="arch_mismatch_detector_agent",
2680
instruction=prompt.ARCH_MISMATCH_DETECTOR_PROMPT,
2781
output_key="installation_analysis_output",
2882
tools=[
83+
get_job_start_and_end_time_tool,
2984
MCPToolset(
3085
connection_params=StreamableHTTPConnectionParams(
31-
url="http://127.0.0.1:9000/mcp",
32-
tool_filter=[
33-
"loki_query",
34-
"loki_label_names",
35-
"loki_label_values",
36-
],
86+
url="http://127.0.0.1:8888/stream"
3787
),
88+
tool_filter=[
89+
"grafana_loki_query",
90+
],
91+
3892
),
3993

4094
],
41-
)
95+
)
96+
97+
root_agent = arch_mismatch_detector_agent

sub_agents/arch_mismatch_detector/prompt.py

Lines changed: 22 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,40 +1,41 @@
11
"""Prompts for Installation Analyst Agent."""
22

3-
ARCH_MISMATCH_DETECTOR_PROMPT = """
4-
You are the Arch Mismatch Detector agent.
3+
ARCH_MISMATCH_DETECTOR_PROMPT = f"""
4+
You are the Arch Mismatch Detector agent. You are a grafana loki expert.
55
66
Objective:
77
- Retrieve and analyze Grafana Loki logs for a specific CI job invocation to identify architecture mismatch errors, specifically messages matching the case-insensitive pattern "exec format".
88
99
Required user inputs in each request:
10-
- start_time: the absolute start of the time range to search.
11-
- end_time: the absolute end of the time range to search.
1210
- job_name: the name of the job to search for.
1311
- build_id: the id of the build to search for.
1412
15-
Time handling rules:
16-
- Accept start_time and end_time as either Unix epoch milliseconds or ISO 8601 / RFC3339 timestamps.
17-
- If the user does not provide both, ask them to provide both before proceeding.
18-
- Convert any non-epoch-millisecond timestamps to epoch milliseconds before calling tools.
19-
- If start_time >= end_time, ask the user to correct the range.
20-
21-
Data source and query:
22-
- Always query Grafana Loki using the loki_query tool.
23-
- Always set orgId to 1.
24-
- Build the invoker as: "openshift-internal-ci/" + job_name + "/" + build_id
25-
- Construct the expression exactly (preserve content; whitespace changes are okay):
26-
{invoker="openshift-internal-ci/{job_name}/{build_id}"} |~ "(?i)exec format"
13+
Workflow:
14+
- Use the get_job_start_and_end_time_tool to get the start and end time of the job from the prow job_name and build_id.
15+
- Prepare the inputs for the grafana_loki_query tool
16+
- orgId: 1
17+
- datasource uid: PCEB727DF2F34084E (DPCR Loki)
18+
- url: https://grafana-loki.ci.openshift.org/api/ds/query
19+
- expr:
20+
- Replace %job_name%, %build_id% by the values provided in the user inputs in the following expression:
21+
{{invoker="openshift-internal-ci/%job_name%/%build_id%"}} |~ "(?i)exec format"
22+
- Set the start_time and end_time to the values provided by the get_job_start_and_end_time_tool.
23+
- Use the grafana_loki_query tool to query the logs for the job.
24+
- Analyze the logs for the job.
25+
- Return the analysis.
2726
28-
Tool invocation contract (loki_query):
27+
Tool invocation contract (grafana_loki_query):
2928
- Parameters you must provide:
29+
- datasource uid: PCEB727DF2F34084E (DPCR Loki)
3030
- orgId: 1
31-
- url: https://grafana-loki.ci.openshift.org
32-
- expr: the expression above
33-
- start: start_time in Unix epoch milliseconds
34-
- end: end_time in Unix epoch milliseconds
31+
- url: https://grafana-loki.ci.openshift.org/api/ds/query
32+
- expr: the expression above prepared by the workflow
33+
- start: start_time in ISO 8601 / RFC3339 format
34+
- end: end_time in ISO 8601 / RFC3339 format
3535
3636
Response style:
3737
- Keep outputs concise and focused on the error pattern.
38+
- When no logs are found, this indicates that there are no arch mismatch errors in the job.
3839
- Report total matches, and surface 3–5 representative lines with timestamps.
3940
- Briefly note any repeated message patterns or clusters.
4041
- Provide a convenience link for further inspection in Grafana Explore with orgId=1 and the requested time range, e.g., https://grafana-loki.ci.openshift.org/explore?orgId=1

0 commit comments

Comments
 (0)