diagram-to-iac 1.0.3__tar.gz → 1.0.4__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.
- {diagram_to_iac-1.0.3 → diagram_to_iac-1.0.4}/PKG-INFO +5 -4
- {diagram_to_iac-1.0.3 → diagram_to_iac-1.0.4}/pyproject.toml +2 -2
- diagram_to_iac-1.0.4/src/diagram_to_iac/actions/supervisor_entry.py +278 -0
- {diagram_to_iac-1.0.3 → diagram_to_iac-1.0.4}/src/diagram_to_iac/agents/git_langgraph/agent.py +60 -28
- {diagram_to_iac-1.0.3 → diagram_to_iac-1.0.4}/src/diagram_to_iac/agents/supervisor_langgraph/agent.py +362 -33
- diagram_to_iac-1.0.4/src/diagram_to_iac/agents/supervisor_langgraph/github_listener.py +433 -0
- diagram_to_iac-1.0.4/src/diagram_to_iac/core/registry.py +674 -0
- diagram_to_iac-1.0.4/src/diagram_to_iac/services/commenter.py +589 -0
- {diagram_to_iac-1.0.3 → diagram_to_iac-1.0.4}/src/diagram_to_iac/tools/llm_utils/__init__.py +3 -1
- diagram_to_iac-1.0.4/src/diagram_to_iac/tools/llm_utils/grok_driver.py +71 -0
- {diagram_to_iac-1.0.3 → diagram_to_iac-1.0.4}/src/diagram_to_iac/tools/llm_utils/router.py +220 -30
- {diagram_to_iac-1.0.3 → diagram_to_iac-1.0.4}/src/diagram_to_iac.egg-info/PKG-INFO +5 -4
- {diagram_to_iac-1.0.3 → diagram_to_iac-1.0.4}/src/diagram_to_iac.egg-info/SOURCES.txt +4 -0
- {diagram_to_iac-1.0.3 → diagram_to_iac-1.0.4}/src/diagram_to_iac.egg-info/requires.txt +4 -3
- diagram_to_iac-1.0.3/src/diagram_to_iac/actions/supervisor_entry.py +0 -116
- {diagram_to_iac-1.0.3 → diagram_to_iac-1.0.4}/README.md +0 -0
- {diagram_to_iac-1.0.3 → diagram_to_iac-1.0.4}/setup.cfg +0 -0
- {diagram_to_iac-1.0.3 → diagram_to_iac-1.0.4}/src/diagram_to_iac/__init__.py +0 -0
- {diagram_to_iac-1.0.3 → diagram_to_iac-1.0.4}/src/diagram_to_iac/actions/__init__.py +0 -0
- {diagram_to_iac-1.0.3 → diagram_to_iac-1.0.4}/src/diagram_to_iac/actions/git_entry.py +0 -0
- {diagram_to_iac-1.0.3 → diagram_to_iac-1.0.4}/src/diagram_to_iac/actions/terraform_agent_entry.py +0 -0
- {diagram_to_iac-1.0.3 → diagram_to_iac-1.0.4}/src/diagram_to_iac/agents/__init__.py +0 -0
- {diagram_to_iac-1.0.3 → diagram_to_iac-1.0.4}/src/diagram_to_iac/agents/demonstrator_langgraph/__init__.py +0 -0
- {diagram_to_iac-1.0.3 → diagram_to_iac-1.0.4}/src/diagram_to_iac/agents/demonstrator_langgraph/agent.py +0 -0
- {diagram_to_iac-1.0.3 → diagram_to_iac-1.0.4}/src/diagram_to_iac/agents/git_langgraph/__init__.py +0 -0
- {diagram_to_iac-1.0.3 → diagram_to_iac-1.0.4}/src/diagram_to_iac/agents/git_langgraph/pr.py +0 -0
- {diagram_to_iac-1.0.3 → diagram_to_iac-1.0.4}/src/diagram_to_iac/agents/hello_langgraph/__init__.py +0 -0
- {diagram_to_iac-1.0.3 → diagram_to_iac-1.0.4}/src/diagram_to_iac/agents/hello_langgraph/agent.py +0 -0
- {diagram_to_iac-1.0.3 → diagram_to_iac-1.0.4}/src/diagram_to_iac/agents/policy_agent/__init__.py +0 -0
- {diagram_to_iac-1.0.3 → diagram_to_iac-1.0.4}/src/diagram_to_iac/agents/policy_agent/agent.py +0 -0
- {diagram_to_iac-1.0.3 → diagram_to_iac-1.0.4}/src/diagram_to_iac/agents/policy_agent/integration_example.py +0 -0
- {diagram_to_iac-1.0.3 → diagram_to_iac-1.0.4}/src/diagram_to_iac/agents/policy_agent/tools/__init__.py +0 -0
- {diagram_to_iac-1.0.3 → diagram_to_iac-1.0.4}/src/diagram_to_iac/agents/policy_agent/tools/tfsec_tool.py +0 -0
- {diagram_to_iac-1.0.3 → diagram_to_iac-1.0.4}/src/diagram_to_iac/agents/shell_langgraph/__init__.py +0 -0
- {diagram_to_iac-1.0.3 → diagram_to_iac-1.0.4}/src/diagram_to_iac/agents/shell_langgraph/agent.py +0 -0
- {diagram_to_iac-1.0.3 → diagram_to_iac-1.0.4}/src/diagram_to_iac/agents/shell_langgraph/detector.py +0 -0
- {diagram_to_iac-1.0.3 → diagram_to_iac-1.0.4}/src/diagram_to_iac/agents/supervisor_langgraph/__init__.py +0 -0
- {diagram_to_iac-1.0.3 → diagram_to_iac-1.0.4}/src/diagram_to_iac/agents/supervisor_langgraph/demonstrator.py +0 -0
- {diagram_to_iac-1.0.3 → diagram_to_iac-1.0.4}/src/diagram_to_iac/agents/supervisor_langgraph/guards.py +0 -0
- {diagram_to_iac-1.0.3 → diagram_to_iac-1.0.4}/src/diagram_to_iac/agents/supervisor_langgraph/pat_loop.py +0 -0
- {diagram_to_iac-1.0.3 → diagram_to_iac-1.0.4}/src/diagram_to_iac/agents/supervisor_langgraph/router.py +0 -0
- {diagram_to_iac-1.0.3 → diagram_to_iac-1.0.4}/src/diagram_to_iac/agents/terraform_langgraph/__init__.py +0 -0
- {diagram_to_iac-1.0.3 → diagram_to_iac-1.0.4}/src/diagram_to_iac/agents/terraform_langgraph/agent.py +0 -0
- {diagram_to_iac-1.0.3 → diagram_to_iac-1.0.4}/src/diagram_to_iac/agents/terraform_langgraph/parser.py +0 -0
- {diagram_to_iac-1.0.3 → diagram_to_iac-1.0.4}/src/diagram_to_iac/cli.py +0 -0
- {diagram_to_iac-1.0.3 → diagram_to_iac-1.0.4}/src/diagram_to_iac/core/__init__.py +0 -0
- {diagram_to_iac-1.0.3 → diagram_to_iac-1.0.4}/src/diagram_to_iac/core/agent_base.py +0 -0
- {diagram_to_iac-1.0.3 → diagram_to_iac-1.0.4}/src/diagram_to_iac/core/config_loader.py +0 -0
- {diagram_to_iac-1.0.3 → diagram_to_iac-1.0.4}/src/diagram_to_iac/core/enhanced_memory.py +0 -0
- {diagram_to_iac-1.0.3 → diagram_to_iac-1.0.4}/src/diagram_to_iac/core/errors.py +0 -0
- {diagram_to_iac-1.0.3 → diagram_to_iac-1.0.4}/src/diagram_to_iac/core/issue_tracker.py +0 -0
- {diagram_to_iac-1.0.3 → diagram_to_iac-1.0.4}/src/diagram_to_iac/core/memory.py +0 -0
- {diagram_to_iac-1.0.3 → diagram_to_iac-1.0.4}/src/diagram_to_iac/r2d.py +0 -0
- {diagram_to_iac-1.0.3 → diagram_to_iac-1.0.4}/src/diagram_to_iac/services/__init__.py +0 -0
- {diagram_to_iac-1.0.3 → diagram_to_iac-1.0.4}/src/diagram_to_iac/services/observability.py +0 -0
- {diagram_to_iac-1.0.3 → diagram_to_iac-1.0.4}/src/diagram_to_iac/services/step_summary.py +0 -0
- {diagram_to_iac-1.0.3 → diagram_to_iac-1.0.4}/src/diagram_to_iac/tools/__init__.py +0 -0
- {diagram_to_iac-1.0.3 → diagram_to_iac-1.0.4}/src/diagram_to_iac/tools/api_utils.py +0 -0
- {diagram_to_iac-1.0.3 → diagram_to_iac-1.0.4}/src/diagram_to_iac/tools/git/__init__.py +0 -0
- {diagram_to_iac-1.0.3 → diagram_to_iac-1.0.4}/src/diagram_to_iac/tools/git/git.py +0 -0
- {diagram_to_iac-1.0.3 → diagram_to_iac-1.0.4}/src/diagram_to_iac/tools/hello/__init__.py +0 -0
- {diagram_to_iac-1.0.3 → diagram_to_iac-1.0.4}/src/diagram_to_iac/tools/hello/cal_utils.py +0 -0
- {diagram_to_iac-1.0.3 → diagram_to_iac-1.0.4}/src/diagram_to_iac/tools/hello/text_utils.py +0 -0
- {diagram_to_iac-1.0.3 → diagram_to_iac-1.0.4}/src/diagram_to_iac/tools/llm_utils/anthropic_driver.py +0 -0
- {diagram_to_iac-1.0.3 → diagram_to_iac-1.0.4}/src/diagram_to_iac/tools/llm_utils/base_driver.py +0 -0
- {diagram_to_iac-1.0.3 → diagram_to_iac-1.0.4}/src/diagram_to_iac/tools/llm_utils/gemini_driver.py +0 -0
- {diagram_to_iac-1.0.3 → diagram_to_iac-1.0.4}/src/diagram_to_iac/tools/llm_utils/openai_driver.py +0 -0
- {diagram_to_iac-1.0.3 → diagram_to_iac-1.0.4}/src/diagram_to_iac/tools/sec_utils.py +0 -0
- {diagram_to_iac-1.0.3 → diagram_to_iac-1.0.4}/src/diagram_to_iac/tools/shell/__init__.py +0 -0
- {diagram_to_iac-1.0.3 → diagram_to_iac-1.0.4}/src/diagram_to_iac/tools/shell/shell.py +0 -0
- {diagram_to_iac-1.0.3 → diagram_to_iac-1.0.4}/src/diagram_to_iac/tools/text_utils.py +0 -0
- {diagram_to_iac-1.0.3 → diagram_to_iac-1.0.4}/src/diagram_to_iac/tools/tf/terraform.py +0 -0
- {diagram_to_iac-1.0.3 → diagram_to_iac-1.0.4}/src/diagram_to_iac.egg-info/dependency_links.txt +0 -0
- {diagram_to_iac-1.0.3 → diagram_to_iac-1.0.4}/src/diagram_to_iac.egg-info/entry_points.txt +0 -0
- {diagram_to_iac-1.0.3 → diagram_to_iac-1.0.4}/src/diagram_to_iac.egg-info/top_level.txt +0 -0
- {diagram_to_iac-1.0.3 → diagram_to_iac-1.0.4}/tests/test_devops_in_a_box.py +0 -0
@@ -1,21 +1,22 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: diagram-to-iac
|
3
|
-
Version: 1.0.
|
3
|
+
Version: 1.0.4
|
4
4
|
Summary: Convert architecture diagrams into IaC modules
|
5
5
|
Author-email: vindpro <admin@vindpro.com>
|
6
6
|
Description-Content-Type: text/markdown
|
7
|
-
Requires-Dist: anthropic==0.
|
7
|
+
Requires-Dist: anthropic==0.55.0
|
8
8
|
Requires-Dist: google_api_python_client==2.173.0
|
9
9
|
Requires-Dist: langchain_anthropic==0.3.15
|
10
10
|
Requires-Dist: langchain-core<1.0.0,>=0.3.62
|
11
11
|
Requires-Dist: langchain_google_genai==2.1.5
|
12
|
-
Requires-Dist: langchain_openai==0.3.
|
12
|
+
Requires-Dist: langchain_openai==0.3.25
|
13
13
|
Requires-Dist: langgraph==0.4.8
|
14
|
-
Requires-Dist: openai==1.
|
14
|
+
Requires-Dist: openai==1.91.0
|
15
15
|
Requires-Dist: protobuf>=5.27.0
|
16
16
|
Requires-Dist: pydantic==2.11.7
|
17
17
|
Requires-Dist: PyYAML==6.0.2
|
18
18
|
Requires-Dist: Requests==2.32.4
|
19
|
+
Requires-Dist: typing_extensions==4.14.0
|
19
20
|
Requires-Dist: GitPython<4.0,>=3.1
|
20
21
|
|
21
22
|
# diagram-to-iac
|
@@ -4,11 +4,11 @@ build-backend = "setuptools.build_meta"
|
|
4
4
|
|
5
5
|
[project]
|
6
6
|
name = "diagram-to-iac"
|
7
|
-
version = "1.0.
|
7
|
+
version = "1.0.4"
|
8
8
|
description = "Convert architecture diagrams into IaC modules"
|
9
9
|
readme = "README.md"
|
10
10
|
authors = [{ name="vindpro", email="admin@vindpro.com" }]
|
11
|
-
dependencies = ["anthropic==0.
|
11
|
+
dependencies = ["anthropic==0.55.0", "google_api_python_client==2.173.0", "langchain_anthropic==0.3.15", "langchain-core>=0.3.62,<1.0.0", "langchain_google_genai==2.1.5", "langchain_openai==0.3.25", "langgraph==0.4.8", "openai==1.91.0", "protobuf>=5.27.0", "pydantic==2.11.7", "PyYAML==6.0.2", "Requests==2.32.4", "typing_extensions==4.14.0", "GitPython>=3.1,<4.0"] # ← always overwritten by update_deps.py
|
12
12
|
|
13
13
|
|
14
14
|
|
@@ -0,0 +1,278 @@
|
|
1
|
+
"""CLI entrypoint for SupervisorAgent."""
|
2
|
+
|
3
|
+
import argparse
|
4
|
+
import json
|
5
|
+
import sys
|
6
|
+
import logging
|
7
|
+
import os
|
8
|
+
from datetime import datetime
|
9
|
+
from pathlib import Path
|
10
|
+
from typing import Optional
|
11
|
+
|
12
|
+
from diagram_to_iac.agents.supervisor_langgraph import (
|
13
|
+
SupervisorAgent,
|
14
|
+
SupervisorAgentInput,
|
15
|
+
)
|
16
|
+
from diagram_to_iac.agents.supervisor_langgraph.github_listener import (
|
17
|
+
GitHubListener,
|
18
|
+
RetryContext,
|
19
|
+
CommentEvent,
|
20
|
+
create_github_listener
|
21
|
+
)
|
22
|
+
from diagram_to_iac.core.registry import RunRegistry, RunStatus
|
23
|
+
from diagram_to_iac.services import get_log_path, generate_step_summary, reset_log_bus
|
24
|
+
|
25
|
+
|
26
|
+
def setup_logging(verbose: bool = False) -> None:
|
27
|
+
level = logging.DEBUG if verbose else logging.INFO
|
28
|
+
logging.basicConfig(
|
29
|
+
level=level,
|
30
|
+
format="%(asctime)s - %(name)s - %(levelname)s - %(message)s",
|
31
|
+
datefmt="%Y-%m-%d %H:%M:%S",
|
32
|
+
)
|
33
|
+
|
34
|
+
|
35
|
+
def create_argument_parser() -> argparse.ArgumentParser:
|
36
|
+
parser = argparse.ArgumentParser(
|
37
|
+
prog="supervisor-agent",
|
38
|
+
description="SupervisorAgent CLI - R2D (Repo-to-Deployment) automation",
|
39
|
+
)
|
40
|
+
parser.add_argument("--repo-url", help="Repository URL to operate on")
|
41
|
+
parser.add_argument("--branch-name", help="Branch name (deprecated - supervisor skips branch creation)")
|
42
|
+
parser.add_argument("--thread-id", help="Optional thread id")
|
43
|
+
parser.add_argument("--verbose", action="store_true", help="Enable verbose logging")
|
44
|
+
parser.add_argument("--no-interactive", action="store_true", help="Skip interactive prompts")
|
45
|
+
parser.add_argument("--dry-run", action="store_true", help="Print issue text instead of creating it")
|
46
|
+
|
47
|
+
# Comment listener options
|
48
|
+
parser.add_argument("--listen-comments", action="store_true",
|
49
|
+
help="Enable GitHub comment listening for retry commands")
|
50
|
+
parser.add_argument("--issue-id", type=int, help="Issue ID to monitor for comments")
|
51
|
+
parser.add_argument("--poll-interval", type=int, default=30,
|
52
|
+
help="Comment polling interval in seconds (default: 30)")
|
53
|
+
parser.add_argument("--max-polls", type=int,
|
54
|
+
help="Maximum number of polls (default: infinite)")
|
55
|
+
|
56
|
+
return parser
|
57
|
+
|
58
|
+
|
59
|
+
def prompt_for_repo_url() -> str:
|
60
|
+
"""Prompt the user for a repository URL."""
|
61
|
+
try:
|
62
|
+
return input("Repository URL: ").strip()
|
63
|
+
except (KeyboardInterrupt, EOFError):
|
64
|
+
print("\n⚠️ Repository URL required")
|
65
|
+
sys.exit(1)
|
66
|
+
|
67
|
+
|
68
|
+
def format_output(result: object) -> str:
|
69
|
+
try:
|
70
|
+
if hasattr(result, "model_dump"):
|
71
|
+
return json.dumps(result.model_dump(), indent=2)
|
72
|
+
return json.dumps(result, indent=2, default=str)
|
73
|
+
except Exception as e:
|
74
|
+
logging.warning(f"Failed to serialize output: {e}")
|
75
|
+
return str(result)
|
76
|
+
|
77
|
+
|
78
|
+
def handle_resume_workflow(context: RetryContext) -> bool:
|
79
|
+
"""
|
80
|
+
Handle resuming an existing workflow.
|
81
|
+
|
82
|
+
Args:
|
83
|
+
context: RetryContext with resumption information
|
84
|
+
|
85
|
+
Returns:
|
86
|
+
True if resumption was successful, False otherwise
|
87
|
+
"""
|
88
|
+
logger = logging.getLogger("supervisor_entry")
|
89
|
+
|
90
|
+
if not context.existing_run:
|
91
|
+
logger.error("No existing run to resume")
|
92
|
+
return False
|
93
|
+
|
94
|
+
try:
|
95
|
+
logger.info(f"Resuming run {context.existing_run.run_key}")
|
96
|
+
|
97
|
+
# Initialize registry and SupervisorAgent
|
98
|
+
registry = RunRegistry()
|
99
|
+
agent = SupervisorAgent(registry=registry)
|
100
|
+
|
101
|
+
# Update run status to clear wait reason if PAT is now available
|
102
|
+
pat_available = os.getenv('TFE_TOKEN') is not None
|
103
|
+
if pat_available and context.existing_run.status == RunStatus.WAITING_FOR_PAT:
|
104
|
+
logger.info("PAT token now available, clearing wait reason")
|
105
|
+
registry.update(context.existing_run.run_key, {
|
106
|
+
'status': RunStatus.IN_PROGRESS,
|
107
|
+
'wait_reason': None
|
108
|
+
})
|
109
|
+
|
110
|
+
# Resume the workflow from where it left off
|
111
|
+
reset_log_bus()
|
112
|
+
result = agent.resume_workflow(
|
113
|
+
context.existing_run.run_key,
|
114
|
+
context.target_sha or context.existing_run.commit_sha
|
115
|
+
)
|
116
|
+
|
117
|
+
logger.info(f"Resume workflow result: {result.success}")
|
118
|
+
return result.success
|
119
|
+
|
120
|
+
except Exception as e:
|
121
|
+
logger.error(f"Error resuming workflow: {e}")
|
122
|
+
return False
|
123
|
+
|
124
|
+
|
125
|
+
def handle_new_workflow(context: RetryContext) -> bool:
|
126
|
+
"""
|
127
|
+
Handle starting a new workflow for manual retry requests.
|
128
|
+
|
129
|
+
Args:
|
130
|
+
context: RetryContext with new workflow information
|
131
|
+
|
132
|
+
Returns:
|
133
|
+
True if new workflow was started successfully, False otherwise
|
134
|
+
"""
|
135
|
+
logger = logging.getLogger("supervisor_entry")
|
136
|
+
|
137
|
+
try:
|
138
|
+
logger.info(f"Starting new workflow for SHA {context.target_sha[:7] if context.target_sha else 'unknown'}")
|
139
|
+
|
140
|
+
# Initialize SupervisorAgent
|
141
|
+
agent = SupervisorAgent()
|
142
|
+
|
143
|
+
# Start new workflow
|
144
|
+
reset_log_bus()
|
145
|
+
result = agent.run(SupervisorAgentInput(
|
146
|
+
repo_url=context.comment_event.repo_url,
|
147
|
+
branch_name="main", # Placeholder - supervisor handles this
|
148
|
+
thread_id=f"retry-{context.comment_event.comment_id}",
|
149
|
+
commit_sha=context.target_sha
|
150
|
+
))
|
151
|
+
|
152
|
+
logger.info(f"New workflow result: {result.success}")
|
153
|
+
return result.success
|
154
|
+
|
155
|
+
except Exception as e:
|
156
|
+
logger.error(f"Error starting new workflow: {e}")
|
157
|
+
return False
|
158
|
+
|
159
|
+
|
160
|
+
def start_comment_listener(repo_url: str, issue_id: int, poll_interval: int = 30,
|
161
|
+
max_polls: Optional[int] = None) -> None:
|
162
|
+
"""
|
163
|
+
Start the GitHub comment listener.
|
164
|
+
|
165
|
+
Args:
|
166
|
+
repo_url: Repository URL to monitor
|
167
|
+
issue_id: Issue ID to monitor for comments
|
168
|
+
poll_interval: Seconds between polls
|
169
|
+
max_polls: Maximum number of polls
|
170
|
+
"""
|
171
|
+
logger = logging.getLogger("supervisor_entry")
|
172
|
+
|
173
|
+
try:
|
174
|
+
# Create GitHub listener with callbacks
|
175
|
+
github_token = os.getenv('GITHUB_TOKEN')
|
176
|
+
registry = RunRegistry()
|
177
|
+
listener = create_github_listener(github_token=github_token, registry=registry)
|
178
|
+
|
179
|
+
# Set up callbacks
|
180
|
+
listener.set_callbacks(
|
181
|
+
resume_callback=handle_resume_workflow,
|
182
|
+
new_run_callback=handle_new_workflow
|
183
|
+
)
|
184
|
+
|
185
|
+
logger.info(f"Starting comment listener for issue #{issue_id} in {repo_url}")
|
186
|
+
logger.info(f"Poll interval: {poll_interval}s, Max polls: {max_polls or 'infinite'}")
|
187
|
+
|
188
|
+
# Start polling
|
189
|
+
listener.poll_issue_comments(
|
190
|
+
issue_id=issue_id,
|
191
|
+
repo_url=repo_url,
|
192
|
+
poll_interval=poll_interval,
|
193
|
+
max_polls=max_polls
|
194
|
+
)
|
195
|
+
|
196
|
+
except Exception as e:
|
197
|
+
logger.error(f"Error in comment listener: {e}")
|
198
|
+
raise
|
199
|
+
|
200
|
+
|
201
|
+
def main() -> int:
|
202
|
+
parser = create_argument_parser()
|
203
|
+
args = parser.parse_args()
|
204
|
+
|
205
|
+
setup_logging(args.verbose)
|
206
|
+
|
207
|
+
# Handle comment listening mode
|
208
|
+
if args.listen_comments:
|
209
|
+
if not args.repo_url:
|
210
|
+
parser.error("--repo-url is required when using --listen-comments")
|
211
|
+
if not args.issue_id:
|
212
|
+
parser.error("--issue-id is required when using --listen-comments")
|
213
|
+
|
214
|
+
try:
|
215
|
+
start_comment_listener(
|
216
|
+
repo_url=args.repo_url,
|
217
|
+
issue_id=args.issue_id,
|
218
|
+
poll_interval=args.poll_interval,
|
219
|
+
max_polls=args.max_polls
|
220
|
+
)
|
221
|
+
return 0
|
222
|
+
except KeyboardInterrupt:
|
223
|
+
print("\n⚠️ Comment listener stopped by user")
|
224
|
+
return 0
|
225
|
+
except Exception as e:
|
226
|
+
logging.error(f"Comment listener failed: {e}")
|
227
|
+
return 1
|
228
|
+
|
229
|
+
# Handle normal workflow mode
|
230
|
+
repo_url = args.repo_url
|
231
|
+
if not repo_url and not args.no_interactive:
|
232
|
+
repo_url = prompt_for_repo_url()
|
233
|
+
elif not repo_url:
|
234
|
+
parser.error("--repo-url is required when --no-interactive is used")
|
235
|
+
|
236
|
+
# Branch name is no longer used since supervisor skips branch creation
|
237
|
+
# All errors are handled via GitHub issues instead
|
238
|
+
branch_name = args.branch_name or "main" # Placeholder for compatibility
|
239
|
+
|
240
|
+
agent = SupervisorAgent()
|
241
|
+
|
242
|
+
while True:
|
243
|
+
reset_log_bus()
|
244
|
+
result = agent.run(
|
245
|
+
SupervisorAgentInput(
|
246
|
+
repo_url=repo_url,
|
247
|
+
branch_name=branch_name,
|
248
|
+
thread_id=args.thread_id,
|
249
|
+
dry_run=args.dry_run,
|
250
|
+
)
|
251
|
+
)
|
252
|
+
|
253
|
+
print(format_output(result))
|
254
|
+
|
255
|
+
try:
|
256
|
+
generate_step_summary(get_log_path(), Path("step-summary.md"))
|
257
|
+
except Exception as e: # noqa: BLE001
|
258
|
+
logging.warning(f"Step summary generation failed: {e}")
|
259
|
+
|
260
|
+
if result.success or args.no_interactive:
|
261
|
+
break
|
262
|
+
|
263
|
+
try:
|
264
|
+
choice = input("Retry workflow? [y/N]: ").strip().lower()
|
265
|
+
except (KeyboardInterrupt, EOFError):
|
266
|
+
choice = ""
|
267
|
+
|
268
|
+
if choice != "y":
|
269
|
+
break
|
270
|
+
|
271
|
+
repo_url = prompt_for_repo_url()
|
272
|
+
# No longer prompt for branch name since supervisor skips branch creation
|
273
|
+
|
274
|
+
return 0 if result.success else 1
|
275
|
+
|
276
|
+
|
277
|
+
if __name__ == "__main__":
|
278
|
+
sys.exit(main())
|
{diagram_to_iac-1.0.3 → diagram_to_iac-1.0.4}/src/diagram_to_iac/agents/git_langgraph/agent.py
RENAMED
@@ -69,17 +69,15 @@ class GitAgentInput(BaseModel):
|
|
69
69
|
|
70
70
|
class GitAgentOutput(BaseModel):
|
71
71
|
"""Output schema for GitAgent operations."""
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
72
|
+
success: bool = Field(..., description="Indicates if the operation was successful")
|
73
|
+
created_pr_id: Optional[int] = Field(None, description="ID of the created pull request, if any")
|
74
|
+
pr_url: Optional[str] = Field(None, description="URL of the created pull request, if any")
|
75
|
+
created_issue_id: Optional[int] = Field(None, description="ID of the created issue, if any")
|
76
|
+
issue_url: Optional[str] = Field(None, description="URL of the created issue, if any")
|
77
|
+
summary: Optional[str] = Field(None, description="Summary of the operation result")
|
78
|
+
artifacts: Optional[Dict[str, Any]] = Field(None, description="Optional artifacts returned by the operation")
|
78
79
|
|
79
|
-
|
80
|
-
def answer(self) -> str:
|
81
|
-
"""Alias for result to match learning guide tests."""
|
82
|
-
return self.result
|
80
|
+
model_config = {"extra": "ignore"}
|
83
81
|
|
84
82
|
|
85
83
|
# --- Agent State Definition ---
|
@@ -848,7 +846,7 @@ Important: Only use routing tokens if the input contains actionable DevOps reque
|
|
848
846
|
return "open_issue"
|
849
847
|
elif final_result in ["route_to_shell", "ROUTE_TO_SHELL"]:
|
850
848
|
return "shell_exec"
|
851
|
-
elif final_result
|
849
|
+
elif final_result in ["route_to_create_pr", "ROUTE_TO_CREATE_PR"]:
|
852
850
|
return "create_pr_node"
|
853
851
|
elif final_result in ["route_to_end", "ROUTE_TO_END"]:
|
854
852
|
return END
|
@@ -959,13 +957,37 @@ Important: Only use routing tokens if the input contains actionable DevOps reque
|
|
959
957
|
result=final_result,
|
960
958
|
)
|
961
959
|
|
960
|
+
# Determine success based on whether there was an error
|
961
|
+
success = error_message is None or error_message == ""
|
962
|
+
|
963
|
+
# Extract PR/Issue IDs from URLs if available
|
964
|
+
created_pr_id = None
|
965
|
+
created_issue_id = None
|
966
|
+
if pr_url:
|
967
|
+
# Extract PR ID from GitHub URL pattern
|
968
|
+
import re
|
969
|
+
pr_match = re.search(r'/pull/(\d+)', pr_url)
|
970
|
+
if pr_match:
|
971
|
+
created_pr_id = int(pr_match.group(1))
|
972
|
+
else:
|
973
|
+
# Check if it's an issue URL
|
974
|
+
issue_match = re.search(r'/issues/(\d+)', pr_url)
|
975
|
+
if issue_match:
|
976
|
+
created_issue_id = int(issue_match.group(1))
|
977
|
+
|
962
978
|
output = GitAgentOutput(
|
963
|
-
|
964
|
-
|
965
|
-
|
966
|
-
|
967
|
-
|
968
|
-
|
979
|
+
success=success,
|
980
|
+
created_pr_id=created_pr_id,
|
981
|
+
pr_url=pr_url if created_pr_id else None,
|
982
|
+
created_issue_id=created_issue_id,
|
983
|
+
issue_url=pr_url if created_issue_id else None,
|
984
|
+
summary=final_result,
|
985
|
+
artifacts={
|
986
|
+
"thread_id": current_thread_id,
|
987
|
+
"repo_path": repo_path,
|
988
|
+
"operation_type": operation_type,
|
989
|
+
"error_message": error_message
|
990
|
+
}
|
969
991
|
)
|
970
992
|
return output
|
971
993
|
|
@@ -977,12 +999,18 @@ Important: Only use routing tokens if the input contains actionable DevOps reque
|
|
977
999
|
error=str(e),
|
978
1000
|
)
|
979
1001
|
return GitAgentOutput(
|
980
|
-
|
981
|
-
|
982
|
-
|
983
|
-
|
984
|
-
|
985
|
-
|
1002
|
+
success=False,
|
1003
|
+
created_pr_id=None,
|
1004
|
+
pr_url=None,
|
1005
|
+
created_issue_id=None,
|
1006
|
+
issue_url=None,
|
1007
|
+
summary="An unexpected error occurred during execution.",
|
1008
|
+
artifacts={
|
1009
|
+
"thread_id": current_thread_id,
|
1010
|
+
"repo_path": None, # Or more specifically result_state.get("repo_path") if available
|
1011
|
+
"operation_type": "error",
|
1012
|
+
"error_message": str(e)
|
1013
|
+
}
|
986
1014
|
)
|
987
1015
|
|
988
1016
|
def get_conversation_history(self) -> List[Dict[str, Any]]:
|
@@ -1042,11 +1070,15 @@ Important: Only use routing tokens if the input contains actionable DevOps reque
|
|
1042
1070
|
if isinstance(result, GitAgentOutput):
|
1043
1071
|
report = {
|
1044
1072
|
"status": "completed",
|
1045
|
-
"result": result.
|
1046
|
-
"thread_id": result.thread_id,
|
1047
|
-
"error": result.error_message,
|
1048
|
-
"operation_type": result.operation_type,
|
1049
|
-
"success": result.
|
1073
|
+
"result": result.summary,
|
1074
|
+
"thread_id": result.artifacts.get("thread_id") if result.artifacts else None,
|
1075
|
+
"error": result.artifacts.get("error_message") if result.artifacts else None,
|
1076
|
+
"operation_type": result.artifacts.get("operation_type") if result.artifacts else None,
|
1077
|
+
"success": result.success,
|
1078
|
+
"pr_url": result.pr_url,
|
1079
|
+
"issue_url": result.issue_url,
|
1080
|
+
"created_pr_id": result.created_pr_id,
|
1081
|
+
"created_issue_id": result.created_issue_id
|
1050
1082
|
}
|
1051
1083
|
elif isinstance(result, str):
|
1052
1084
|
report = {
|