github-agent 0.2.4__tar.gz → 0.2.6__tar.gz

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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: github-agent
3
- Version: 0.2.4
3
+ Version: 0.2.6
4
4
  Summary: GitHub Agent for MCP
5
5
  Author-email: Audel Rouhi <knucklessg1@gmail.com>
6
6
  License: MIT
@@ -43,7 +43,7 @@ Dynamic: license-file
43
43
  ![PyPI - Wheel](https://img.shields.io/pypi/wheel/github-agent)
44
44
  ![PyPI - Implementation](https://img.shields.io/pypi/implementation/github-agent)
45
45
 
46
- *Version: 0.2.4*
46
+ *Version: 0.2.6*
47
47
 
48
48
  ## Overview
49
49
 
@@ -21,7 +21,7 @@
21
21
  ![PyPI - Wheel](https://img.shields.io/pypi/wheel/github-agent)
22
22
  ![PyPI - Implementation](https://img.shields.io/pypi/implementation/github-agent)
23
23
 
24
- *Version: 0.2.4*
24
+ *Version: 0.2.6*
25
25
 
26
26
  ## Overview
27
27
 
@@ -7,6 +7,7 @@ import os
7
7
  import argparse
8
8
  import logging
9
9
  import uvicorn
10
+ import httpx
10
11
  from typing import Optional, Any
11
12
  from contextlib import asynccontextmanager
12
13
 
@@ -38,7 +39,7 @@ from pydantic import ValidationError
38
39
  from pydantic_ai.ui import SSE_CONTENT_TYPE
39
40
  from pydantic_ai.ui.ag_ui import AGUIAdapter
40
41
 
41
- __version__ = "0.2.4"
42
+ __version__ = "0.2.6"
42
43
 
43
44
  logging.basicConfig(
44
45
  level=logging.INFO,
@@ -63,7 +64,6 @@ DEFAULT_SKILLS_DIRECTORY = os.getenv("SKILLS_DIRECTORY", get_skills_path())
63
64
  DEFAULT_ENABLE_WEB_UI = to_boolean(os.getenv("ENABLE_WEB_UI", "False"))
64
65
  DEFAULT_SSL_VERIFY = to_boolean(os.getenv("SSL_VERIFY", "True"))
65
66
 
66
- # Model Settings
67
67
  DEFAULT_MAX_TOKENS = to_integer(os.getenv("MAX_TOKENS", "16384"))
68
68
  DEFAULT_TEMPERATURE = to_float(os.getenv("TEMPERATURE", "0.7"))
69
69
  DEFAULT_TOP_P = to_float(os.getenv("TOP_P", "1.0"))
@@ -83,9 +83,6 @@ AGENT_DESCRIPTION = (
83
83
  "A multi-agent system for interacting with GitHub via delegated specialists."
84
84
  )
85
85
 
86
- # -------------------------------------------------------------------------
87
- # 1. System Prompts
88
- # -------------------------------------------------------------------------
89
86
 
90
87
  SUPERVISOR_SYSTEM_PROMPT = os.environ.get(
91
88
  "SUPERVISOR_SYSTEM_PROMPT",
@@ -264,16 +261,12 @@ SUPPORT_DOCS_AGENT_PROMPT = os.environ.get(
264
261
  ),
265
262
  )
266
263
 
267
- # -------------------------------------------------------------------------
268
- # 2. Agent Creation Logic
269
- # -------------------------------------------------------------------------
270
-
271
264
 
272
265
  def create_agent(
273
266
  provider: str = DEFAULT_PROVIDER,
274
267
  model_id: str = DEFAULT_MODEL_ID,
275
- base_url: Optional[str] = None,
276
- api_key: Optional[str] = None,
268
+ base_url: Optional[str] = DEFAULT_LLM_BASE_URL,
269
+ api_key: Optional[str] = DEFAULT_LLM_API_KEY,
277
270
  mcp_url: str = DEFAULT_MCP_URL,
278
271
  mcp_config: str = DEFAULT_MCP_CONFIG,
279
272
  skills_directory: Optional[str] = DEFAULT_SKILLS_DIRECTORY,
@@ -306,25 +299,29 @@ def create_agent(
306
299
  extra_body=DEFAULT_EXTRA_BODY,
307
300
  )
308
301
 
309
- # Load master toolsets
310
302
  agent_toolsets = []
311
303
  if mcp_url:
312
304
  if "sse" in mcp_url.lower():
313
- server = MCPServerSSE(mcp_url)
305
+ server = MCPServerSSE(
306
+ mcp_url, http_client=httpx.AsyncClient(verify=ssl_verify)
307
+ )
314
308
  else:
315
- server = MCPServerStreamableHTTP(mcp_url)
309
+ server = MCPServerStreamableHTTP(
310
+ mcp_url, http_client=httpx.AsyncClient(verify=ssl_verify)
311
+ )
316
312
  agent_toolsets.append(server)
317
313
  logger.info(f"Connected to MCP Server: {mcp_url}")
318
314
  elif mcp_config:
319
315
  mcp_toolset = load_mcp_servers(mcp_config)
316
+ for server in mcp_toolset:
317
+ if hasattr(server, "http_client"):
318
+ server.http_client = httpx.AsyncClient(verify=ssl_verify)
320
319
  agent_toolsets.extend(mcp_toolset)
321
320
  logger.info(f"Connected to MCP Config JSON: {mcp_toolset}")
322
321
 
323
322
  if skills_directory and os.path.exists(skills_directory):
324
323
  agent_toolsets.append(SkillsToolset(directories=[str(skills_directory)]))
325
324
 
326
- # Define Tag -> Prompt map
327
- # Key is the MCP Tool Tag (or set of tags), Value is (SystemPrompt, AgentName)
328
325
  agent_defs = {
329
326
  "person": (CONTEXT_AGENT_PROMPT, "GitHub_Context_Agent"),
330
327
  "workflow": (ACTIONS_AGENT_PROMPT, "GitHub_Actions_Agent"),
@@ -383,7 +380,6 @@ def create_agent(
383
380
  )
384
381
  child_agents[tag] = agent
385
382
 
386
- # Create Supervisor
387
383
  supervisor = Agent(
388
384
  name=AGENT_NAME,
389
385
  system_prompt=SUPERVISOR_SYSTEM_PROMPT,
@@ -392,9 +388,6 @@ def create_agent(
392
388
  deps_type=Any,
393
389
  )
394
390
 
395
- # Define delegation tools
396
- # We define these explicitly to give the Supervisor clear, typed tools.
397
-
398
391
  @supervisor.tool
399
392
  async def assign_task_to_context_agent(ctx: RunContext[Any], task: str) -> str:
400
393
  """Assign a task related to user context and general GitHub status to the Context Agent."""
@@ -570,8 +563,8 @@ def create_agent(
570
563
  def create_agent_server(
571
564
  provider: str = DEFAULT_PROVIDER,
572
565
  model_id: str = DEFAULT_MODEL_ID,
573
- base_url: Optional[str] = None,
574
- api_key: Optional[str] = None,
566
+ base_url: Optional[str] = DEFAULT_LLM_BASE_URL,
567
+ api_key: Optional[str] = DEFAULT_LLM_API_KEY,
575
568
  mcp_url: str = DEFAULT_MCP_URL,
576
569
  mcp_config: str = DEFAULT_MCP_CONFIG,
577
570
  skills_directory: Optional[str] = DEFAULT_SKILLS_DIRECTORY,
@@ -582,7 +575,12 @@ def create_agent_server(
582
575
  ssl_verify: bool = DEFAULT_SSL_VERIFY,
583
576
  ):
584
577
  print(
585
- f"Starting {AGENT_NAME} with provider={provider}, model={model_id}, mcp={mcp_url} | {mcp_config}"
578
+ f"Starting {AGENT_NAME}:"
579
+ f"\tprovider={provider}"
580
+ f"\tmodel={model_id}"
581
+ f"\tbase_url={base_url}"
582
+ f"\tmcp={mcp_url} | {mcp_config}"
583
+ f"\tssl_verify={ssl_verify}"
586
584
  )
587
585
  agent = create_agent(
588
586
  provider=provider,
@@ -651,7 +649,6 @@ def create_agent_server(
651
649
  status_code=422,
652
650
  )
653
651
 
654
- # Prune large messages from history
655
652
  if hasattr(run_input, "messages"):
656
653
  run_input.messages = prune_large_messages(run_input.messages)
657
654
 
@@ -726,6 +723,12 @@ def agent_server():
726
723
  default=DEFAULT_ENABLE_WEB_UI,
727
724
  help="Enable Pydantic AI Web UI",
728
725
  )
726
+
727
+ parser.add_argument(
728
+ "--insecure",
729
+ action="store_true",
730
+ help="Disable SSL verification for LLM requests (Use with caution)",
731
+ )
729
732
  parser.add_argument("--help", action="store_true", help="Show usage")
730
733
 
731
734
  args = parser.parse_args()
@@ -3,7 +3,6 @@
3
3
 
4
4
  import os
5
5
 
6
- # Try importing specific clients/providers, but don't fail if variables are missing
7
6
  try:
8
7
 
9
8
  from openai import AsyncOpenAI
@@ -128,22 +127,17 @@ def prune_large_messages(messages: list[Any], max_length: int = 5000) -> list[An
128
127
  f"... {content[-200:]}"
129
128
  )
130
129
 
131
- # Replace content
132
130
  if isinstance(msg, dict):
133
131
  msg["content"] = summary
134
132
  pruned_messages.append(msg)
135
133
  elif hasattr(msg, "content"):
136
- # Try to create a copy or modify in place if mutable
137
- # If it's a Pydantic model it might be immutable or require copy
138
134
  try:
139
- # Attempt shallow copy with update
140
135
  from copy import copy
141
136
 
142
137
  new_msg = copy(msg)
143
138
  new_msg.content = summary
144
139
  pruned_messages.append(new_msg)
145
140
  except Exception:
146
- # Fallback: keep original if we can't modify
147
141
  pruned_messages.append(msg)
148
142
  else:
149
143
  pruned_messages.append(msg)
@@ -218,7 +212,6 @@ def load_skills_from_directory(directory: str) -> List[Skill]:
218
212
  if skill_file.exists():
219
213
  try:
220
214
  with open(skill_file, "r") as f:
221
- # Extract frontmatter
222
215
  content = f.read()
223
216
  if content.startswith("---"):
224
217
  _, frontmatter, _ = content.split("---", 2)
@@ -254,8 +247,8 @@ def get_http_client(ssl_verify: bool = True) -> httpx.AsyncClient | None:
254
247
  def create_model(
255
248
  provider: str,
256
249
  model_id: str,
257
- base_url: Optional[str] = None,
258
- api_key: Optional[str] = None,
250
+ base_url: Optional[str],
251
+ api_key: Optional[str],
259
252
  ssl_verify: bool = True,
260
253
  ):
261
254
  """
@@ -271,7 +264,6 @@ def create_model(
271
264
  Returns:
272
265
  A Pydantic AI Model instance
273
266
  """
274
- # Create a custom HTTP client if SSL verification is disabled
275
267
  http_client = None
276
268
  if not ssl_verify:
277
269
  http_client = httpx.AsyncClient(verify=False)
@@ -280,7 +272,6 @@ def create_model(
280
272
  target_base_url = base_url
281
273
  target_api_key = api_key
282
274
 
283
- # If we have a custom client or specific settings, we might want to use the explicit provider object
284
275
  if http_client and AsyncOpenAI and OpenAIProvider:
285
276
  client = AsyncOpenAI(
286
277
  api_key=target_api_key or os.environ.get("OPENAI_API_KEY"),
@@ -290,7 +281,6 @@ def create_model(
290
281
  provider_instance = OpenAIProvider(openai_client=client)
291
282
  return OpenAIChatModel(model_name=model_id, provider=provider_instance)
292
283
 
293
- # Fallback to standard env vars
294
284
  if target_base_url:
295
285
  os.environ["OPENAI_BASE_URL"] = target_base_url
296
286
  if target_api_key:
@@ -298,7 +288,6 @@ def create_model(
298
288
  return OpenAIChatModel(model_name=model_id, provider="openai")
299
289
 
300
290
  elif provider == "ollama":
301
- # Ollama is OpenAI compatible
302
291
  target_base_url = base_url or "http://localhost:11434/v1"
303
292
  target_api_key = api_key or "ollama"
304
293
 
@@ -319,9 +308,6 @@ def create_model(
319
308
  if api_key:
320
309
  os.environ["ANTHROPIC_API_KEY"] = api_key
321
310
 
322
- # AnthropicModel supports http_client directly via some paths,
323
- # but pydantic-ai might prefer we pass the client to the provider or use a custom client
324
-
325
311
  try:
326
312
  if http_client and AsyncAnthropic and AnthropicProvider:
327
313
  client = AsyncAnthropic(
@@ -338,7 +324,6 @@ def create_model(
338
324
  elif provider == "google":
339
325
  if api_key:
340
326
  os.environ["GEMINI_API_KEY"] = api_key
341
- # Google SSL disable is tricky with genai, skipping for now unless specifically requested/researched
342
327
  return GoogleModel(model_name=model_id)
343
328
 
344
329
  elif provider == "groq":
@@ -360,12 +345,7 @@ def create_model(
360
345
  os.environ["MISTRAL_API_KEY"] = api_key
361
346
 
362
347
  if http_client and Mistral and MistralProvider:
363
- # Assuming mistral_client argument for MistralProvider
364
- # Ideally we would verify this, but we'll try standard pattern
365
348
  pass
366
- # client = Mistral(...) - Mistral SDK might be different
367
- # Skipping Mistral custom client for now to avoid breaking without verification
368
- # If user needs Mistral SSL disable, we'll need to research Mistral SDK + Provider
369
349
 
370
350
  return MistralModel(model_name=model_id)
371
351
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: github-agent
3
- Version: 0.2.4
3
+ Version: 0.2.6
4
4
  Summary: GitHub Agent for MCP
5
5
  Author-email: Audel Rouhi <knucklessg1@gmail.com>
6
6
  License: MIT
@@ -43,7 +43,7 @@ Dynamic: license-file
43
43
  ![PyPI - Wheel](https://img.shields.io/pypi/wheel/github-agent)
44
44
  ![PyPI - Implementation](https://img.shields.io/pypi/implementation/github-agent)
45
45
 
46
- *Version: 0.2.4*
46
+ *Version: 0.2.6*
47
47
 
48
48
  ## Overview
49
49
 
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "github-agent"
7
- version = "0.2.4"
7
+ version = "0.2.6"
8
8
  readme = "README.md"
9
9
  description = "GitHub Agent for MCP"
10
10
  requires-python = ">=3.10"
File without changes
File without changes