diagram-to-iac 1.3.0__py3-none-any.whl → 1.4.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.
- diagram_to_iac/core/config_loader.py +74 -85
- diagram_to_iac/core/enhanced_memory.py +22 -5
- diagram_to_iac/core/registry.py +23 -3
- diagram_to_iac/tools/llm_utils/router.py +14 -3
- {diagram_to_iac-1.3.0.dist-info → diagram_to_iac-1.4.0.dist-info}/METADATA +2 -2
- {diagram_to_iac-1.3.0.dist-info → diagram_to_iac-1.4.0.dist-info}/RECORD +9 -9
- {diagram_to_iac-1.3.0.dist-info → diagram_to_iac-1.4.0.dist-info}/WHEEL +0 -0
- {diagram_to_iac-1.3.0.dist-info → diagram_to_iac-1.4.0.dist-info}/entry_points.txt +0 -0
- {diagram_to_iac-1.3.0.dist-info → diagram_to_iac-1.4.0.dist-info}/top_level.txt +0 -0
@@ -16,113 +16,104 @@ logger = logging.getLogger(__name__)
|
|
16
16
|
class ConfigLoader:
|
17
17
|
"""
|
18
18
|
Central configuration management for the diagram-to-iac project.
|
19
|
-
Loads configuration from
|
19
|
+
Loads configuration from central config.yaml file with environment variable override capability.
|
20
20
|
"""
|
21
21
|
|
22
|
-
def __init__(self,
|
22
|
+
def __init__(self, config_path: Optional[str] = None):
|
23
23
|
"""
|
24
|
-
Initialize ConfigLoader with optional custom config
|
24
|
+
Initialize ConfigLoader with optional custom config path.
|
25
25
|
|
26
26
|
Args:
|
27
|
-
|
28
|
-
system_config_path: Path to system config file (default: config/system.yaml)
|
27
|
+
config_path: Path to central config file (default: src/diagram_to_iac/config.yaml)
|
29
28
|
"""
|
30
29
|
self.logger = logging.getLogger(self.__class__.__name__)
|
31
30
|
|
32
|
-
# Set default paths
|
33
|
-
|
34
|
-
|
35
|
-
|
31
|
+
# Set default paths (container-safe)
|
32
|
+
if config_path:
|
33
|
+
self.config_path = Path(config_path)
|
34
|
+
else:
|
35
|
+
# Try multiple locations for central config
|
36
|
+
possible_paths = [
|
37
|
+
Path.cwd() / "src" / "diagram_to_iac" / "config.yaml", # Development
|
38
|
+
Path(__file__).parent.parent / "config.yaml", # Package location
|
39
|
+
Path("/workspace/src/diagram_to_iac/config.yaml"), # Container workspace
|
40
|
+
Path("/workspace/config.yaml"), # Container root
|
41
|
+
]
|
42
|
+
self.config_path = None
|
43
|
+
for path in possible_paths:
|
44
|
+
if path.exists():
|
45
|
+
self.config_path = path
|
46
|
+
break
|
47
|
+
# Default to package location if none found (will create defaults)
|
48
|
+
if not self.config_path:
|
49
|
+
self.config_path = Path(__file__).parent.parent / "config.yaml"
|
36
50
|
|
37
|
-
# Cache for loaded
|
38
|
-
self.
|
39
|
-
self._system_config = None
|
40
|
-
self._merged_config = None
|
51
|
+
# Cache for loaded config
|
52
|
+
self._config = None
|
41
53
|
|
42
54
|
@lru_cache(maxsize=1)
|
43
55
|
def get_config(self) -> Dict[str, Any]:
|
44
56
|
"""
|
45
|
-
Get the complete
|
57
|
+
Get the complete configuration with environment variable overrides.
|
46
58
|
|
47
59
|
Returns:
|
48
|
-
|
60
|
+
Configuration dictionary
|
49
61
|
"""
|
50
|
-
if self.
|
51
|
-
self.
|
52
|
-
return self.
|
62
|
+
if self._config is None:
|
63
|
+
self._config = self._load_config()
|
64
|
+
return self._config
|
53
65
|
|
54
|
-
def
|
66
|
+
def _load_config(self) -> Dict[str, Any]:
|
55
67
|
"""
|
56
|
-
Load
|
68
|
+
Load configuration from central config file.
|
57
69
|
|
58
70
|
Returns:
|
59
|
-
|
71
|
+
Configuration dictionary with environment overrides applied
|
60
72
|
"""
|
61
|
-
# Load base
|
62
|
-
|
63
|
-
system_config = self._load_system_config()
|
64
|
-
|
65
|
-
# Start with system config as base, overlay app config
|
66
|
-
merged = self._deep_merge(system_config, app_config)
|
73
|
+
# Load base config
|
74
|
+
config = self._load_config_file()
|
67
75
|
|
68
76
|
# Apply environment variable overrides
|
69
|
-
|
77
|
+
config = self._apply_env_overrides(config)
|
70
78
|
|
71
|
-
self.logger.debug("Configuration loaded
|
72
|
-
return
|
73
|
-
|
74
|
-
def _load_app_config(self) -> Dict[str, Any]:
|
75
|
-
"""Load application configuration from YAML file."""
|
76
|
-
if self._app_config is None:
|
77
|
-
try:
|
78
|
-
if self.app_config_path.exists():
|
79
|
-
with open(self.app_config_path, 'r') as f:
|
80
|
-
self._app_config = yaml.safe_load(f) or {}
|
81
|
-
self.logger.debug(f"Loaded app config from {self.app_config_path}")
|
82
|
-
else:
|
83
|
-
self.logger.warning(f"App config file not found: {self.app_config_path}")
|
84
|
-
self._app_config = {}
|
85
|
-
except Exception as e:
|
86
|
-
self.logger.error(f"Failed to load app config: {e}")
|
87
|
-
self._app_config = {}
|
88
|
-
return self._app_config
|
79
|
+
self.logger.debug("Configuration loaded successfully")
|
80
|
+
return config
|
89
81
|
|
90
|
-
def
|
91
|
-
"""Load
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
self.logger.debug(f"Loaded system config from {self.system_config_path}")
|
98
|
-
else:
|
99
|
-
self.logger.warning(f"System config file not found: {self.system_config_path}")
|
100
|
-
self._system_config = {}
|
101
|
-
except Exception as e:
|
102
|
-
self.logger.error(f"Failed to load system config: {e}")
|
103
|
-
self._system_config = {}
|
104
|
-
return self._system_config
|
105
|
-
|
106
|
-
def _deep_merge(self, base: Dict[str, Any], overlay: Dict[str, Any]) -> Dict[str, Any]:
|
107
|
-
"""
|
108
|
-
Deep merge two dictionaries, with overlay taking precedence.
|
109
|
-
|
110
|
-
Args:
|
111
|
-
base: Base dictionary
|
112
|
-
overlay: Dictionary to overlay on base
|
113
|
-
|
114
|
-
Returns:
|
115
|
-
Merged dictionary
|
116
|
-
"""
|
117
|
-
result = base.copy()
|
118
|
-
|
119
|
-
for key, value in overlay.items():
|
120
|
-
if key in result and isinstance(result[key], dict) and isinstance(value, dict):
|
121
|
-
result[key] = self._deep_merge(result[key], value)
|
82
|
+
def _load_config_file(self) -> Dict[str, Any]:
|
83
|
+
"""Load configuration from central YAML file."""
|
84
|
+
try:
|
85
|
+
if self.config_path.exists():
|
86
|
+
with open(self.config_path, 'r') as f:
|
87
|
+
config = yaml.safe_load(f) or {}
|
88
|
+
self.logger.debug(f"Loaded config from {self.config_path}")
|
122
89
|
else:
|
123
|
-
|
124
|
-
|
125
|
-
|
90
|
+
self.logger.warning(f"Config file not found at {self.config_path}, using built-in defaults")
|
91
|
+
config = self._get_default_config()
|
92
|
+
except Exception as e:
|
93
|
+
self.logger.error(f"Failed to load config: {e}")
|
94
|
+
config = self._get_default_config()
|
95
|
+
return config
|
96
|
+
|
97
|
+
def _get_default_config(self) -> Dict[str, Any]:
|
98
|
+
"""Get default configuration when config file is not available."""
|
99
|
+
return {
|
100
|
+
'system': {
|
101
|
+
'workspace_base': '/workspace',
|
102
|
+
'log_level': 'INFO'
|
103
|
+
},
|
104
|
+
'network': {
|
105
|
+
'api_timeout': 10,
|
106
|
+
'shell_timeout': 30,
|
107
|
+
'terraform_timeout': 300,
|
108
|
+
'github_timeout': 15,
|
109
|
+
'git_timeout': 300
|
110
|
+
},
|
111
|
+
'ai': {
|
112
|
+
'default_model': 'gpt-4o-mini',
|
113
|
+
'default_temperature': 0.1,
|
114
|
+
'max_tokens': 1000
|
115
|
+
}
|
116
|
+
}
|
126
117
|
|
127
118
|
def _apply_env_overrides(self, config: Dict[str, Any]) -> Dict[str, Any]:
|
128
119
|
"""
|
@@ -246,10 +237,8 @@ class ConfigLoader:
|
|
246
237
|
return default
|
247
238
|
|
248
239
|
def reload(self) -> None:
|
249
|
-
"""Reload configuration from
|
250
|
-
self.
|
251
|
-
self._system_config = None
|
252
|
-
self._merged_config = None
|
240
|
+
"""Reload configuration from file (clears cache)."""
|
241
|
+
self._config = None
|
253
242
|
self.get_config.cache_clear()
|
254
243
|
self.logger.debug("Configuration cache cleared, will reload on next access")
|
255
244
|
|
@@ -4,6 +4,13 @@ import json
|
|
4
4
|
import os
|
5
5
|
from pathlib import Path
|
6
6
|
|
7
|
+
try:
|
8
|
+
from .config_loader import get_config_value
|
9
|
+
except ImportError:
|
10
|
+
# Fallback for tests or standalone usage
|
11
|
+
def get_config_value(path: str, default: Any = None) -> Any:
|
12
|
+
return default
|
13
|
+
|
7
14
|
# Abstract base for memory implementations
|
8
15
|
class MemoryInterface(ABC):
|
9
16
|
"""Abstract interface for agent memory systems."""
|
@@ -94,11 +101,21 @@ class PersistentFileMemory(MemoryInterface):
|
|
94
101
|
|
95
102
|
def __init__(self, file_path: Optional[str] = None):
|
96
103
|
if file_path is None:
|
97
|
-
#
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
104
|
+
# Get workspace base from config with fallback
|
105
|
+
workspace_base = get_config_value("system.workspace_base", "/workspace")
|
106
|
+
|
107
|
+
# Default to workspace or /tmp directory for container safety
|
108
|
+
try:
|
109
|
+
# Try workspace first (from config)
|
110
|
+
base_dir = Path(workspace_base) if Path(workspace_base).exists() else Path.cwd()
|
111
|
+
data_dir = base_dir / "data" / "db"
|
112
|
+
data_dir.mkdir(parents=True, exist_ok=True)
|
113
|
+
file_path = data_dir / "agent_memory.json"
|
114
|
+
except (PermissionError, OSError):
|
115
|
+
# Fallback to /tmp for container environments
|
116
|
+
data_dir = Path("/tmp") / "diagram_to_iac" / "data" / "db"
|
117
|
+
data_dir.mkdir(parents=True, exist_ok=True)
|
118
|
+
file_path = data_dir / "agent_memory.json"
|
102
119
|
|
103
120
|
self.file_path = Path(file_path)
|
104
121
|
self._state: Dict[str, Any] = {}
|
diagram_to_iac/core/registry.py
CHANGED
@@ -33,6 +33,8 @@ from enum import Enum
|
|
33
33
|
|
34
34
|
from pydantic import BaseModel, Field, field_validator
|
35
35
|
|
36
|
+
from .config_loader import get_config_value
|
37
|
+
|
36
38
|
|
37
39
|
class RunStatus(str, Enum):
|
38
40
|
"""Status values for deployment runs."""
|
@@ -126,9 +128,27 @@ class RunRegistry:
|
|
126
128
|
if registry_path:
|
127
129
|
self.registry_path = Path(registry_path)
|
128
130
|
else:
|
129
|
-
#
|
130
|
-
|
131
|
-
|
131
|
+
# Get workspace base from config (with fallback)
|
132
|
+
workspace_base = get_config_value("system.workspace_base", "/workspace")
|
133
|
+
|
134
|
+
# Try multiple locations for registry file
|
135
|
+
possible_paths = [
|
136
|
+
Path.cwd() / "data" / "state" / "issue_registry.json", # Development
|
137
|
+
Path(workspace_base) / "data" / "state" / "issue_registry.json", # Container workspace
|
138
|
+
Path("/tmp/diagram_to_iac/data/state/issue_registry.json"), # Container fallback
|
139
|
+
]
|
140
|
+
self.registry_path = None
|
141
|
+
for path in possible_paths:
|
142
|
+
try:
|
143
|
+
path.parent.mkdir(parents=True, exist_ok=True)
|
144
|
+
self.registry_path = path
|
145
|
+
break
|
146
|
+
except (PermissionError, OSError):
|
147
|
+
continue
|
148
|
+
|
149
|
+
# Final fallback if all locations fail
|
150
|
+
if not self.registry_path:
|
151
|
+
self.registry_path = Path("/tmp/issue_registry.json")
|
132
152
|
|
133
153
|
# Ensure the directory exists
|
134
154
|
self.registry_path.parent.mkdir(parents=True, exist_ok=True)
|
@@ -46,9 +46,20 @@ class LLMRouter:
|
|
46
46
|
def _load_model_policy(self, config_path: Optional[str] = None) -> Dict[str, Any]:
|
47
47
|
"""Load model policy from YAML configuration."""
|
48
48
|
if config_path is None:
|
49
|
-
#
|
50
|
-
|
51
|
-
|
49
|
+
# Try multiple locations for model policy config
|
50
|
+
possible_paths = [
|
51
|
+
Path.cwd() / "config" / "model_policy.yaml", # Development
|
52
|
+
Path("/workspace/config/model_policy.yaml"), # Container workspace
|
53
|
+
Path(__file__).parent.parent.parent.parent.parent / "config" / "model_policy.yaml", # Package fallback
|
54
|
+
]
|
55
|
+
config_path = None
|
56
|
+
for path in possible_paths:
|
57
|
+
if path.exists():
|
58
|
+
config_path = path
|
59
|
+
break
|
60
|
+
# Default to workspace location if none found
|
61
|
+
if not config_path:
|
62
|
+
config_path = Path.cwd() / "config" / "model_policy.yaml"
|
52
63
|
|
53
64
|
try:
|
54
65
|
with open(config_path, 'r') as f:
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: diagram-to-iac
|
3
|
-
Version: 1.
|
3
|
+
Version: 1.4.0
|
4
4
|
Summary: Convert architecture diagrams into IaC modules
|
5
5
|
Author-email: vindpro <admin@vindpro.com>
|
6
6
|
Description-Content-Type: text/markdown
|
@@ -10,7 +10,7 @@ Requires-Dist: langchain_anthropic==0.3.16
|
|
10
10
|
Requires-Dist: langchain-core<1.0.0,>=0.3.62
|
11
11
|
Requires-Dist: langchain_google_genai==2.1.5
|
12
12
|
Requires-Dist: langchain_openai==0.3.26
|
13
|
-
Requires-Dist: langgraph==0.
|
13
|
+
Requires-Dist: langgraph==0.5.0
|
14
14
|
Requires-Dist: openai==1.92.2
|
15
15
|
Requires-Dist: protobuf>=5.27.0
|
16
16
|
Requires-Dist: pydantic==2.11.7
|
@@ -33,12 +33,12 @@ diagram_to_iac/agents/terraform_langgraph/agent.py,sha256=lDaRCLcqShZiUGN25R-T94
|
|
33
33
|
diagram_to_iac/agents/terraform_langgraph/parser.py,sha256=J56CPlpIEIPuDHeAOL3sz4TiIgqLi7raPlX7jwFrAms,2039
|
34
34
|
diagram_to_iac/core/__init__.py,sha256=VjXPYLIS2SAPIDniBkeA2EDK0VHJvdaKIC8dzVneaTM,140
|
35
35
|
diagram_to_iac/core/agent_base.py,sha256=DjZjcfzDpEhfIOki00XwQ-4lPli3OBcQ_7RNKsT7JSI,505
|
36
|
-
diagram_to_iac/core/config_loader.py,sha256=
|
37
|
-
diagram_to_iac/core/enhanced_memory.py,sha256=
|
36
|
+
diagram_to_iac/core/config_loader.py,sha256=6WWOp6G7_xYUhm1x62sVa-7kFlCthcthbppmeGz1YsM,9276
|
37
|
+
diagram_to_iac/core/enhanced_memory.py,sha256=fJ8r-MREZRnm6Rg01CDCicMEx-dDxDEjJgrk8rnVc5Y,11761
|
38
38
|
diagram_to_iac/core/errors.py,sha256=gZwZocnIcBlS4YccIBdjG8XztRCtMe4Cu6KWxLzebDM,115
|
39
39
|
diagram_to_iac/core/issue_tracker.py,sha256=0eo289hn94yCoFCkLaYiDOIJBjk33i2dk6eLeYe_9YE,1659
|
40
40
|
diagram_to_iac/core/memory.py,sha256=P9URX8m2nab65ZPF36uf6Z9hEXQGXrjrXa8dPXG7pm8,4444
|
41
|
-
diagram_to_iac/core/registry.py,sha256=
|
41
|
+
diagram_to_iac/core/registry.py,sha256=ibdMz68W7qkwF0dprt4ni5pekgJfAPuRgL85uRU7wHY,26632
|
42
42
|
diagram_to_iac/services/__init__.py,sha256=I5R8g7vYX4tCldRf1Jf9vEhm5mylc-MfFicqLnY6a3E,238
|
43
43
|
diagram_to_iac/services/commenter.py,sha256=iXvHXOeih64FbE34PuGPk6fhI4RmC62ZSVtFwmMqiOA,22146
|
44
44
|
diagram_to_iac/services/observability.py,sha256=yxbnjMc4TO1SM8RZZMHf2E8uVOLpxFhiTjsTkymDi6Y,1856
|
@@ -58,12 +58,12 @@ diagram_to_iac/tools/llm_utils/base_driver.py,sha256=sDUxk6_iNn3WU_HyRz2hW3YGTn8
|
|
58
58
|
diagram_to_iac/tools/llm_utils/gemini_driver.py,sha256=VO1mJ3o10oSFo5hTBs6h8TJsXyAuah4FRr6Ua-9aNYc,3794
|
59
59
|
diagram_to_iac/tools/llm_utils/grok_driver.py,sha256=hcq4m6ZEgjVsLXaaGlW5SWHEqyjY4KUDy88xSZFUa6Y,2955
|
60
60
|
diagram_to_iac/tools/llm_utils/openai_driver.py,sha256=ZqzXEYEutwqRw3qWx-GH85Mj2afxK4NlhCOMq_MabqQ,3962
|
61
|
-
diagram_to_iac/tools/llm_utils/router.py,sha256=
|
61
|
+
diagram_to_iac/tools/llm_utils/router.py,sha256=ga8xfmPMl_SGINDwazeAAFYTAx9L_IQcVV5AdvqD0dQ,22643
|
62
62
|
diagram_to_iac/tools/shell/__init__.py,sha256=6UZjBcnbPabA6Qy7t4j-dCi3S2sE6sB2bTE9PIL98bA,292
|
63
63
|
diagram_to_iac/tools/shell/shell.py,sha256=ZOJ7Vo3l_R2Gm6Ml2FL0RX__-C_JOsUrLJVvBMwAy9E,21122
|
64
64
|
diagram_to_iac/tools/tf/terraform.py,sha256=j1boWRo6JKpNGf1OwnWoWboO0gMYTizCOHDSxozoFZw,37343
|
65
|
-
diagram_to_iac-1.
|
66
|
-
diagram_to_iac-1.
|
67
|
-
diagram_to_iac-1.
|
68
|
-
diagram_to_iac-1.
|
69
|
-
diagram_to_iac-1.
|
65
|
+
diagram_to_iac-1.4.0.dist-info/METADATA,sha256=qdDVn1c4C91A_2FrJYoAOPUrAaqI841bMUd7eymUNsM,10428
|
66
|
+
diagram_to_iac-1.4.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
67
|
+
diagram_to_iac-1.4.0.dist-info/entry_points.txt,sha256=DfGCnmgWWGHtQpqU8VqcUWs5k_be-bfO67z1vOuTitA,277
|
68
|
+
diagram_to_iac-1.4.0.dist-info/top_level.txt,sha256=k1cV0YODiCUU46qlmbQaquMcbMXhNm05NZLxsinDUBA,15
|
69
|
+
diagram_to_iac-1.4.0.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|