It is an issue reader in fact
This commit is contained in:
@@ -0,0 +1,3 @@
|
|||||||
|
### 2026-09-19
|
||||||
|
1. Created an agent that can accept YouTrack™ task ID, read an issue, create a context for a task (body, comments, image attachments) and decompose it for implementing
|
||||||
|
2. **[missing]** extract a decomposing because it's manner depends on the task context (i.e. backend-dev, frontend-dev, seller, marketing, ad, design, ...) so an issue_reader agent should listen for not delivered tasks, create a context and delegate a decomposition for specific agent. If there is no agent can create this work - add comment that it cannot be resolved until appropriate agent will be created, assign a task to admin and change status to "To Be Discussed". There should be an agent that has information about all the rest of agents and can provide the information, who can do that task and how (in case of confusing - ask another agents if they can do the task). As this architecture is a very future automatization, it is enough to have just a registry of agents and omit the conversation of issue reader with another agents.
|
||||||
+8
-11
@@ -1,25 +1,22 @@
|
|||||||
|
|
||||||
"""
|
"""
|
||||||
Backend Developer Agent
|
Issue Decomposing Agent
|
||||||
This agent specializes in backend development tasks including:
|
This agent specializes in development tasks including:
|
||||||
- API development with FastAPI
|
- Web systems architecture
|
||||||
- Database design and management
|
|
||||||
- Server-side programming
|
|
||||||
- System architecture
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from typing import Dict, Any
|
from typing import Dict, Any
|
||||||
import json
|
import json
|
||||||
|
|
||||||
from agents.backend_dev.models import TaskPlan
|
from agents.issue_reader.models import TaskPlan
|
||||||
from agents.backend_dev.decomposer import IssueDecomposer
|
from agents.issue_reader.decomposer import IssueDecomposer
|
||||||
from agents.backend_dev.validator import enforce
|
from agents.issue_reader.validator import enforce
|
||||||
from common.youtrack_mcp_client import IssueNotFound
|
from common.youtrack_mcp_client import IssueNotFound
|
||||||
|
|
||||||
|
|
||||||
class BackendDeveloperAgent:
|
class IssueReaderAgent:
|
||||||
def __init__(self, context_builder, llm):
|
def __init__(self, context_builder, llm):
|
||||||
self.name = "Backend Developer"
|
self.name = "Issue decomposing agent"
|
||||||
self.ctx_builder = context_builder
|
self.ctx_builder = context_builder
|
||||||
self.decomposer = IssueDecomposer(llm)
|
self.decomposer = IssueDecomposer(llm)
|
||||||
|
|
||||||
@@ -5,8 +5,8 @@ import re
|
|||||||
|
|
||||||
import httpx
|
import httpx
|
||||||
|
|
||||||
from agents.backend_dev.models import IssueContext
|
from agents.issue_reader.models import IssueContext
|
||||||
from agents.backend_dev.project_loader import load_project
|
from agents.issue_reader.project_loader import load_project
|
||||||
from common.as_type import _as_dict, _as_list, _first, _extract_base64
|
from common.as_type import _as_dict, _as_list, _first, _extract_base64
|
||||||
from common.youtrack_mcp_client import IssueNotFound
|
from common.youtrack_mcp_client import IssueNotFound
|
||||||
|
|
||||||
@@ -3,10 +3,10 @@ import json
|
|||||||
|
|
||||||
from openai import images
|
from openai import images
|
||||||
|
|
||||||
from agents.backend_dev.models import IssueContext, Task, TaskPlan, TaskKind, Atomicity
|
from agents.issue_reader.models import IssueContext, Task, TaskPlan, TaskKind, Atomicity
|
||||||
|
|
||||||
|
|
||||||
SYSTEM_PROMPT = """You are a senior backend engineer.
|
SYSTEM_PROMPT = """You are a senior engineer.
|
||||||
Your job: given a YouTrack issue, its comments, and the project context,
|
Your job: given a YouTrack issue, its comments, and the project context,
|
||||||
produce the SMALLEST possible sequence of tasks to resolve it.
|
produce the SMALLEST possible sequence of tasks to resolve it.
|
||||||
|
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
import yaml
|
import yaml
|
||||||
from agents.backend_dev.models import ProjectContext
|
from agents.issue_reader.models import ProjectContext
|
||||||
|
|
||||||
|
|
||||||
PROJECTS_DIR = Path(__file__).parent.parent.parent / "projects"
|
PROJECTS_DIR = Path(__file__).parent.parent.parent / "projects"
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
# validator.py
|
# validator.py
|
||||||
from agents.backend_dev.models import Task, TaskPlan, Atomicity
|
from agents.issue_reader.models import Task, TaskPlan, Atomicity
|
||||||
|
|
||||||
MAX_HOURS = 8
|
MAX_HOURS = 8
|
||||||
VAGUE_VERBS = ("handle", "support", "improve", "refactor", "manage", "deal with")
|
VAGUE_VERBS = ("handle", "support", "improve", "refactor", "manage", "deal with")
|
||||||
@@ -5,8 +5,8 @@ from contextlib import asynccontextmanager
|
|||||||
import httpx
|
import httpx
|
||||||
from dotenv import load_dotenv
|
from dotenv import load_dotenv
|
||||||
from fastapi import FastAPI, HTTPException
|
from fastapi import FastAPI, HTTPException
|
||||||
from agents.backend_dev.BackendDeveloperAgent import BackendDeveloperAgent
|
from agents.issue_reader.IssueReaderAgent import IssueReaderAgent
|
||||||
from agents.backend_dev.context_builder import YouTrackContextBuilder
|
from agents.issue_reader.context_builder import YouTrackContextBuilder
|
||||||
from common.llm_client import LLMClient
|
from common.llm_client import LLMClient
|
||||||
from common.youtrack_mcp_client import YouTrackMCPClient, IssueNotFound
|
from common.youtrack_mcp_client import YouTrackMCPClient, IssueNotFound
|
||||||
|
|
||||||
@@ -34,7 +34,7 @@ async def lifespan(app: FastAPI):
|
|||||||
follow_redirects=True,
|
follow_redirects=True,
|
||||||
)
|
)
|
||||||
|
|
||||||
app.state.backend_agent = BackendDeveloperAgent(
|
app.state.issue_reader_agent = IssueReaderAgent(
|
||||||
YouTrackContextBuilder(mcp, http_for_attachments),
|
YouTrackContextBuilder(mcp, http_for_attachments),
|
||||||
LLMClient(
|
LLMClient(
|
||||||
base_url=env("LLM_ADDRESS"),
|
base_url=env("LLM_ADDRESS"),
|
||||||
@@ -59,18 +59,18 @@ async def say_hello(name: str):
|
|||||||
return {"message": f"Hello {name}"}
|
return {"message": f"Hello {name}"}
|
||||||
|
|
||||||
|
|
||||||
@app.get("/backend")
|
@app.get("/decomposing")
|
||||||
async def backend_task(task: str):
|
async def decomposing_issue(issue: str):
|
||||||
agent: BackendDeveloperAgent = app.state.backend_agent
|
agent: IssueReaderAgent = app.state.issue_reader_agent
|
||||||
try:
|
try:
|
||||||
logger.info(f"Received task: {task}")
|
logger.info(f"Received an issue: {issue}")
|
||||||
plan = await agent.plan_issue(task)
|
plan = await agent.plan_issue(issue)
|
||||||
logger.info("Task planning successful.")
|
logger.info("Task planning successful.")
|
||||||
print(agent.render(plan))
|
print(agent.render(plan))
|
||||||
return {"plan": plan}
|
return {"plan": plan}
|
||||||
except IssueNotFound:
|
except IssueNotFound:
|
||||||
logger.error(f"Issue {task} not found.")
|
logger.error(f"Issue {issue} not found.")
|
||||||
raise HTTPException(status_code=404, detail=f"Issue {task} not found")
|
raise HTTPException(status_code=404, detail=f"Issue {issue} not found")
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.exception("An unexpected error occurred")
|
logger.exception("An unexpected error occurred")
|
||||||
return {"error": str(e)}
|
return {"error": str(e)}
|
||||||
|
|||||||
Reference in New Issue
Block a user