diagram-to-iac 0.7.0__py3-none-any.whl → 0.8.0__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.
Files changed (77) hide show
  1. diagram_to_iac/__init__.py +10 -0
  2. diagram_to_iac/actions/__init__.py +7 -0
  3. diagram_to_iac/actions/git_entry.py +174 -0
  4. diagram_to_iac/actions/supervisor_entry.py +116 -0
  5. diagram_to_iac/actions/terraform_agent_entry.py +207 -0
  6. diagram_to_iac/agents/__init__.py +26 -0
  7. diagram_to_iac/agents/demonstrator_langgraph/__init__.py +10 -0
  8. diagram_to_iac/agents/demonstrator_langgraph/agent.py +826 -0
  9. diagram_to_iac/agents/git_langgraph/__init__.py +10 -0
  10. diagram_to_iac/agents/git_langgraph/agent.py +1018 -0
  11. diagram_to_iac/agents/git_langgraph/pr.py +146 -0
  12. diagram_to_iac/agents/hello_langgraph/__init__.py +9 -0
  13. diagram_to_iac/agents/hello_langgraph/agent.py +621 -0
  14. diagram_to_iac/agents/policy_agent/__init__.py +15 -0
  15. diagram_to_iac/agents/policy_agent/agent.py +507 -0
  16. diagram_to_iac/agents/policy_agent/integration_example.py +191 -0
  17. diagram_to_iac/agents/policy_agent/tools/__init__.py +14 -0
  18. diagram_to_iac/agents/policy_agent/tools/tfsec_tool.py +259 -0
  19. diagram_to_iac/agents/shell_langgraph/__init__.py +21 -0
  20. diagram_to_iac/agents/shell_langgraph/agent.py +122 -0
  21. diagram_to_iac/agents/shell_langgraph/detector.py +50 -0
  22. diagram_to_iac/agents/supervisor_langgraph/__init__.py +17 -0
  23. diagram_to_iac/agents/supervisor_langgraph/agent.py +1947 -0
  24. diagram_to_iac/agents/supervisor_langgraph/demonstrator.py +22 -0
  25. diagram_to_iac/agents/supervisor_langgraph/guards.py +23 -0
  26. diagram_to_iac/agents/supervisor_langgraph/pat_loop.py +49 -0
  27. diagram_to_iac/agents/supervisor_langgraph/router.py +9 -0
  28. diagram_to_iac/agents/terraform_langgraph/__init__.py +15 -0
  29. diagram_to_iac/agents/terraform_langgraph/agent.py +1216 -0
  30. diagram_to_iac/agents/terraform_langgraph/parser.py +76 -0
  31. diagram_to_iac/core/__init__.py +7 -0
  32. diagram_to_iac/core/agent_base.py +19 -0
  33. diagram_to_iac/core/enhanced_memory.py +302 -0
  34. diagram_to_iac/core/errors.py +4 -0
  35. diagram_to_iac/core/issue_tracker.py +49 -0
  36. diagram_to_iac/core/memory.py +132 -0
  37. diagram_to_iac/services/__init__.py +10 -0
  38. diagram_to_iac/services/observability.py +59 -0
  39. diagram_to_iac/services/step_summary.py +77 -0
  40. diagram_to_iac/tools/__init__.py +11 -0
  41. diagram_to_iac/tools/api_utils.py +108 -26
  42. diagram_to_iac/tools/git/__init__.py +45 -0
  43. diagram_to_iac/tools/git/git.py +956 -0
  44. diagram_to_iac/tools/hello/__init__.py +30 -0
  45. diagram_to_iac/tools/hello/cal_utils.py +31 -0
  46. diagram_to_iac/tools/hello/text_utils.py +97 -0
  47. diagram_to_iac/tools/llm_utils/__init__.py +20 -0
  48. diagram_to_iac/tools/llm_utils/anthropic_driver.py +87 -0
  49. diagram_to_iac/tools/llm_utils/base_driver.py +90 -0
  50. diagram_to_iac/tools/llm_utils/gemini_driver.py +89 -0
  51. diagram_to_iac/tools/llm_utils/openai_driver.py +93 -0
  52. diagram_to_iac/tools/llm_utils/router.py +303 -0
  53. diagram_to_iac/tools/sec_utils.py +4 -2
  54. diagram_to_iac/tools/shell/__init__.py +17 -0
  55. diagram_to_iac/tools/shell/shell.py +415 -0
  56. diagram_to_iac/tools/text_utils.py +277 -0
  57. diagram_to_iac/tools/tf/terraform.py +851 -0
  58. diagram_to_iac-0.8.0.dist-info/METADATA +99 -0
  59. diagram_to_iac-0.8.0.dist-info/RECORD +64 -0
  60. {diagram_to_iac-0.7.0.dist-info → diagram_to_iac-0.8.0.dist-info}/WHEEL +1 -1
  61. diagram_to_iac-0.8.0.dist-info/entry_points.txt +4 -0
  62. diagram_to_iac/agents/codegen_agent.py +0 -0
  63. diagram_to_iac/agents/consensus_agent.py +0 -0
  64. diagram_to_iac/agents/deployment_agent.py +0 -0
  65. diagram_to_iac/agents/github_agent.py +0 -0
  66. diagram_to_iac/agents/interpretation_agent.py +0 -0
  67. diagram_to_iac/agents/question_agent.py +0 -0
  68. diagram_to_iac/agents/supervisor.py +0 -0
  69. diagram_to_iac/agents/vision_agent.py +0 -0
  70. diagram_to_iac/core/config.py +0 -0
  71. diagram_to_iac/tools/cv_utils.py +0 -0
  72. diagram_to_iac/tools/gh_utils.py +0 -0
  73. diagram_to_iac/tools/tf_utils.py +0 -0
  74. diagram_to_iac-0.7.0.dist-info/METADATA +0 -16
  75. diagram_to_iac-0.7.0.dist-info/RECORD +0 -32
  76. diagram_to_iac-0.7.0.dist-info/entry_points.txt +0 -2
  77. {diagram_to_iac-0.7.0.dist-info → diagram_to_iac-0.8.0.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,77 @@
1
+ from __future__ import annotations
2
+
3
+ import json
4
+ import re
5
+ from datetime import datetime
6
+ from pathlib import Path
7
+
8
+
9
+ def _parse_timestamp(ts: str) -> datetime:
10
+ try:
11
+ return datetime.fromisoformat(ts)
12
+ except Exception:
13
+ # Fallback for timestamps that may not be ISO formatted
14
+ return datetime.strptime(ts.split(".")[0], "%Y-%m-%dT%H:%M:%S")
15
+
16
+
17
+ def generate_step_summary(log_path: str | Path, output_path: str | Path, *, stdout: bool = False) -> str:
18
+ """Generate a Markdown step summary from JSONL logs."""
19
+ log_path = Path(log_path)
20
+ output_path = Path(output_path)
21
+
22
+ modules: set[str] = set()
23
+ adds = changes = destroys = 0
24
+ critical = high = medium = low = 0
25
+ start: datetime | None = None
26
+ end: datetime | None = None
27
+
28
+ if not log_path.exists():
29
+ raise FileNotFoundError(log_path)
30
+
31
+ with log_path.open("r", encoding="utf-8") as f:
32
+ for line in f:
33
+ line = line.strip()
34
+ if not line:
35
+ continue
36
+ data = json.loads(line)
37
+ ts = data.get("timestamp")
38
+ if ts:
39
+ ts_dt = _parse_timestamp(ts)
40
+ if start is None or ts_dt < start:
41
+ start = ts_dt
42
+ if end is None or ts_dt > end:
43
+ end = ts_dt
44
+ result = data.get("result", "")
45
+ if result:
46
+ modules.update(re.findall(r"module\.([\w-]+)", result))
47
+ m = re.search(r"Plan:\s*(\d+)\s*to\s*add,\s*(\d+)\s*to\s*change,\s*(\d+)\s*to\s*destroy", result)
48
+ if m:
49
+ adds = int(m.group(1))
50
+ changes = int(m.group(2))
51
+ destroys = int(m.group(3))
52
+ m = re.search(r"(\d+)\s*critical", result, re.IGNORECASE)
53
+ if m:
54
+ critical = int(m.group(1))
55
+ m = re.search(r"(\d+)\s*high", result, re.IGNORECASE)
56
+ if m:
57
+ high = int(m.group(1))
58
+ m = re.search(r"(\d+)\s*medium", result, re.IGNORECASE)
59
+ if m:
60
+ medium = int(m.group(1))
61
+ m = re.search(r"(\d+)\s*low", result, re.IGNORECASE)
62
+ if m:
63
+ low = int(m.group(1))
64
+
65
+ runtime = (end - start).total_seconds() if start and end else 0
66
+ modules_str = ", ".join(sorted(modules)) if modules else "root"
67
+
68
+ md = (
69
+ "| Module | Adds | Changes | Destroys | Critical | High | Medium | Low | Run Time (s) |\n"
70
+ "| --- | --- | --- | --- | --- | --- | --- | --- | --- |\n"
71
+ f"| {modules_str} | {adds} | {changes} | {destroys} | {critical} | {high} | {medium} | {low} | {int(runtime)} |\n"
72
+ )
73
+
74
+ output_path.write_text(md, encoding="utf-8")
75
+ if stdout:
76
+ print(md)
77
+ return md
@@ -0,0 +1,11 @@
1
+ # This file makes the 'tools' module a package.
2
+
3
+ # Note: Agent-specific tools organization:
4
+ # - cal_utils, text_utils -> tools/hello/
5
+ # - git_tools -> tools/git/ (moved from agents/git_langgraph/tools/)
6
+ # - shell_tools -> agents/shell_langgraph/tools/
7
+
8
+ # You can expose shared tools here as needed
9
+ # For example:
10
+ # from .llm_utils import router (if router.py is in llm_utils subdirectory)
11
+ # from .cv_utils import some_vision_function
@@ -5,9 +5,7 @@ from anthropic import Anthropic
5
5
  import requests
6
6
  import google.generativeai as genai
7
7
  import googleapiclient.discovery
8
- # Add the parent directory to sys.path to import env_loader
9
- # sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
10
- # from scripts.env_loader import load_env_keys
8
+ from concurrent.futures import ThreadPoolExecutor, TimeoutError
11
9
 
12
10
  def test_openai_api():
13
11
  try:
@@ -15,12 +13,20 @@ def test_openai_api():
15
13
  print("❌ OpenAI API error: OPENAI_API_KEY environment variable not set.")
16
14
  return False
17
15
  client = OpenAI()
18
- response = client.chat.completions.create(
19
- # Consider using a newer model if appropriate, e.g., "gpt-4o-mini" or "gpt-3.5-turbo"
20
- model="gpt-3.5-turbo",
21
- messages=[{"role": "user", "content": "Hello, are you working?"}],
22
- max_tokens=10
23
- )
16
+
17
+ # Run the API call with a 10-second timeout
18
+ with ThreadPoolExecutor(max_workers=1) as executor:
19
+ future = executor.submit(
20
+ client.chat.completions.create,
21
+ model="gpt-3.5-turbo",
22
+ messages=[{"role": "user", "content": "Hello, are you working?"}],
23
+ max_tokens=10
24
+ )
25
+ try:
26
+ response = future.result(timeout=10)
27
+ except TimeoutError:
28
+ print("❌ OpenAI API error: request timed out.")
29
+ return False
24
30
  return True
25
31
  except Exception as e:
26
32
  print(f"❌ Open AI API error: {str(e)}")
@@ -33,8 +39,16 @@ def test_gemini_api():
33
39
  print("❌ Gemini API error: GOOGLE_API_KEY environment variable not set.")
34
40
  return False
35
41
  genai.configure(api_key=google_api_key)
36
- model = genai.GenerativeModel('gemini-1.5-flash-latest') # Corrected model name
37
- response = model.generate_content("Hello, are you working?")
42
+ model = genai.GenerativeModel('gemini-2.0-flash') # Corrected model name
43
+
44
+ # Run the API call with a 10-second timeout
45
+ with ThreadPoolExecutor(max_workers=1) as executor:
46
+ future = executor.submit(model.generate_content, "Hello, are you working?")
47
+ try:
48
+ response = future.result(timeout=10)
49
+ except TimeoutError:
50
+ print("❌ Gemini API error: request timed out.")
51
+ return False
38
52
  return True
39
53
  except Exception as e:
40
54
  print(f"❌ Gemini API error: {str(e)}")
@@ -46,11 +60,20 @@ def test_anthropic_api():
46
60
  print("❌ Anthropic API error: ANTHROPIC_API_KEY environment variable not set.")
47
61
  return False
48
62
  client = Anthropic()
49
- response = client.messages.create(
50
- model="claude-3-haiku-20240307",
51
- max_tokens=10,
52
- messages=[{"role": "user", "content": "Hello, are you working?"}]
53
- )
63
+
64
+ # Run the API call with a 10-second timeout
65
+ with ThreadPoolExecutor(max_workers=1) as executor:
66
+ future = executor.submit(
67
+ client.messages.create,
68
+ model="claude-3-haiku-20240307",
69
+ max_tokens=10,
70
+ messages=[{"role": "user", "content": "Hello, are you working?"}]
71
+ )
72
+ try:
73
+ response = future.result(timeout=10)
74
+ except TimeoutError:
75
+ print("❌ Anthropic API error: request timed out.")
76
+ return False
54
77
  return True
55
78
  except Exception as e:
56
79
  print(f"❌ Anthropic API error: {str(e)}")
@@ -69,9 +92,18 @@ def test_github_api():
69
92
  "Accept": "application/vnd.github.v3+json"
70
93
  }
71
94
 
72
- # Try to get the authenticated user
73
- url = "https://api.github.com/user"
74
- response = requests.get(url, headers=headers)
95
+ # Run the API call with a 10-second timeout
96
+ with ThreadPoolExecutor(max_workers=1) as executor:
97
+ future = executor.submit(
98
+ requests.get,
99
+ "https://api.github.com/user",
100
+ headers=headers
101
+ )
102
+ try:
103
+ response = future.result(timeout=10)
104
+ except TimeoutError:
105
+ print("❌ GitHub API error: request timed out.")
106
+ return False
75
107
 
76
108
  if response.status_code == 200:
77
109
  user_data = response.json()
@@ -85,25 +117,75 @@ def test_github_api():
85
117
  print(f"❌ GitHub API error: {str(e)}")
86
118
  return False
87
119
 
120
+ def test_Terraform_API():
121
+ try:
122
+ if not os.environ.get("TFE_TOKEN"):
123
+ print("❌ Terraform API error: TFE_TOKEN environment variable not set.")
124
+ return False
125
+ headers = {
126
+ "Authorization": f"Bearer {os.environ.get('TFE_TOKEN')}",
127
+ "Content-Type": "application/vnd.api+json"
128
+ }
129
+ # Run the API call with a 10-second timeout
130
+ with ThreadPoolExecutor(max_workers=1) as executor:
131
+ future = executor.submit(
132
+ requests.get,
133
+ "https://app.terraform.io/api/v2/organizations",
134
+ headers=headers
135
+ )
136
+ try:
137
+ response = future.result(timeout=10)
138
+ except TimeoutError:
139
+ print("❌ Terraform API error: request timed out.")
140
+ return False
141
+ if response.status_code == 200:
142
+ org_data = response.json()
143
+ # print(f"✅ Terraform API works! Organizations: {org_data}")
144
+ return True
145
+ else:
146
+ print(f"❌ Terraform API error: Status code {response.status_code}")
147
+ if hasattr(response, 'text'):
148
+ print(f" Response body: {response.text}")
149
+ return False
150
+ except requests.exceptions.ConnectionError as e:
151
+ print(f"❌ Terraform API error: Connection failed - {str(e)}")
152
+ print(" This could be due to:")
153
+ print(" - Network connectivity issues")
154
+ print(" - DNS resolution problems")
155
+ print(" - Firewall blocking the connection")
156
+ return False
157
+ except requests.exceptions.SSLError as e:
158
+ print(f"❌ Terraform API error: SSL/TLS error - {str(e)}")
159
+ return False
160
+ except requests.exceptions.Timeout as e:
161
+ print(f"❌ Terraform API error: Request timeout - {str(e)}")
162
+ return False
163
+ except requests.exceptions.RequestException as e:
164
+ print(f"❌ Terraform API error: Request failed - {str(e)}")
165
+ return False
166
+ except Exception as e:
167
+ print(f"❌ Terraform API error: Unexpected error - {str(e)}")
168
+ return False
169
+
88
170
  def test_all_apis():
89
171
  print("Hello from the test workflow!")
90
- print("Loading environment keys...")
91
- # Load environment keys once before running all tests
92
- #load_env_keys()
172
+
93
173
 
94
174
  print("Testing API connections...")
95
175
  openai_success = test_openai_api()
96
176
  gemini_success = test_gemini_api()
97
177
  anthropic_success = test_anthropic_api()
98
- github_success = test_github_api() # Added GitHub API test
178
+ github_success = test_github_api()
179
+ terraform_success = test_Terraform_API()
99
180
 
100
181
  print("\nSummary:")
101
182
  print(f"OpenAI API: {'✅ Working' if openai_success else '❌ Failed'}")
102
183
  print(f"Gemini API: {'✅ Working' if gemini_success else '❌ Failed'}")
103
184
  print(f"Anthropic API: {'✅ Working' if anthropic_success else '❌ Failed'}")
104
- print(f"GitHub API: {'✅ Working' if github_success else '❌ Failed'}") # Added GitHub API result
105
-
106
- if openai_success and gemini_success and anthropic_success and github_success: # Updated condition
185
+ print(f"GitHub API: {'✅ Working' if github_success else '❌ Failed'}")
186
+ print(f"Terraform API: {'✅ Working' if terraform_success else '❌ Failed'}")
187
+
188
+ if openai_success and gemini_success and anthropic_success and github_success and terraform_success: # Updated condition
107
189
  print("\n🎉 All APIs are working correctly!")
108
190
  else:
109
191
  print("\n⚠️ Some APIs failed. Check the errors above.")
@@ -0,0 +1,45 @@
1
+ """
2
+ Git Tools Package
3
+
4
+ This package contains git-related tools and utilities:
5
+ - git: Core git operations (clone, GitHub CLI)
6
+ - git_config.yaml: Configuration for git operations
7
+
8
+ Moved from agents/git_langgraph/tools for better organization.
9
+ """
10
+
11
+ from .git import (
12
+ GitExecutor,
13
+ git_clone,
14
+ gh_open_issue,
15
+ get_git_executor,
16
+ GitCloneInput,
17
+ GitCloneOutput,
18
+ GhOpenIssueInput,
19
+ GhOpenIssueOutput,
20
+ )
21
+
22
+ # Ensure the tool functions reference the exported get_git_executor so that
23
+ # tests can patch `diagram_to_iac.tools.git.get_git_executor` and have the
24
+ # patch affect the functions imported from this package. Without this,
25
+ # git_clone and gh_open_issue would retain references to the original function
26
+ # defined in ``git.py`` making patching ineffective.
27
+ import importlib
28
+
29
+ def _patched_get_git_executor():
30
+ """Resolve get_git_executor dynamically so tests can patch it easily."""
31
+ return importlib.import_module(__name__).get_git_executor()
32
+
33
+ git_clone.func.__globals__["get_git_executor"] = _patched_get_git_executor
34
+ gh_open_issue.func.__globals__["get_git_executor"] = _patched_get_git_executor
35
+
36
+ __all__ = [
37
+ "GitExecutor",
38
+ "git_clone",
39
+ "gh_open_issue",
40
+ "get_git_executor",
41
+ "GitCloneInput",
42
+ "GitCloneOutput",
43
+ "GhOpenIssueInput",
44
+ "GhOpenIssueOutput"
45
+ ]