github-agent 0.2.1__tar.gz → 0.2.2__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.1
3
+ Version: 0.2.2
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.1*
46
+ *Version: 0.2.2*
47
47
 
48
48
  ## Overview
49
49
 
@@ -172,7 +172,7 @@ The `github-agent` command starts the server.
172
172
  | `--port` | Port to bind the server to | `9000` |
173
173
  | `--mcp-config` | Path to MCP configuration file | `mcp_config.json` |
174
174
  | `--provider` | LLM Provider (openai, anthropic, google, etc.) | `openai` |
175
- | `--model-id` | LLM Model ID | `qwen/qwen3-4b-2507` |
175
+ | `--model-id` | LLM Model ID | `qwen/qwen3-coder-next` |
176
176
 
177
177
  ### Running the Agent Server
178
178
 
@@ -193,7 +193,7 @@ docker build -t github-agent .
193
193
  ```bash
194
194
  docker run -d \
195
195
  -p 9000:9000 \
196
- -e OPENAI_API_KEY=sk-... \
196
+ -e LLM_API_KEY=sk-... \
197
197
  -e MCP_CONFIG=/app/mcp_config.json \
198
198
  knucklessg1/github-agent:latest
199
199
  ```
@@ -211,7 +211,7 @@ services:
211
211
  environment:
212
212
  - PROVIDER=openai
213
213
  - MODEL_ID=gpt-4o
214
- - OPENAI_API_KEY=${OPENAI_API_KEY}
214
+ - LLM_API_KEY=${LLM_API_KEY}
215
215
  volumes:
216
216
  - ./mcp_config.json:/app/mcp_config.json
217
217
  ```
@@ -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.1*
24
+ *Version: 0.2.2*
25
25
 
26
26
  ## Overview
27
27
 
@@ -150,7 +150,7 @@ The `github-agent` command starts the server.
150
150
  | `--port` | Port to bind the server to | `9000` |
151
151
  | `--mcp-config` | Path to MCP configuration file | `mcp_config.json` |
152
152
  | `--provider` | LLM Provider (openai, anthropic, google, etc.) | `openai` |
153
- | `--model-id` | LLM Model ID | `qwen/qwen3-4b-2507` |
153
+ | `--model-id` | LLM Model ID | `qwen/qwen3-coder-next` |
154
154
 
155
155
  ### Running the Agent Server
156
156
 
@@ -171,7 +171,7 @@ docker build -t github-agent .
171
171
  ```bash
172
172
  docker run -d \
173
173
  -p 9000:9000 \
174
- -e OPENAI_API_KEY=sk-... \
174
+ -e LLM_API_KEY=sk-... \
175
175
  -e MCP_CONFIG=/app/mcp_config.json \
176
176
  knucklessg1/github-agent:latest
177
177
  ```
@@ -189,7 +189,7 @@ services:
189
189
  environment:
190
190
  - PROVIDER=openai
191
191
  - MODEL_ID=gpt-4o
192
- - OPENAI_API_KEY=${OPENAI_API_KEY}
192
+ - LLM_API_KEY=${LLM_API_KEY}
193
193
  volumes:
194
194
  - ./mcp_config.json:/app/mcp_config.json
195
195
  ```
@@ -11,7 +11,11 @@ from typing import Optional, Any
11
11
  from contextlib import asynccontextmanager
12
12
 
13
13
  from pydantic_ai import Agent, ModelSettings, RunContext
14
- from pydantic_ai.mcp import load_mcp_servers, MCPServerStreamableHTTP, MCPServerSSE
14
+ from pydantic_ai.mcp import (
15
+ load_mcp_servers,
16
+ MCPServerStreamableHTTP,
17
+ MCPServerSSE,
18
+ )
15
19
  from pydantic_ai_skills import SkillsToolset
16
20
  from fasta2a import Skill
17
21
  from github_agent.utils import (
@@ -34,7 +38,7 @@ from pydantic import ValidationError
34
38
  from pydantic_ai.ui import SSE_CONTENT_TYPE
35
39
  from pydantic_ai.ui.ag_ui import AGUIAdapter
36
40
 
37
- __version__ = "0.2.1"
41
+ __version__ = "0.2.2"
38
42
 
39
43
  logging.basicConfig(
40
44
  level=logging.INFO,
@@ -50,18 +54,17 @@ DEFAULT_HOST = os.getenv("HOST", "0.0.0.0")
50
54
  DEFAULT_PORT = to_integer(string=os.getenv("PORT", "9000"))
51
55
  DEFAULT_DEBUG = to_boolean(string=os.getenv("DEBUG", "False"))
52
56
  DEFAULT_PROVIDER = os.getenv("PROVIDER", "openai")
53
- DEFAULT_MODEL_ID = os.getenv("MODEL_ID", "qwen/qwen3-4b-2507")
54
- DEFAULT_OPENAI_BASE_URL = os.getenv(
55
- "OPENAI_BASE_URL", "http://host.docker.internal:1234/v1"
56
- )
57
- DEFAULT_OPENAI_API_KEY = os.getenv("OPENAI_API_KEY", "ollama")
57
+ DEFAULT_MODEL_ID = os.getenv("MODEL_ID", "qwen/qwen3-coder-next")
58
+ DEFAULT_LLM_BASE_URL = os.getenv("LLM_BASE_URL", "http://host.docker.internal:1234/v1")
59
+ DEFAULT_LLM_API_KEY = os.getenv("LLM_API_KEY", "ollama")
58
60
  DEFAULT_MCP_URL = os.getenv("MCP_URL", None)
59
61
  DEFAULT_MCP_CONFIG = os.getenv("MCP_CONFIG", get_mcp_config_path())
60
62
  DEFAULT_SKILLS_DIRECTORY = os.getenv("SKILLS_DIRECTORY", get_skills_path())
61
63
  DEFAULT_ENABLE_WEB_UI = to_boolean(os.getenv("ENABLE_WEB_UI", "False"))
64
+ DEFAULT_SSL_VERIFY = to_boolean(os.getenv("SSL_VERIFY", "True"))
62
65
 
63
66
  # Model Settings
64
- DEFAULT_MAX_TOKENS = to_integer(os.getenv("MAX_TOKENS", "8192"))
67
+ DEFAULT_MAX_TOKENS = to_integer(os.getenv("MAX_TOKENS", "16384"))
65
68
  DEFAULT_TEMPERATURE = to_float(os.getenv("TEMPERATURE", "0.7"))
66
69
  DEFAULT_TOP_P = to_float(os.getenv("TOP_P", "1.0"))
67
70
  DEFAULT_TIMEOUT = to_float(os.getenv("TIMEOUT", "32400.0"))
@@ -274,13 +277,20 @@ def create_agent(
274
277
  mcp_url: str = DEFAULT_MCP_URL,
275
278
  mcp_config: str = DEFAULT_MCP_CONFIG,
276
279
  skills_directory: Optional[str] = DEFAULT_SKILLS_DIRECTORY,
280
+ ssl_verify: bool = DEFAULT_SSL_VERIFY,
277
281
  ) -> Agent:
278
282
  """
279
283
  Creates the Supervisor Agent with sub-agents registered as tools.
280
284
  """
281
285
  logger.info("Initializing Multi-Agent System for GitHub...")
282
286
 
283
- model = create_model(provider, model_id, base_url, api_key)
287
+ model = create_model(
288
+ provider=provider,
289
+ model_id=model_id,
290
+ base_url=base_url,
291
+ api_key=api_key,
292
+ ssl_verify=ssl_verify,
293
+ )
284
294
  settings = ModelSettings(
285
295
  max_tokens=DEFAULT_MAX_TOKENS,
286
296
  temperature=DEFAULT_TEMPERATURE,
@@ -297,21 +307,21 @@ def create_agent(
297
307
  )
298
308
 
299
309
  # Load master toolsets
300
- master_toolsets = []
301
- if mcp_config:
302
- mcp_toolset = load_mcp_servers(mcp_config)
303
- master_toolsets.extend(mcp_toolset)
304
- logger.info(f"Connected to MCP Config JSON: {mcp_toolset}")
305
- elif mcp_url:
310
+ agent_toolsets = []
311
+ if mcp_url:
306
312
  if "sse" in mcp_url.lower():
307
313
  server = MCPServerSSE(mcp_url)
308
314
  else:
309
315
  server = MCPServerStreamableHTTP(mcp_url)
310
- master_toolsets.append(server)
316
+ agent_toolsets.append(server)
311
317
  logger.info(f"Connected to MCP Server: {mcp_url}")
318
+ elif mcp_config:
319
+ mcp_toolset = load_mcp_servers(mcp_config)
320
+ agent_toolsets.extend(mcp_toolset)
321
+ logger.info(f"Connected to MCP Config JSON: {mcp_toolset}")
312
322
 
313
323
  if skills_directory and os.path.exists(skills_directory):
314
- master_toolsets.append(SkillsToolset(directories=[str(skills_directory)]))
324
+ agent_toolsets.append(SkillsToolset(directories=[str(skills_directory)]))
315
325
 
316
326
  # Define Tag -> Prompt map
317
327
  # Key is the MCP Tool Tag (or set of tags), Value is (SystemPrompt, AgentName)
@@ -352,7 +362,7 @@ def create_agent(
352
362
 
353
363
  for tag, (system_prompt, agent_name) in agent_defs.items():
354
364
  tag_toolsets = []
355
- for ts in master_toolsets:
365
+ for ts in agent_toolsets:
356
366
 
357
367
  def filter_func(ctx, tool_def, t=tag):
358
368
  return tool_in_tag(tool_def, t)
@@ -569,6 +579,7 @@ def create_agent_server(
569
579
  host: Optional[str] = DEFAULT_HOST,
570
580
  port: Optional[int] = DEFAULT_PORT,
571
581
  enable_web_ui: bool = DEFAULT_ENABLE_WEB_UI,
582
+ ssl_verify: bool = DEFAULT_SSL_VERIFY,
572
583
  ):
573
584
  print(
574
585
  f"Starting {AGENT_NAME} with provider={provider}, model={model_id}, mcp={mcp_url} | {mcp_config}"
@@ -581,6 +592,7 @@ def create_agent_server(
581
592
  mcp_url=mcp_url,
582
593
  mcp_config=mcp_config,
583
594
  skills_directory=skills_directory,
595
+ ssl_verify=ssl_verify,
584
596
  )
585
597
 
586
598
  if skills_directory and os.path.exists(skills_directory):
@@ -695,10 +707,10 @@ def agent_server():
695
707
  parser.add_argument("--model-id", default=DEFAULT_MODEL_ID, help="LLM Model ID")
696
708
  parser.add_argument(
697
709
  "--base-url",
698
- default=DEFAULT_OPENAI_BASE_URL,
710
+ default=DEFAULT_LLM_BASE_URL,
699
711
  help="LLM Base URL (for OpenAI compatible providers)",
700
712
  )
701
- parser.add_argument("--api-key", default=DEFAULT_OPENAI_API_KEY, help="LLM API Key")
713
+ parser.add_argument("--api-key", default=DEFAULT_LLM_API_KEY, help="LLM API Key")
702
714
  parser.add_argument("--mcp-url", default=DEFAULT_MCP_URL, help="MCP Server URL")
703
715
  parser.add_argument(
704
716
  "--mcp-config", default=DEFAULT_MCP_CONFIG, help="MCP Server Config"
@@ -753,6 +765,7 @@ def agent_server():
753
765
  host=args.host,
754
766
  port=args.port,
755
767
  enable_web_ui=args.web,
768
+ ssl_verify=not args.insecure,
756
769
  )
757
770
 
758
771
 
@@ -2,6 +2,38 @@
2
2
  # coding: utf-8
3
3
 
4
4
  import os
5
+
6
+ # Try importing specific clients/providers, but don't fail if variables are missing
7
+ try:
8
+
9
+ from openai import AsyncOpenAI
10
+ from pydantic_ai.providers.openai import OpenAIProvider
11
+ except ImportError:
12
+ AsyncOpenAI = None
13
+ OpenAIProvider = None
14
+
15
+ try:
16
+ from groq import AsyncGroq
17
+ from pydantic_ai.providers.groq import GroqProvider
18
+ except ImportError:
19
+ AsyncGroq = None
20
+ GroqProvider = None
21
+
22
+ try:
23
+ from mistralai import Mistral
24
+ from pydantic_ai.providers.mistral import MistralProvider
25
+ except ImportError:
26
+ Mistral = None
27
+ MistralProvider = None
28
+
29
+ try:
30
+ from anthropic import AsyncAnthropic
31
+ from pydantic_ai.providers.anthropic import AnthropicProvider
32
+ except ImportError:
33
+ AsyncAnthropic = None
34
+ AnthropicProvider = None
35
+
36
+ import httpx
5
37
  import pickle
6
38
  import yaml
7
39
  from pathlib import Path
@@ -12,6 +44,8 @@ from pydantic_ai.models.openai import OpenAIChatModel
12
44
  from pydantic_ai.models.anthropic import AnthropicModel
13
45
  from pydantic_ai.models.google import GoogleModel
14
46
  from pydantic_ai.models.huggingface import HuggingFaceModel
47
+ from pydantic_ai.models.groq import GroqModel
48
+ from pydantic_ai.models.mistral import MistralModel
15
49
  from pydantic_ai_skills import Skill
16
50
 
17
51
 
@@ -211,36 +245,113 @@ def load_skills_from_directory(directory: str) -> List[Skill]:
211
245
  return skills
212
246
 
213
247
 
248
+ def get_http_client(ssl_verify: bool = True) -> httpx.AsyncClient | None:
249
+ if not ssl_verify:
250
+ return httpx.AsyncClient(verify=False)
251
+ return None
252
+
253
+
214
254
  def create_model(
215
255
  provider: str,
216
256
  model_id: str,
217
- base_url: Optional[str],
218
- api_key: Optional[str],
257
+ base_url: Optional[str] = None,
258
+ api_key: Optional[str] = None,
259
+ ssl_verify: bool = True,
219
260
  ):
261
+ http_client = get_http_client(ssl_verify=ssl_verify)
262
+
220
263
  if provider == "openai":
221
264
  target_base_url = base_url
222
265
  target_api_key = api_key
266
+
267
+ # If we have a custom client or specific settings, we might want to use the explicit provider object
268
+ if http_client and AsyncOpenAI and OpenAIProvider:
269
+ client = AsyncOpenAI(
270
+ api_key=target_api_key or os.environ.get("LLM_API_KEY"),
271
+ base_url=target_base_url or os.environ.get("LLM_BASE_URL"),
272
+ http_client=http_client,
273
+ )
274
+ provider_instance = OpenAIProvider(openai_client=client)
275
+ return OpenAIChatModel(model_name=model_id, provider=provider_instance)
276
+
277
+ # Fallback to standard env vars
223
278
  if target_base_url:
224
- os.environ["OPENAI_BASE_URL"] = target_base_url
279
+ os.environ["LLM_BASE_URL"] = target_base_url
225
280
  if target_api_key:
226
- os.environ["OPENAI_API_KEY"] = target_api_key
281
+ os.environ["LLM_API_KEY"] = target_api_key
282
+ return OpenAIChatModel(model_name=model_id, provider="openai")
283
+
284
+ elif provider == "ollama":
285
+ # Ollama is OpenAI compatible
286
+ target_base_url = base_url or "http://localhost:11434/v1"
287
+ target_api_key = api_key or "ollama"
288
+
289
+ if http_client and AsyncOpenAI and OpenAIProvider:
290
+ client = AsyncOpenAI(
291
+ api_key=target_api_key,
292
+ base_url=target_base_url,
293
+ http_client=http_client,
294
+ )
295
+ provider_instance = OpenAIProvider(openai_client=client)
296
+ return OpenAIChatModel(model_name=model_id, provider=provider_instance)
297
+
298
+ os.environ["LLM_BASE_URL"] = target_base_url
299
+ os.environ["LLM_API_KEY"] = target_api_key
227
300
  return OpenAIChatModel(model_name=model_id, provider="openai")
228
301
 
229
302
  elif provider == "anthropic":
230
303
  if api_key:
231
- os.environ["ANTHROPIC_API_KEY"] = api_key
304
+ os.environ["LLM_API_KEY"] = api_key
305
+
306
+ try:
307
+ if http_client and AsyncAnthropic and AnthropicProvider:
308
+ client = AsyncAnthropic(
309
+ api_key=api_key or os.environ.get("LLM_API_KEY"),
310
+ http_client=http_client,
311
+ )
312
+ provider_instance = AnthropicProvider(anthropic_client=client)
313
+ return AnthropicModel(model_name=model_id, provider=provider_instance)
314
+ except ImportError:
315
+ pass
316
+
232
317
  return AnthropicModel(model_name=model_id)
233
318
 
234
319
  elif provider == "google":
320
+ # Google generic setup, skipping complex SSL for now as agreed
235
321
  if api_key:
236
- os.environ["GEMINI_API_KEY"] = api_key
237
- os.environ["GOOGLE_API_KEY"] = api_key
322
+ os.environ["LLM_API_KEY"] = api_key
238
323
  return GoogleModel(model_name=model_id)
239
324
 
325
+ elif provider == "groq":
326
+ if api_key:
327
+ os.environ["LLM_API_KEY"] = api_key
328
+
329
+ if http_client and AsyncGroq and GroqProvider:
330
+ client = AsyncGroq(
331
+ api_key=api_key or os.environ.get("LLM_API_KEY"),
332
+ http_client=http_client,
333
+ )
334
+ provider_instance = GroqProvider(groq_client=client)
335
+ return GroqModel(model_name=model_id, provider=provider_instance)
336
+
337
+ return GroqModel(model_name=model_id)
338
+
339
+ elif provider == "mistral":
340
+ if api_key:
341
+ os.environ["LLM_API_KEY"] = api_key
342
+
343
+ if http_client and Mistral and MistralProvider:
344
+ # Assuming mistral_client argument for MistralProvider
345
+ # Ideally we would verify this, but we'll try standard pattern
346
+ pass
347
+
348
+ return MistralModel(model_name=model_id)
349
+
240
350
  elif provider == "huggingface":
241
351
  if api_key:
242
- os.environ["HF_TOKEN"] = api_key
352
+ os.environ["LLM_API_KEY"] = api_key
243
353
  return HuggingFaceModel(model_name=model_id)
354
+
244
355
  return OpenAIChatModel(model_name=model_id, provider="openai")
245
356
 
246
357
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: github-agent
3
- Version: 0.2.1
3
+ Version: 0.2.2
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.1*
46
+ *Version: 0.2.2*
47
47
 
48
48
  ## Overview
49
49
 
@@ -172,7 +172,7 @@ The `github-agent` command starts the server.
172
172
  | `--port` | Port to bind the server to | `9000` |
173
173
  | `--mcp-config` | Path to MCP configuration file | `mcp_config.json` |
174
174
  | `--provider` | LLM Provider (openai, anthropic, google, etc.) | `openai` |
175
- | `--model-id` | LLM Model ID | `qwen/qwen3-4b-2507` |
175
+ | `--model-id` | LLM Model ID | `qwen/qwen3-coder-next` |
176
176
 
177
177
  ### Running the Agent Server
178
178
 
@@ -193,7 +193,7 @@ docker build -t github-agent .
193
193
  ```bash
194
194
  docker run -d \
195
195
  -p 9000:9000 \
196
- -e OPENAI_API_KEY=sk-... \
196
+ -e LLM_API_KEY=sk-... \
197
197
  -e MCP_CONFIG=/app/mcp_config.json \
198
198
  knucklessg1/github-agent:latest
199
199
  ```
@@ -211,7 +211,7 @@ services:
211
211
  environment:
212
212
  - PROVIDER=openai
213
213
  - MODEL_ID=gpt-4o
214
- - OPENAI_API_KEY=${OPENAI_API_KEY}
214
+ - LLM_API_KEY=${LLM_API_KEY}
215
215
  volumes:
216
216
  - ./mcp_config.json:/app/mcp_config.json
217
217
  ```
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "github-agent"
7
- version = "0.2.1"
7
+ version = "0.2.2"
8
8
  readme = "README.md"
9
9
  description = "GitHub Agent for MCP"
10
10
  requires-python = ">=3.10"
File without changes
File without changes