mycode-aiagent 0.1.4__tar.gz → 0.2.1__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.
Files changed (25) hide show
  1. {mycode_aiagent-0.1.4 → mycode_aiagent-0.2.1}/PKG-INFO +1 -1
  2. {mycode_aiagent-0.1.4 → mycode_aiagent-0.2.1}/my_code/__init__.py +1 -1
  3. {mycode_aiagent-0.1.4 → mycode_aiagent-0.2.1}/my_code/analyzer.py +20 -18
  4. {mycode_aiagent-0.1.4 → mycode_aiagent-0.2.1}/my_code/backends/__init__.py +3 -2
  5. {mycode_aiagent-0.1.4 → mycode_aiagent-0.2.1}/my_code/backends/mcp_backend.py +2 -2
  6. {mycode_aiagent-0.1.4 → mycode_aiagent-0.2.1}/my_code/backends/ricky_backend.py +2 -2
  7. {mycode_aiagent-0.1.4 → mycode_aiagent-0.2.1}/my_code/cli.py +3 -0
  8. {mycode_aiagent-0.1.4 → mycode_aiagent-0.2.1}/my_code/mcp_client.py +5 -4
  9. {mycode_aiagent-0.1.4 → mycode_aiagent-0.2.1}/my_code/utils/prompts.py +11 -6
  10. {mycode_aiagent-0.1.4 → mycode_aiagent-0.2.1}/mycode_aiagent.egg-info/PKG-INFO +1 -1
  11. {mycode_aiagent-0.1.4 → mycode_aiagent-0.2.1}/pyproject.toml +1 -1
  12. {mycode_aiagent-0.1.4 → mycode_aiagent-0.2.1}/README.md +0 -0
  13. {mycode_aiagent-0.1.4 → mycode_aiagent-0.2.1}/my_code/__main__.py +0 -0
  14. {mycode_aiagent-0.1.4 → mycode_aiagent-0.2.1}/my_code/backends/base.py +0 -0
  15. {mycode_aiagent-0.1.4 → mycode_aiagent-0.2.1}/my_code/backends/claude_backend.py +0 -0
  16. {mycode_aiagent-0.1.4 → mycode_aiagent-0.2.1}/my_code/backends/openai_backend.py +0 -0
  17. {mycode_aiagent-0.1.4 → mycode_aiagent-0.2.1}/my_code/generator.py +0 -0
  18. {mycode_aiagent-0.1.4 → mycode_aiagent-0.2.1}/my_code/utils/__init__.py +0 -0
  19. {mycode_aiagent-0.1.4 → mycode_aiagent-0.2.1}/mycode_aiagent.egg-info/SOURCES.txt +0 -0
  20. {mycode_aiagent-0.1.4 → mycode_aiagent-0.2.1}/mycode_aiagent.egg-info/dependency_links.txt +0 -0
  21. {mycode_aiagent-0.1.4 → mycode_aiagent-0.2.1}/mycode_aiagent.egg-info/entry_points.txt +0 -0
  22. {mycode_aiagent-0.1.4 → mycode_aiagent-0.2.1}/mycode_aiagent.egg-info/requires.txt +0 -0
  23. {mycode_aiagent-0.1.4 → mycode_aiagent-0.2.1}/mycode_aiagent.egg-info/top_level.txt +0 -0
  24. {mycode_aiagent-0.1.4 → mycode_aiagent-0.2.1}/setup.cfg +0 -0
  25. {mycode_aiagent-0.1.4 → mycode_aiagent-0.2.1}/tests/test_library.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: mycode-aiagent
3
- Version: 0.1.4
3
+ Version: 0.2.1
4
4
  Summary: Style-aware code generation — analyze any codebase and generate new code that matches its style
5
5
  License: MIT
6
6
  Project-URL: Homepage, https://github.com/RyanAbbottData/MyCode
@@ -1,4 +1,4 @@
1
- __version__ = "0.1.0"
1
+ __version__ = "0.1.5"
2
2
 
3
3
  from .analyzer import StyleAnalyzer
4
4
  from .generator import generate_code
@@ -3,7 +3,7 @@ import re
3
3
  from pathlib import Path
4
4
 
5
5
  from .backends import AIBackend
6
- from .utils.prompts import STYLE_EXTRACTION_PROMPT, STYLE_SUMMARY_PROMPT
6
+ from .utils.prompts import STYLE_EXTRACTION_PROMPT, STYLE_MERGE_PROMPT
7
7
 
8
8
  _SKIP_EXACT = {"__pycache__", ".git", "node_modules", "dist", "build"}
9
9
 
@@ -52,30 +52,32 @@ class StyleAnalyzer:
52
52
  if not files:
53
53
  raise FileNotFoundError(f"No Python files found under {root}")
54
54
 
55
- observations = []
55
+ profile = {}
56
56
  for path in files:
57
57
  rel = path.relative_to(root)
58
58
  if verbose:
59
59
  print(f" Analyzing {rel} ...")
60
60
  obs = self.analyze_file(path)
61
- if obs:
62
- observations.append(obs)
63
-
64
- if not observations:
61
+ if not obs:
62
+ continue
63
+ if not profile:
64
+ profile = obs
65
+ continue
66
+ prompt = STYLE_MERGE_PROMPT.format(
67
+ profile=json.dumps(profile, indent=2),
68
+ observation=json.dumps(obs, indent=2),
69
+ filename=path.name,
70
+ )
71
+ raw = self.backend.ask_to_analyze(prompt)
72
+ try:
73
+ profile = _extract_json(raw)
74
+ except (ValueError, json.JSONDecodeError) as e:
75
+ print(f" [warn] Could not merge style from {path.name}: {e}")
76
+
77
+ if not profile:
65
78
  raise RuntimeError("No style data could be extracted from any file.")
66
79
 
67
- if len(observations) == 1:
68
- return observations[0]
69
-
70
- prompt = STYLE_SUMMARY_PROMPT.format(
71
- observations=json.dumps(observations, indent=2)
72
- )
73
- raw = self.backend.ask_to_analyze(prompt)
74
- try:
75
- return _extract_json(raw)
76
- except (ValueError, json.JSONDecodeError) as e:
77
- print(f"[warn] Could not synthesize profile, using first observation: {e}")
78
- return observations[0]
80
+ return profile
79
81
 
80
82
  @staticmethod
81
83
  def save_profile(profile: dict, path: Path):
@@ -15,6 +15,7 @@ def make_backend(
15
15
  ricky_url: str = "http://localhost:8000/mcp",
16
16
  mcp_url: str = "http://localhost:8001/mcp",
17
17
  model: str | None = None,
18
+ timeout: int = 120,
18
19
  ) -> AIBackend:
19
20
  if backend == "claude":
20
21
  key = api_key or os.environ.get("ANTHROPIC_API_KEY")
@@ -27,7 +28,7 @@ def make_backend(
27
28
  raise ValueError("OpenAI backend requires OPENAI_API_KEY or --api-key")
28
29
  return OpenAIBackend(api_key=key, **{"model": model} if model else {})
29
30
  if backend == "mcp":
30
- return MCPBackend(url=mcp_url)
31
+ return MCPBackend(url=mcp_url, timeout=timeout)
31
32
  if backend == "llama":
32
- return RickyBackend(url=ricky_url)
33
+ return RickyBackend(url=ricky_url, timeout=timeout)
33
34
  raise ValueError(f"Unknown backend {backend!r}. Choose: llama, claude, openai, mcp")
@@ -3,8 +3,8 @@ from ..mcp_client import MCPClient
3
3
 
4
4
 
5
5
  class MCPBackend(AIBackend):
6
- def __init__(self, url: str = "http://localhost:8001/mcp"):
7
- self._client = MCPClient(url=url)
6
+ def __init__(self, url: str = "http://localhost:8001/mcp", timeout: int = 120):
7
+ self._client = MCPClient(url=url, timeout=timeout)
8
8
 
9
9
  def ask_for_code(self, prompt: str) -> str:
10
10
  return self._client.ask_for_code(prompt)
@@ -5,8 +5,8 @@ from ..mcp_client import MCPClient
5
5
  class RickyBackend(AIBackend):
6
6
  max_file_chars: int = 1500
7
7
 
8
- def __init__(self, url: str = "http://localhost:8000/mcp"):
9
- self._client = MCPClient(url=url)
8
+ def __init__(self, url: str = "http://localhost:8000/mcp", timeout: int = 120):
9
+ self._client = MCPClient(url=url, timeout=timeout)
10
10
 
11
11
  def ask_for_code(self, prompt: str) -> str:
12
12
  return self._client.ask_for_code(prompt)
@@ -29,6 +29,7 @@ def cmd_analyze(args):
29
29
  ricky_url=args.ricky_url,
30
30
  mcp_url=args.mcp_url,
31
31
  model=args.model,
32
+ timeout=args.timeout,
32
33
  )
33
34
 
34
35
  print(f"Analyzing codebase at {root} ...")
@@ -53,6 +54,7 @@ def cmd_generate(args):
53
54
  ricky_url=args.ricky_url,
54
55
  mcp_url=args.mcp_url,
55
56
  model=args.model,
57
+ timeout=args.timeout,
56
58
  )
57
59
 
58
60
  profile = json.loads(profile_path.read_text(encoding="utf-8"))
@@ -72,6 +74,7 @@ def main():
72
74
  parser.add_argument("--model", default=None, help="Override default model for claude/openai backends")
73
75
  parser.add_argument("--ricky-url", default="http://localhost:8000/mcp", help="Ricky MCP server URL (llama backend)")
74
76
  parser.add_argument("--mcp-url", default="http://localhost:8001/mcp", help="MCP server URL (mcp backend)")
77
+ parser.add_argument("--timeout", type=int, default=120, help="Request timeout in seconds (default: 120)")
75
78
  parser.add_argument("--profile", default=str(DEFAULT_PROFILE))
76
79
 
77
80
  sub = parser.add_subparsers(dest="command", required=True)
@@ -24,8 +24,9 @@ class MCPClient:
24
24
  3. POST /mcp tools/call → invoke a tool
25
25
  """
26
26
 
27
- def __init__(self, url: str = "http://localhost:8001/mcp"):
27
+ def __init__(self, url: str = "http://localhost:8001/mcp", timeout: int = 120):
28
28
  self.url = url
29
+ self._timeout = timeout
29
30
  self._session_id: str | None = None
30
31
  self._tool_name: str | None = None
31
32
  self._tool_name_analyze: str | None = None
@@ -35,7 +36,7 @@ class MCPClient:
35
36
  self._discover_tools()
36
37
  print(f"Connected to MCP server — tools: '{self._tool_name}', '{self._tool_name_analyze}'")
37
38
 
38
- def _post(self, method: str, params: dict, timeout: int = 120) -> dict:
39
+ def _post(self, method: str, params: dict) -> dict:
39
40
  headers = {
40
41
  "Content-Type": "application/json",
41
42
  "Accept": "application/json, text/event-stream",
@@ -49,7 +50,7 @@ class MCPClient:
49
50
  "method": method,
50
51
  "params": params,
51
52
  }
52
- resp = requests.post(self.url, json=payload, headers=headers, timeout=timeout)
53
+ resp = requests.post(self.url, json=payload, headers=headers, timeout=self._timeout)
53
54
  resp.raise_for_status()
54
55
 
55
56
  if "Mcp-Session-Id" in resp.headers:
@@ -117,5 +118,5 @@ class MCPClient:
117
118
  result = self._post("tools/call", {
118
119
  "name": self._tool_name_analyze,
119
120
  "arguments": {self._analyze_arg: prompt},
120
- }, timeout=600)
121
+ })
121
122
  return self._extract_text(result)
@@ -30,15 +30,20 @@ Source file ({filename}):
30
30
  ```
31
31
  """
32
32
 
33
- STYLE_SUMMARY_PROMPT = """\
34
- You are a code style analyst. Below are JSON style observations extracted from multiple files in a codebase. Synthesize them into a single authoritative style profile JSON.
33
+ STYLE_MERGE_PROMPT = """\
34
+ You are a code style analyst. Update the current style profile by merging in a new file observation.
35
35
 
36
- Use the same schema. For fields where files disagree, pick the majority or most consistent value. Add a "confidence" field (low/medium/high) per section. Keep representative_snippets to the 3 best examples across all files.
36
+ Rules:
37
+ - Where they agree, keep the value.
38
+ - Where they disagree, pick the more consistent value.
39
+ - Keep representative_snippets to the 3 best examples total.
40
+ - Return ONLY valid JSON using the same schema.
37
41
 
38
- Return ONLY valid JSON.
42
+ Current profile:
43
+ {profile}
39
44
 
40
- Observations:
41
- {observations}
45
+ New observation ({filename}):
46
+ {observation}
42
47
  """
43
48
 
44
49
  CODE_GENERATION_PROMPT = """\
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: mycode-aiagent
3
- Version: 0.1.4
3
+ Version: 0.2.1
4
4
  Summary: Style-aware code generation — analyze any codebase and generate new code that matches its style
5
5
  License: MIT
6
6
  Project-URL: Homepage, https://github.com/RyanAbbottData/MyCode
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "mycode-aiagent"
7
- version = "0.1.4"
7
+ version = "0.2.1"
8
8
  description = "Style-aware code generation — analyze any codebase and generate new code that matches its style"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.10"
File without changes
File without changes