Skip to content

Commit 268f29c

Browse files
Merge pull request #723 from UiPath/chore/agents_md_override
chore(Agents.md): override the AGENTS.md files on init
2 parents eeb3aa3 + dc3080a commit 268f29c

File tree

3 files changed

+101
-30
lines changed

3 files changed

+101
-30
lines changed

src/uipath/_cli/cli_init.py

Lines changed: 40 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -60,34 +60,49 @@ def generate_env_file(target_directory):
6060
console.success(f"Created '{relative_path}' file.")
6161

6262

63-
def generate_agent_md_file(target_directory: str, file_name: str) -> None:
63+
def generate_agent_md_file(
64+
target_directory: str, file_name: str, no_agents_md_override: bool
65+
) -> bool:
6466
"""Generate an agent-specific file from the packaged resource.
6567
6668
Args:
6769
target_directory: The directory where the file should be created.
6870
file_name: The name of the file should be created.
71+
no_agents_md_override: Whether to override existing files.
6972
"""
7073
target_path = os.path.join(target_directory, file_name)
7174

72-
if os.path.exists(target_path):
73-
logger.debug(f"File '{target_path}' already exists.")
74-
return
75+
will_override = os.path.exists(target_path)
76+
77+
if will_override and no_agents_md_override:
78+
console.success(
79+
f"File {click.style(target_path, fg='cyan')} already exists. Skipping."
80+
)
81+
return False
7582

7683
try:
7784
source_path = importlib.resources.files("uipath._resources").joinpath(file_name)
7885

7986
with importlib.resources.as_file(source_path) as s_path:
8087
shutil.copy(s_path, target_path)
8188

89+
if will_override:
90+
logger.debug(f"File '{target_path}' has been overridden.")
91+
92+
return will_override
93+
8294
except Exception as e:
8395
console.warning(f"Could not create {file_name}: {e}")
8496

97+
return False
98+
8599

86-
def generate_agent_md_files(target_directory: str) -> None:
100+
def generate_agent_md_files(target_directory: str, no_agents_md_override: bool) -> None:
87101
"""Generate an agent-specific file from the packaged resource.
88102
89103
Args:
90104
target_directory: The directory where the files should be created.
105+
no_agents_md_override: Whether to override existing files.
91106
"""
92107
agent_dir = os.path.join(target_directory, ".agent")
93108
os.makedirs(agent_dir, exist_ok=True)
@@ -96,13 +111,21 @@ def generate_agent_md_files(target_directory: str) -> None:
96111

97112
agent_files = ["CLI_REFERENCE.md", "REQUIRED_STRUCTURE.md", "SDK_REFERENCE.md"]
98113

114+
any_overridden = False
115+
99116
for file_name in root_files:
100-
generate_agent_md_file(target_directory, file_name)
117+
if generate_agent_md_file(target_directory, file_name, no_agents_md_override):
118+
any_overridden = True
101119

102120
for file_name in agent_files:
103-
generate_agent_md_file(agent_dir, file_name)
121+
if generate_agent_md_file(agent_dir, file_name, no_agents_md_override):
122+
any_overridden = True
104123

105-
console.success(f"Created {click.style('AGENTS.md', fg='cyan')} file.")
124+
if any_overridden:
125+
console.success(f"Updated {click.style('AGENTS.md', fg='cyan')} related files.")
126+
return
127+
128+
console.success(f"Created {click.style('AGENTS.md', fg='cyan')} related files.")
106129

107130

108131
def get_existing_settings(config_path: str) -> Optional[Dict[str, Any]]:
@@ -149,8 +172,15 @@ def write_config_file(config_data: Dict[str, Any] | RuntimeSchema) -> None:
149172
default=True,
150173
help="Infer bindings from the script.",
151174
)
175+
@click.option(
176+
"--no-agents-md-override",
177+
is_flag=True,
178+
required=False,
179+
default=False,
180+
help="Won't override existing .agent files and AGENTS.md file.",
181+
)
152182
@track
153-
def init(entrypoint: str, infer_bindings: bool) -> None:
183+
def init(entrypoint: str, infer_bindings: bool, no_agents_md_override: bool) -> None:
154184
"""Create uipath.json with input/output schemas and bindings."""
155185
with console.spinner("Initializing UiPath project ..."):
156186
current_directory = os.getcwd()
@@ -175,7 +205,7 @@ def init(entrypoint: str, infer_bindings: bool) -> None:
175205
if not result.should_continue:
176206
return
177207

178-
generate_agent_md_files(current_directory)
208+
generate_agent_md_files(current_directory, no_agents_md_override)
179209
script_path = get_user_script(current_directory, entrypoint=entrypoint)
180210
if not script_path:
181211
return

src/uipath/_resources/CLI_REFERENCE.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ The UiPath Python SDK provides a comprehensive CLI for managing coded agents and
2727
| Option | Type | Default | Description |
2828
|--------|------|---------|-------------|
2929
| `--infer-bindings` | flag | false | Infer bindings from the script. |
30+
| `--no-agents-md-override` | flag | false | Won't override existing .agent files and AGENTS.md file. |
3031

3132
**Usage Examples:**
3233

tests/cli/test_init_agents_md.py

Lines changed: 60 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -44,22 +44,42 @@ def test_generate_agent_md_file_creates_file(self) -> None:
4444
mock_as_file.return_value.__enter__.return_value = mock_source
4545
mock_as_file.return_value.__exit__.return_value = None
4646

47-
generate_agent_md_file(temp_dir, "AGENTS.md")
47+
generate_agent_md_file(temp_dir, "AGENTS.md", False)
4848

4949
assert (Path(temp_dir) / "AGENTS.md").exists()
5050
finally:
5151
os.chdir(original_cwd)
5252

53-
def test_generate_agents_md_skips_existing_file(self) -> None:
54-
"""Test that existing AGENTS.md is not overwritten."""
53+
def test_generate_agents_md_overwrites_existing_file(self) -> None:
54+
"""Test that existing AGENTS.md is overwritten."""
5555
with tempfile.TemporaryDirectory() as temp_dir:
5656
agents_path = Path(temp_dir) / "AGENTS.md"
5757
original_content = "Original content"
5858
agents_path.write_text(original_content)
5959

60-
generate_agent_md_file(temp_dir, "AGENTS.md")
60+
mock_source = (
61+
Path(__file__).parent.parent.parent
62+
/ "src"
63+
/ "uipath"
64+
/ "_resources"
65+
/ "AGENTS.md"
66+
)
6167

62-
assert agents_path.read_text() == original_content
68+
with (
69+
patch("uipath._cli.cli_init.importlib.resources.files") as mock_files,
70+
patch(
71+
"uipath._cli.cli_init.importlib.resources.as_file"
72+
) as mock_as_file,
73+
):
74+
mock_path = MagicMock()
75+
mock_files.return_value.joinpath.return_value = mock_path
76+
mock_as_file.return_value.__enter__.return_value = mock_source
77+
mock_as_file.return_value.__exit__.return_value = None
78+
79+
generate_agent_md_file(temp_dir, "AGENTS.md", False)
80+
81+
assert agents_path.read_text() != original_content
82+
assert agents_path.exists()
6383

6484
def test_generate_agents_md_handles_errors_gracefully(self) -> None:
6585
"""Test that errors are handled gracefully."""
@@ -70,7 +90,7 @@ def test_generate_agents_md_handles_errors_gracefully(self) -> None:
7090
):
7191
mock_files.side_effect = RuntimeError("Test error")
7292

73-
generate_agent_md_file(temp_dir, "AGENTS.md")
93+
generate_agent_md_file(temp_dir, "AGENTS.md", False)
7494

7595
mock_console.warning.assert_called_once()
7696
assert "Could not create AGENTS.md: Test error" in str(
@@ -100,7 +120,7 @@ def test_generate_agent_md_files_creates_all_files(self) -> None:
100120
mock_as_file.return_value.__enter__.return_value = temp_source
101121
mock_as_file.return_value.__exit__.return_value = None
102122

103-
generate_agent_md_files(temp_dir)
123+
generate_agent_md_files(temp_dir, False)
104124

105125
agent_dir = Path(temp_dir) / ".agent"
106126
assert agent_dir.exists()
@@ -113,8 +133,8 @@ def test_generate_agent_md_files_creates_all_files(self) -> None:
113133
assert (agent_dir / "REQUIRED_STRUCTURE.md").exists()
114134
assert (agent_dir / "SDK_REFERENCE.md").exists()
115135

116-
def test_generate_agent_md_files_skips_existing_files(self) -> None:
117-
"""Test that existing files are not overwritten."""
136+
def test_generate_agent_md_files_overwrites_existing_files(self) -> None:
137+
"""Test that existing files are overwritten."""
118138
with tempfile.TemporaryDirectory() as temp_dir:
119139
agent_dir = Path(temp_dir) / ".agent"
120140
agent_dir.mkdir()
@@ -132,6 +152,7 @@ def test_generate_agent_md_files_skips_existing_files(self) -> None:
132152
patch(
133153
"uipath._cli.cli_init.importlib.resources.as_file"
134154
) as mock_as_file,
155+
patch("uipath._cli.cli_init.console"),
135156
):
136157
temp_source = Path(temp_dir) / "temp_source.md"
137158
temp_source.write_text("Test content")
@@ -141,10 +162,12 @@ def test_generate_agent_md_files_skips_existing_files(self) -> None:
141162
mock_as_file.return_value.__enter__.return_value = temp_source
142163
mock_as_file.return_value.__exit__.return_value = None
143164

144-
generate_agent_md_files(temp_dir)
165+
generate_agent_md_files(temp_dir, False)
145166

146-
assert agents_path.read_text() == agents_content
147-
assert cli_ref_path.read_text() == cli_ref_content
167+
assert agents_path.read_text() != agents_content
168+
assert agents_path.read_text() == "Test content"
169+
assert cli_ref_path.read_text() != cli_ref_content
170+
assert cli_ref_path.read_text() == "Test content"
148171

149172

150173
class TestInitWithAgentsMd:
@@ -187,10 +210,10 @@ def test_init_creates_agent_files_by_default(
187210
assert os.path.exists(".agent/REQUIRED_STRUCTURE.md")
188211
assert os.path.exists(".agent/SDK_REFERENCE.md")
189212

190-
def test_init_does_not_overwrite_existing_agents_md(
213+
def test_init_overwrites_existing_agents_md(
191214
self, runner: CliRunner, temp_dir: str
192215
) -> None:
193-
"""Test that existing AGENTS.md is not overwritten."""
216+
"""Test that existing AGENTS.md is overwritten."""
194217
with runner.isolated_filesystem(temp_dir=temp_dir):
195218
# Create a simple Python file
196219
with open("main.py", "w") as f:
@@ -201,11 +224,28 @@ def test_init_does_not_overwrite_existing_agents_md(
201224
with open("AGENTS.md", "w") as f:
202225
f.write(original_content)
203226

204-
# Run init (AGENTS.md creation is now default)
205-
result = runner.invoke(cli, ["init"])
227+
temp_source = Path(temp_dir) / "temp_source.md"
228+
temp_source.write_text("Test content")
206229

207-
assert result.exit_code == 0
230+
with (
231+
patch("uipath._cli.cli_init.importlib.resources.files") as mock_files,
232+
patch(
233+
"uipath._cli.cli_init.importlib.resources.as_file"
234+
) as mock_as_file,
235+
):
236+
# Setup mocks
237+
mock_path = MagicMock()
238+
mock_files.return_value.joinpath.return_value = mock_path
239+
mock_as_file.return_value.__enter__.return_value = temp_source
240+
mock_as_file.return_value.__exit__.return_value = None
241+
242+
# Run init (AGENTS.md creation is now default)
243+
result = runner.invoke(cli, ["init"])
244+
245+
assert result.exit_code == 0
208246

209-
# Verify content wasn't changed
210-
with open("AGENTS.md", "r") as f:
211-
assert f.read() == original_content
247+
# Verify content was changed
248+
with open("AGENTS.md", "r") as f:
249+
content = f.read()
250+
assert content != original_content
251+
assert content == "Test content"

0 commit comments

Comments
 (0)