fastmcp-agents-library-agent-github 0.5.1__py3-none-any.whl → 0.5.5__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
File without changes
@@ -0,0 +1,97 @@
1
+ """
2
+ This agent is used to triage issues on a GitHub repository.
3
+ """
4
+
5
+ import os
6
+ from typing import Any, Literal
7
+
8
+ from fastmcp import FastMCP
9
+ from fastmcp.tools.tool import Tool
10
+ from fastmcp_ai_agent_bridge.pydantic_ai import FastMCPToolset
11
+ from pydantic import BaseModel
12
+ from pydantic_ai import Agent
13
+
14
+ from fastmcp_agents.library.agent.github.shared.logging import configure_console_logging
15
+ from fastmcp_agents.library.mcp.github import repo_restricted_github_mcp
16
+ from fastmcp_agents.library.mcp.nickclyde import duckduckgo_mcp
17
+
18
+ configure_console_logging()
19
+
20
+ gather_background_instructions = """
21
+ ## Persona & Goal:
22
+ You are a helpful assistant to an open source maintainer. You triage issues posted on a GitHub repository, looking
23
+ to connect them with previous issues posted, open or closed pull requests, and discussions.
24
+
25
+ {mindset_instructions}
26
+ {confidence_levels}
27
+ {section_guidelines}
28
+
29
+ You will perform multiple searches against the repository across issues, pull requests, and discussions to identify
30
+ and relevant information for the issue. If you find a relevant related item, you will review the comments or discussion
31
+ under that item to determine if it is related to the issue and how it might be related.
32
+
33
+ Your goal is to "connect the dots", and gather all related information to assist the maintainer in investigating the issue.
34
+ """
35
+
36
+
37
+ def mcp_servers_factory(owner: str, repo: str) -> dict[str, Any]:
38
+ return {
39
+ "duckduckgo": duckduckgo_mcp(),
40
+ "github": repo_restricted_github_mcp(owner=owner, repo=repo, read_only=True),
41
+ }
42
+
43
+
44
+ def repo_restricted_toolset_factory(owner: str, repo: str) -> FastMCPToolset:
45
+ return FastMCPToolset.from_mcp_config(
46
+ mcp_config=mcp_servers_factory(
47
+ owner=owner,
48
+ repo=repo,
49
+ )
50
+ )
51
+
52
+
53
+ class GitHubRelatedIssue(BaseModel):
54
+ issue_title: str
55
+ issue_number: int
56
+ confidence: Literal["high", "medium", "low"]
57
+ reason: str
58
+
59
+
60
+ class GitHubIssueSummary(BaseModel):
61
+ issue_title: str
62
+ issue_number: int
63
+ detailed_summary: str
64
+ related_issues: list[GitHubRelatedIssue]
65
+
66
+
67
+ gather_background_agent = Agent[Any, GitHubIssueSummary](
68
+ model=os.environ.get("MODEL"),
69
+ system_prompt=gather_background_instructions,
70
+ output_type=GitHubIssueSummary,
71
+ )
72
+
73
+ server = FastMCP[None](name="gather-github-issue-background")
74
+
75
+
76
+ async def gather_background(owner: str, repo: str, issue_number: int) -> GitHubIssueSummary:
77
+ result = await gather_background_agent.run(
78
+ user_prompt=[
79
+ f"The issue number to gather background information for is {issue_number}.",
80
+ ],
81
+ toolsets=[repo_restricted_toolset_factory(owner=owner, repo=repo)],
82
+ )
83
+
84
+ return result.output
85
+
86
+
87
+ gather_background_tool = Tool.from_function(fn=gather_background)
88
+
89
+ server.add_tool(tool=gather_background_tool)
90
+
91
+
92
+ def run():
93
+ server.run()
94
+
95
+
96
+ if __name__ == "__main__":
97
+ server.run(transport="sse")
@@ -0,0 +1,72 @@
1
+ from pathlib import Path
2
+
3
+ from fastmcp import FastMCP
4
+ from fastmcp.tools.tool import Tool
5
+ from fastmcp_ai_agent_bridge.pydantic_ai import FastMCPToolset
6
+ from pydantic import AnyHttpUrl
7
+
8
+ from fastmcp_agents.library.agent.github.gather_background import GitHubIssueSummary, gather_background, gather_background_tool
9
+ from fastmcp_agents.library.agent.github.respond_to_issue import respond_to_issue
10
+ from fastmcp_agents.library.agent.simple_code.investigate import InvestigationResponse, investigate_code, investigate_code_tool
11
+
12
+ fastmcp = FastMCP[None](name="github-issue-triage")
13
+
14
+ fastmcp.add_tool(gather_background_tool)
15
+ fastmcp.add_tool(investigate_code_tool)
16
+
17
+ toolset = FastMCPToolset(fastmcp=fastmcp)
18
+
19
+
20
+ async def investigate_github_issue(
21
+ *,
22
+ owner: str,
23
+ repo: str,
24
+ reply_to_owner: str | None = None,
25
+ reply_to_repo: str | None = None,
26
+ reply_to_issue_number: int | None = None,
27
+ code_path: Path | None = None,
28
+ issue_number: int,
29
+ reply_to_issue: bool,
30
+ ) -> tuple[GitHubIssueSummary, InvestigationResponse, str | None]:
31
+ issue_summary: GitHubIssueSummary = await gather_background(owner=owner, repo=repo, issue_number=issue_number)
32
+
33
+ code_repository: Path | AnyHttpUrl
34
+
35
+ if code_path:
36
+ code_repository = code_path
37
+ elif owner and repo:
38
+ code_repository = AnyHttpUrl(f"https://github.com/{owner}/{repo}.git")
39
+ else:
40
+ msg = "Either code_path or owner and repo must be provided"
41
+ raise ValueError(msg)
42
+
43
+ investigation_response: InvestigationResponse = await investigate_code(
44
+ task=issue_summary.detailed_summary,
45
+ code_repository=code_repository,
46
+ )
47
+
48
+ if not reply_to_issue:
49
+ return issue_summary, investigation_response, None
50
+
51
+ response = await respond_to_issue(
52
+ owner=reply_to_owner or owner,
53
+ repo=reply_to_repo or repo,
54
+ issue_number=reply_to_issue_number or issue_number,
55
+ issue_summary=issue_summary,
56
+ investigation=investigation_response,
57
+ )
58
+
59
+ return issue_summary, investigation_response, response
60
+
61
+
62
+ investigate_github_issue_tool = Tool.from_function(fn=investigate_github_issue)
63
+
64
+ fastmcp.add_tool(tool=investigate_github_issue_tool)
65
+
66
+
67
+ def run():
68
+ fastmcp.run()
69
+
70
+
71
+ if __name__ == "__main__":
72
+ fastmcp.run(transport="sse")
@@ -0,0 +1,98 @@
1
+ """
2
+ This agent is used to triage issues on a GitHub repository.
3
+ """
4
+
5
+ import os
6
+ from textwrap import dedent
7
+ from typing import Any
8
+
9
+ import yaml
10
+ from fastmcp import FastMCP
11
+ from fastmcp_ai_agent_bridge.pydantic_ai import FastMCPToolset
12
+ from pydantic_ai import Agent
13
+
14
+ from fastmcp_agents.library.agent.github.gather_background import GitHubIssueSummary
15
+ from fastmcp_agents.library.agent.github.shared.logging import configure_console_logging
16
+ from fastmcp_agents.library.agent.simple_code.investigate import InvestigationResponse
17
+ from fastmcp_agents.library.mcp.github import repo_restricted_github_mcp
18
+
19
+ configure_console_logging()
20
+
21
+ respond_instructions = """
22
+ ## Persona & Goal:
23
+ You are a helpful assistant to an open source maintainer. You receive a bunch of background about an issue
24
+ and a triage performed by another maintainer and you reponse on the issue.
25
+
26
+ {mindset_instructions}
27
+ {confidence_levels}
28
+ {section_guidelines}
29
+
30
+ Your goal is to reflect all of the details of the triage and background while producing a nicely formatted markdown response
31
+ in the GitHub comment. When you complete the task and report success include the body of the reponse of the comment.
32
+ """
33
+
34
+
35
+ def mcp_servers_factory(owner: str, repo: str) -> dict[str, Any]:
36
+ return {
37
+ "github": repo_restricted_github_mcp(
38
+ owner=owner,
39
+ repo=repo,
40
+ issues=True,
41
+ pull_requests=False,
42
+ discussions=False,
43
+ repository=False,
44
+ ),
45
+ }
46
+
47
+
48
+ def repo_restricted_toolset_factory(owner: str, repo: str) -> FastMCPToolset:
49
+ return FastMCPToolset.from_mcp_config(
50
+ mcp_config=mcp_servers_factory(
51
+ owner=owner,
52
+ repo=repo,
53
+ )
54
+ )
55
+
56
+
57
+ issue_response_agent = Agent[Any, str](
58
+ model=os.environ.get("MODEL"),
59
+ system_prompt=respond_instructions,
60
+ output_type=str,
61
+ )
62
+
63
+ server = FastMCP[None](name="respond-to-github-issue-background")
64
+
65
+
66
+ async def respond_to_issue(
67
+ owner: str,
68
+ repo: str,
69
+ issue_number: int,
70
+ issue_summary: GitHubIssueSummary,
71
+ investigation: InvestigationResponse | None = None,
72
+ ) -> str:
73
+ background_yaml = yaml.safe_dump(issue_summary.model_dump())
74
+ investigation_yaml = yaml.safe_dump(data=investigation.model_dump()) if investigation else None
75
+
76
+ task = dedent(
77
+ text=f"""The issue number to reply to is {issue_number}.
78
+
79
+ The background information is as follows:
80
+ {background_yaml}
81
+ """
82
+ ).strip()
83
+
84
+ if investigation:
85
+ task += dedent(
86
+ text=f"""
87
+ The investigation response is as follows:
88
+ {investigation_yaml}
89
+ """
90
+ ).strip()
91
+
92
+ run_result = await issue_response_agent.run(
93
+ user_prompt=task, toolsets=[repo_restricted_toolset_factory(owner=owner, repo=repo)], output_type=str
94
+ )
95
+
96
+ print(run_result.output)
97
+
98
+ return run_result.output
@@ -0,0 +1,2 @@
1
+ def get_repo_url(owner: str, repository: str) -> str:
2
+ return f"https://github.com/{owner}/{repository}.git"
@@ -0,0 +1,213 @@
1
+ from typing import Annotated, Literal
2
+
3
+ from fastmcp import Context
4
+ from fastmcp.tools import FunctionTool
5
+ from fastmcp.tools.tool import ToolResult
6
+ from fastmcp.tools.tool_transform import ArgTransform, TransformedTool
7
+
8
+ from fastmcp_agents.core.agents.base import FastMCPTool
9
+ from fastmcp_agents.core.utilities.mcp import get_text_from_tool_result
10
+
11
+ # async def get_issue(ctx: Context, owner: str, repo: str, issue_number: int) -> ToolResult:
12
+ # github_issue: ToolResult = await ctx.fastmcp._call_tool(
13
+ # "get_issue",
14
+ # arguments={
15
+ # "owner": owner,
16
+ # "repo": repo,
17
+ # "issue_number": issue_number,
18
+ # },
19
+ # )
20
+
21
+ # return github_issue
22
+
23
+
24
+ # async def get_issue_comments(ctx: Context, owner: str, repo: str, issue_number: int) -> ToolResult:
25
+ # github_issue_comments: ToolResult = await ctx.fastmcp._call_tool(
26
+ # "get_issue_comments",
27
+ # arguments={
28
+ # "owner": owner,
29
+ # "repo": repo,
30
+ # "per_page": 100,
31
+ # "issue_number": issue_number,
32
+ # },
33
+ # )
34
+
35
+ # return github_issue_comments
36
+
37
+
38
+ # class RelatedKeywords(BaseModel):
39
+ # keywords: list[str]
40
+
41
+
42
+ # class RelatedIssues(BaseModel):
43
+ # issue_numbers: list[int]
44
+
45
+
46
+ # async def related_issues_completion(ctx: Context, owner: str, repo: str, background: str) -> list[ContentBlock]:
47
+ # def provide_keywords(keywords: list[str]) -> RelatedKeywords:
48
+ # return RelatedKeywords(keywords=keywords)
49
+
50
+ # _, _, pending_tool_call = await ctx.completions.tool(
51
+ # system_prompt="""Review the background information for the following GitHub issue and provide a list of important
52
+ # keywords that can be used to search for related issues. Provide no more than 5 keywords.""",
53
+ # messages=background,
54
+ # tools=[FunctionTool.from_function(fn=provide_keywords)],
55
+ # )
56
+
57
+ # _, result = await pending_tool_call.run()
58
+
59
+ # if isinstance(result, ToolError):
60
+ # raise result
61
+
62
+ # keywords: list[str] = result.structured_content.get("keywords", []) if result.structured_content else []
63
+
64
+ # related_issues_search: ToolResult = await search_issues(ctx, owner, repo, keywords)
65
+
66
+ # def provide_issue_numbers(issue_numbers: list[int]) -> RelatedIssues:
67
+ # return RelatedIssues(issue_numbers=issue_numbers)
68
+
69
+ # _, _, pending_tool_call = await ctx.completions.tool(
70
+ # system_prompt="""
71
+ # Review the background information for the following GitHub issue and the provided list of search results and provide a
72
+ # list of likely related issue numbers from the search results.",
73
+ # """,
74
+ # messages=[
75
+ # background,
76
+ # str(related_issues_search.structured_content),
77
+ # ],
78
+ # tools=[FunctionTool.from_function(fn=provide_issue_numbers)],
79
+ # )
80
+
81
+ # _, result = await pending_tool_call.run()
82
+
83
+ # if isinstance(result, ToolError):
84
+ # raise result
85
+
86
+ # issue_numbers: list[int] = result.structured_content.get("issue_numbers", []) if result.structured_content else []
87
+
88
+ # related_issues: list[ToolResult] = [await get_issue(ctx, owner, repo, issue_number) for issue_number in issue_numbers]
89
+
90
+ # issues: list[ContentBlock] = []
91
+
92
+ # for related_issue in related_issues:
93
+ # issues.extend(related_issue.content)
94
+
95
+ # return issues
96
+
97
+
98
+ async def search_issues(
99
+ ctx: Context,
100
+ owner: str,
101
+ repo: str,
102
+ keywords: Annotated[list[str], "The keywords to search for. Maximum of 5 keywords."],
103
+ state: Literal["all", "open", "closed"] = "all",
104
+ ) -> ToolResult:
105
+ """Search for issues by keyword in a GitHub repo. If more than 5 keywords are provided, only the first 5 will be used."""
106
+
107
+ search_query_parts: list[str] = ["is:issue", f"repo:{owner}/{repo}"]
108
+
109
+ if state == "open":
110
+ search_query_parts.append("state:open")
111
+ elif state == "closed":
112
+ search_query_parts.append("state:closed")
113
+
114
+ search_query_parts.append(" OR ".join(keywords[:5]))
115
+
116
+ github_issues: ToolResult = await ctx.fastmcp._call_tool(
117
+ "search_issues",
118
+ arguments={
119
+ "q": " ".join(search_query_parts),
120
+ },
121
+ )
122
+
123
+ return github_issues
124
+
125
+
126
+ search_issues_tool = FunctionTool.from_function(fn=search_issues)
127
+
128
+
129
+ async def get_issue_background(
130
+ tools: dict[str, FastMCPTool],
131
+ owner: str,
132
+ repo: str,
133
+ issue_number: int,
134
+ ) -> tuple[str, str]:
135
+ get_issue_tool: FastMCPTool | None = tools.get("get_issue")
136
+
137
+ if get_issue_tool is None:
138
+ msg = "get_issue tool not found"
139
+ raise ValueError(msg)
140
+
141
+ get_issue_comments_tool: FastMCPTool | None = tools.get("get_issue_comments")
142
+
143
+ if get_issue_comments_tool is None:
144
+ msg = "get_issue_comments tool not found"
145
+ raise ValueError(msg)
146
+
147
+ issue = await get_issue_tool.run(arguments={"owner": owner, "repo": repo, "issue_number": issue_number})
148
+
149
+ issue_content: str = get_text_from_tool_result(issue)
150
+
151
+ comments = await get_issue_comments_tool.run(arguments={"owner": owner, "repo": repo, "issue_number": issue_number})
152
+
153
+ comments_content: str = get_text_from_tool_result(comments)
154
+
155
+ return issue_content, comments_content
156
+
157
+
158
+ def owner_repo_args_transform_factory(owner: str, repo: str) -> dict[str, ArgTransform]:
159
+ return {
160
+ "owner": ArgTransform(default=owner, hide=True),
161
+ "repo": ArgTransform(default=repo, hide=True),
162
+ }
163
+
164
+
165
+ async def restricted_get_issue_tool_factory(tools: dict[str, FastMCPTool], owner: str, repo: str) -> TransformedTool:
166
+ if get_issue_tool := tools.get("get_issue"):
167
+ return TransformedTool.from_tool(
168
+ get_issue_tool,
169
+ transform_args=owner_repo_args_transform_factory(owner, repo),
170
+ )
171
+
172
+ msg = "get_issue tool not found"
173
+ raise ValueError(msg)
174
+
175
+
176
+ async def restricted_get_pull_request_tool_factory(tools: dict[str, FastMCPTool], owner: str, repo: str) -> TransformedTool:
177
+ if get_pull_request_tool := tools.get("get_pull_request"):
178
+ return TransformedTool.from_tool(
179
+ get_pull_request_tool,
180
+ transform_args=owner_repo_args_transform_factory(owner, repo),
181
+ )
182
+
183
+ msg = "get_pull_request tool not found"
184
+ raise ValueError(msg)
185
+
186
+
187
+ async def restricted_search_issues_tool_factory(owner: str, repo: str) -> TransformedTool:
188
+ return TransformedTool.from_tool(
189
+ search_issues_tool,
190
+ transform_args=owner_repo_args_transform_factory(owner, repo),
191
+ )
192
+
193
+
194
+ def generate_background(issue_content: str, comments_content: str, extra: str | None = None) -> str:
195
+ """Generate a background for an issue."""
196
+ background: str = f"""
197
+ An issue has been reported in the repo.
198
+
199
+ ```markdown
200
+ {issue_content}
201
+ ```
202
+
203
+ There may be some discussion in the issue comments.
204
+
205
+ ```markdown
206
+ {comments_content}
207
+ ```
208
+ """
209
+
210
+ if extra:
211
+ background += f"\n\n{extra}"
212
+
213
+ return background
@@ -0,0 +1,113 @@
1
+ import json
2
+ from datetime import UTC, datetime
3
+
4
+ import logfire
5
+ from logfire import ConsoleOptions
6
+ from opentelemetry.sdk.trace import ReadableSpan
7
+ from opentelemetry.sdk.trace.export import ConsoleSpanExporter, SimpleSpanProcessor
8
+ from pydantic_ai import Agent
9
+
10
+
11
+ def get_tool_names_from_span(span: ReadableSpan) -> list[str]:
12
+ if not span.attributes:
13
+ return []
14
+
15
+ if not (model_request_parameters := span.attributes.get("model_request_parameters")):
16
+ return []
17
+
18
+ if not isinstance(model_request_parameters, str):
19
+ return []
20
+
21
+ deserialized_model_request_parameters = json.loads(model_request_parameters)
22
+
23
+ if not (function_tools := deserialized_model_request_parameters.get("function_tools")):
24
+ return []
25
+
26
+ return [tool["name"] for tool in function_tools]
27
+
28
+
29
+ def get_picked_tools_from_span(span: ReadableSpan) -> list[str]:
30
+ if not span.attributes:
31
+ return []
32
+
33
+ if not (events := span.attributes.get("events")):
34
+ return []
35
+
36
+ if not isinstance(events, str):
37
+ return []
38
+
39
+ deserialized_events = json.loads(events)
40
+
41
+ assistant_event = deserialized_events[-1]
42
+
43
+ if not (message := assistant_event.get("message")):
44
+ return []
45
+
46
+ if not (tool_calls := message.get("tool_calls")):
47
+ return []
48
+
49
+ return [
50
+ tool_call.get(
51
+ "function",
52
+ {},
53
+ ).get(
54
+ "name",
55
+ "<unknown>",
56
+ )
57
+ for tool_call in tool_calls
58
+ if tool_call.get("type") == "function"
59
+ ]
60
+
61
+
62
+ ADDT_FORMAT_SPAN_NAMES = {"running tool"}
63
+
64
+
65
+ def format_span(span: ReadableSpan) -> str:
66
+ timestamp: datetime | None = datetime.fromtimestamp(span.start_time / 1_000_000_000, tz=UTC) if span.start_time else None
67
+
68
+ span_message = span.name
69
+
70
+ message = "{timestamp} - {span_message}\n"
71
+ default_message = message.format(timestamp=timestamp, span_message=span_message)
72
+
73
+ if not span.attributes:
74
+ return default_message
75
+
76
+ if not span.name.startswith("chat ") and span.name not in ADDT_FORMAT_SPAN_NAMES:
77
+ return default_message
78
+
79
+ match span.name:
80
+ case "running tool":
81
+ model_name: str | None = str(span.attributes.get("gen_ai.request.model"))
82
+ tool_name: str | None = str(span.attributes.get("gen_ai.tool.name"))
83
+ tool_arguments: str | None = str(span.attributes.get("tool_arguments"))
84
+ tool_response: str | None = str(span.attributes.get("tool_response"))
85
+
86
+ span_message = f"Model called {tool_name} with arguments: {tool_arguments} returned: {tool_response[:200]}"
87
+
88
+ case _ if span.name.startswith("chat "):
89
+ model_name: str | None = str(span.attributes.get("gen_ai.request.model"))
90
+ # tool_names: list[str] = get_tool_names_from_span(span)
91
+ picked_tools: list[str] = get_picked_tools_from_span(span)
92
+ span_message = f"Model: {model_name} -- Picked tools: {picked_tools}"
93
+
94
+ case _:
95
+ span_message = span.name
96
+
97
+ return message.format(timestamp=timestamp, span_message=span_message)
98
+
99
+
100
+ def configure_console_logging():
101
+ Agent.instrument_all()
102
+
103
+ _ = logfire.configure(
104
+ send_to_logfire=False,
105
+ console=ConsoleOptions(),
106
+ additional_span_processors=[
107
+ SimpleSpanProcessor(
108
+ span_exporter=ConsoleSpanExporter(
109
+ formatter=format_span,
110
+ )
111
+ )
112
+ ],
113
+ )
@@ -0,0 +1,16 @@
1
+ import os
2
+
3
+ github_mcp_server = {
4
+ "command": "docker",
5
+ "args": [
6
+ "run",
7
+ "-i",
8
+ "--rm",
9
+ "-e",
10
+ "GITHUB_PERSONAL_ACCESS_TOKEN",
11
+ "ghcr.io/github/github-mcp-server",
12
+ ],
13
+ "env": {
14
+ "GITHUB_PERSONAL_ACCESS_TOKEN": os.getenv("GITHUB_PERSONAL_ACCESS_TOKEN"),
15
+ },
16
+ }
@@ -0,0 +1,38 @@
1
+ confidence_levels = """
2
+ ## Confidence Levels and Presentation:
3
+ * High Confidence (90-100%):
4
+ - Present findings directly in the main response
5
+ - Provide clear evidence and explanations
6
+ - Include specific code references
7
+ * Medium Confidence (50-89%):
8
+ - Present findings in the main response
9
+ - Clearly state confidence level
10
+ - Explain why you're not completely certain
11
+ * Low Confidence (0-49%):
12
+ - Hide findings in an expandable section using GitHub's details/summary syntax:
13
+ ```markdown
14
+ <details>
15
+ <summary>Low Confidence Findings (Click to expand)</summary>
16
+
17
+ [Your low confidence findings here]
18
+ </details>
19
+ ```
20
+ - Explain why confidence is low
21
+ - Suggest what additional information would increase confidence
22
+ """
23
+
24
+ mindset_instructions = """
25
+ ## Mindset: Approach each task with:
26
+ * Accuracy - ensure findings are truly relevant
27
+ * Clarity - present findings in a clear, organized manner
28
+ * Honesty - be explicit about confidence levels and hide low confidence findings in expandable sections
29
+ """
30
+
31
+ section_guidelines = """
32
+ ## Section Guidelines:
33
+ * Only include sections that are relevant to the current task
34
+ * Skip sections where you have no findings or insights to share
35
+ * If a section would be empty, omit it entirely rather than including it with no content
36
+ * Focus on quality over quantity - better to have fewer, well-analyzed sections than many empty ones
37
+ * If you're unsure whether a section is relevant, err on the side of omitting it
38
+ """
@@ -1,10 +1,12 @@
1
- Metadata-Version: 2.4
1
+ Metadata-Version: 2.3
2
2
  Name: fastmcp-agents-library-agent-github
3
- Version: 0.5.1
3
+ Version: 0.5.5
4
4
  Summary: Agents for GitHub
5
- Requires-Python: >=3.13
6
5
  Requires-Dist: asyncstdlib>=3.13.1
7
6
  Requires-Dist: fastmcp-agents-library-agent-simple-code
8
7
  Requires-Dist: fastmcp-agents-library-mcp
9
8
  Requires-Dist: fastmcp-ai-agent-bridge-pydantic-ai>=0.1.2
10
9
  Requires-Dist: gitpython>=3.1.44
10
+ Requires-Python: >=3.13
11
+ Description-Content-Type: text/markdown
12
+
@@ -0,0 +1,13 @@
1
+ fastmcp_agents/library/agent/github/__init__.py,sha256=e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855,0
2
+ fastmcp_agents/library/agent/github/gather_background.py,sha256=6aa1d908a36f54cbdd437994109fd7994c94494fa962802ad94b2a5024ae0238,2903
3
+ fastmcp_agents/library/agent/github/investigate_issue.py,sha256=6841d9926ffea3908782075bb01555f938c3d0e915cf8fb8d526d5802171bf7a,2283
4
+ fastmcp_agents/library/agent/github/respond_to_issue.py,sha256=0d0a9b5712a66d5eabdf7a2c1db5a596ffdd962e491593df4d07010c3ec86e79,2848
5
+ fastmcp_agents/library/agent/github/shared/git.py,sha256=200e22082c2ae038895dea85b08e10f42f071f56ae802b672dba51fd2158b7e8,112
6
+ fastmcp_agents/library/agent/github/shared/helpers.py,sha256=4d4a39922c829675678d2a362957f91146938a7c2dfd4bd2bbbe5e1f905c5ee4,6904
7
+ fastmcp_agents/library/agent/github/shared/logging.py,sha256=788f61791cb02232ca2d4f30575441751c8b87d2b6993615c9a546954a219df9,3436
8
+ fastmcp_agents/library/agent/github/shared/mcp.py,sha256=f19ca673a531953a70bc51043e138e48a2c6d90d751e0558442f1511f2837d41,327
9
+ fastmcp_agents/library/agent/github/shared/prompts.py,sha256=eaae4fcbb1603d79540fc5174138d543c00e6df5f4c1ec33fe8489bd23c59896,1495
10
+ fastmcp_agents_library_agent_github-0.5.5.dist-info/WHEEL,sha256=03f80d698bb4300c27bcafc3987ea73ef427fcb365e59e808e50d041a7f87b89,78
11
+ fastmcp_agents_library_agent_github-0.5.5.dist-info/entry_points.txt,sha256=4a99925805bb82d01b31152188036ecd8c968048a4d5cdc8055fc359d488d6f7,189
12
+ fastmcp_agents_library_agent_github-0.5.5.dist-info/METADATA,sha256=adc1c310b828fab791c397f29dabeded92325acfdbc0d4698f2511b0c60a7a10,395
13
+ fastmcp_agents_library_agent_github-0.5.5.dist-info/RECORD,,
@@ -0,0 +1,4 @@
1
+ Wheel-Version: 1.0
2
+ Generator: uv 0.8.2
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
@@ -0,0 +1,4 @@
1
+ [console_scripts]
2
+ github-gather-background = fastmcp_agents.library.agent.github.gather_background:run
3
+ github-investigate-issue = fastmcp_agents.library.agent.github.investigate_issue:run
4
+
@@ -1,4 +0,0 @@
1
- fastmcp_agents_library_agent_github-0.5.1.dist-info/METADATA,sha256=Xo0H-I_nBPa7mpzPRqxAWqC8MAQLk5Pzp_OcSPkI30o,354
2
- fastmcp_agents_library_agent_github-0.5.1.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
3
- fastmcp_agents_library_agent_github-0.5.1.dist-info/entry_points.txt,sha256=Co3KZ71gxHFiJ32ukLPTXedx5xvMAkrlo3RElZbnp2c,180
4
- fastmcp_agents_library_agent_github-0.5.1.dist-info/RECORD,,
@@ -1,4 +0,0 @@
1
- Wheel-Version: 1.0
2
- Generator: hatchling 1.27.0
3
- Root-Is-Purelib: true
4
- Tag: py3-none-any
@@ -1,3 +0,0 @@
1
- [console_scripts]
2
- github-gather-background = fastmcp_agents.library.agent.github.gather_background:main
3
- github-issue-triage = fastmcp_agents.library.agent.github.issue_triage:main