# Copyright (c) Microsoft. All rights reserved. import httpx from pydantic import BaseModel, Field from semantic_kernel.functions.kernel_function_decorator import kernel_function # region GitHub Models class Repo(BaseModel): id: int = Field(..., alias="id") name: str = Field(..., alias="full_name") description: str | None = Field(default=None, alias="description") url: str = Field(..., alias="html_url") class User(BaseModel): id: int = Field(..., alias="id") login: str = Field(..., alias="login") name: str | None = Field(default=None, alias="name") company: str | None = Field(default=None, alias="company") url: str = Field(..., alias="html_url") class Label(BaseModel): id: int = Field(..., alias="id") name: str = Field(..., alias="name") description: str | None = Field(default=None, alias="description") class Issue(BaseModel): id: int = Field(..., alias="id") number: int = Field(..., alias="number") url: str = Field(..., alias="html_url") title: str = Field(..., alias="title") state: str = Field(..., alias="state") labels: list[Label] = Field(..., alias="labels") when_created: str | None = Field(default=None, alias="created_at") when_closed: str | None = Field(default=None, alias="closed_at") class IssueDetail(Issue): body: str | None = Field(default=None, alias="body") # endregion class GitHubSettings(BaseModel): base_url: str = "https://api.github.com" token: str class GitHubPlugin: def __init__(self, settings: GitHubSettings): self.settings = settings @kernel_function async def get_user_profile(self) -> "User": async with self.create_client() as client: response = await self.make_request(client, "/user") return User(**response) @kernel_function async def get_repository(self, organization: str, repo: str) -> "Repo": async with self.create_client() as client: response = await self.make_request(client, f"/repos/{organization}/{repo}") return Repo(**response) @kernel_function async def get_issues( self, organization: str, repo: str, max_results: int | None = None, state: str = "", label: str = "", assignee: str = "", ) -> list["Issue"]: async with self.create_client() as client: path = f"/repos/{organization}/{repo}/issues?" path = self.build_query(path, "state", state) path = self.build_query(path, "assignee", assignee) path = self.build_query(path, "labels", label) path = self.build_query(path, "per_page", str(max_results) if max_results else "") response = await self.make_request(client, path) return [Issue(**issue) for issue in response] @kernel_function async def get_issue_detail(self, organization: str, repo: str, issue_id: int) -> "IssueDetail": async with self.create_client() as client: path = f"/repos/{organization}/{repo}/issues/{issue_id}" response = await self.make_request(client, path) return IssueDetail(**response) def create_client(self) -> httpx.AsyncClient: headers = { "User-Agent": "request", "Accept": "application/vnd.github+json", "Authorization": f"Bearer {self.settings.token}", "X-GitHub-Api-Version": "2022-11-28", } return httpx.AsyncClient(base_url=self.settings.base_url, headers=headers, timeout=5) @staticmethod def build_query(path: str, key: str, value: str) -> str: if value: return f"{path}{key}={value}&" return path @staticmethod async def make_request(client: httpx.AsyncClient, path: str) -> dict: print(f"REQUEST: {path}\n") response = await client.get(path) response.raise_for_status() return response.json()