devduck 0.4.0__py3-none-any.whl → 0.4.1__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.

Potentially problematic release.


This version of devduck might be problematic. Click here for more details.

devduck/__init__.py CHANGED
@@ -126,168 +126,6 @@ def get_own_source_code():
126
126
  except Exception as e:
127
127
  return f"Error reading own source code: {e}"
128
128
 
129
-
130
- # 🛠️ System prompt tool (with .prompt file persistence)
131
- def system_prompt_tool(
132
- action: str,
133
- prompt: str | None = None,
134
- context: str | None = None,
135
- variable_name: str = "SYSTEM_PROMPT",
136
- ) -> Dict[str, Any]:
137
- """
138
- Manage the agent's system prompt dynamically with file persistence.
139
-
140
- Args:
141
- action: "view", "update", "add_context", or "reset"
142
- prompt: New system prompt text (required for "update")
143
- context: Additional context to prepend (for "add_context")
144
- variable_name: Environment variable name (default: SYSTEM_PROMPT)
145
-
146
- Returns:
147
- Dict with status and content
148
- """
149
- from pathlib import Path
150
- import tempfile
151
-
152
- def _get_prompt_file_path() -> Path:
153
- """Get the .prompt file path in temp directory."""
154
- temp_dir = Path(tempfile.gettempdir()) / ".devduck"
155
- temp_dir.mkdir(exist_ok=True, mode=0o700) # Create with restrictive permissions
156
- return temp_dir / ".prompt"
157
-
158
- def _write_prompt_file(prompt_text: str) -> None:
159
- """Write prompt to .prompt file in temp directory."""
160
- prompt_file = _get_prompt_file_path()
161
- try:
162
- # Create file with restrictive permissions
163
- with open(
164
- prompt_file,
165
- "w",
166
- encoding="utf-8",
167
- opener=lambda path, flags: os.open(path, flags, 0o600),
168
- ) as f:
169
- f.write(prompt_text)
170
- except (OSError, PermissionError):
171
- try:
172
- prompt_file.write_text(prompt_text, encoding="utf-8")
173
- prompt_file.chmod(0o600)
174
- except (OSError, PermissionError):
175
- prompt_file.write_text(prompt_text, encoding="utf-8")
176
-
177
- def _get_system_prompt(var_name: str) -> str:
178
- """Get current system prompt from environment variable."""
179
- return os.environ.get(var_name, "")
180
-
181
- def _update_system_prompt(new_prompt: str, var_name: str) -> None:
182
- """Update system prompt in both environment and .prompt file."""
183
- os.environ[var_name] = new_prompt
184
- if var_name == "SYSTEM_PROMPT":
185
- _write_prompt_file(new_prompt)
186
-
187
- try:
188
- if action == "view":
189
- current = _get_system_prompt(variable_name)
190
- return {
191
- "status": "success",
192
- "content": [
193
- {"text": f"Current system prompt from {variable_name}:{current}"}
194
- ],
195
- }
196
-
197
- elif action == "update":
198
- if not prompt:
199
- return {
200
- "status": "error",
201
- "content": [
202
- {"text": "Error: prompt parameter required for update action"}
203
- ],
204
- }
205
-
206
- _update_system_prompt(prompt, variable_name)
207
-
208
- if variable_name == "SYSTEM_PROMPT":
209
- message = f"System prompt updated (env: {variable_name}, file: .prompt)"
210
- else:
211
- message = f"System prompt updated (env: {variable_name})"
212
-
213
- return {"status": "success", "content": [{"text": message}]}
214
-
215
- elif action == "add_context":
216
- if not context:
217
- return {
218
- "status": "error",
219
- "content": [
220
- {
221
- "text": "Error: context parameter required for add_context action"
222
- }
223
- ],
224
- }
225
-
226
- current = _get_system_prompt(variable_name)
227
- new_prompt = f"{current} {context}" if current else context
228
- _update_system_prompt(new_prompt, variable_name)
229
-
230
- if variable_name == "SYSTEM_PROMPT":
231
- message = f"Context added to system prompt (env: {variable_name}, file: .prompt)"
232
- else:
233
- message = f"Context added to system prompt (env: {variable_name})"
234
-
235
- return {"status": "success", "content": [{"text": message}]}
236
-
237
- elif action == "reset":
238
- os.environ.pop(variable_name, None)
239
-
240
- if variable_name == "SYSTEM_PROMPT":
241
- prompt_file = _get_prompt_file_path()
242
- if prompt_file.exists():
243
- try:
244
- prompt_file.unlink()
245
- except (OSError, PermissionError):
246
- pass
247
- message = (
248
- f"System prompt reset (env: {variable_name}, file: .prompt cleared)"
249
- )
250
- else:
251
- message = f"System prompt reset (env: {variable_name})"
252
-
253
- return {"status": "success", "content": [{"text": message}]}
254
-
255
- elif action == "get":
256
- # Backward compatibility
257
- current = _get_system_prompt(variable_name)
258
- return {
259
- "status": "success",
260
- "content": [{"text": f"System prompt: {current}"}],
261
- }
262
-
263
- elif action == "set":
264
- # Backward compatibility
265
- if prompt is None:
266
- return {"status": "error", "content": [{"text": "No prompt provided"}]}
267
-
268
- if context:
269
- prompt = f"{context} {prompt}"
270
-
271
- _update_system_prompt(prompt, variable_name)
272
- return {
273
- "status": "success",
274
- "content": [{"text": "System prompt updated successfully"}],
275
- }
276
-
277
- else:
278
- return {
279
- "status": "error",
280
- "content": [
281
- {
282
- "text": f"Unknown action '{action}'. Valid: view, update, add_context, reset"
283
- }
284
- ],
285
- }
286
-
287
- except Exception as e:
288
- return {"status": "error", "content": [{"text": f"Error: {str(e)}"}]}
289
-
290
-
291
129
  def view_logs_tool(
292
130
  action: str = "view",
293
131
  lines: int = 100,
@@ -661,6 +499,7 @@ class DevDuck:
661
499
  use_github,
662
500
  create_subagent,
663
501
  store_in_kb,
502
+ system_prompt,
664
503
  )
665
504
 
666
505
  core_tools.extend(
@@ -672,6 +511,7 @@ class DevDuck:
672
511
  use_github,
673
512
  create_subagent,
674
513
  store_in_kb,
514
+ system_prompt
675
515
  ]
676
516
  )
677
517
  except ImportError as e:
@@ -731,17 +571,6 @@ class DevDuck:
731
571
  "strands-agents-tools not installed - core tools unavailable (install with: pip install devduck[all])"
732
572
  )
733
573
 
734
- # Wrap system_prompt_tool with @tool decorator
735
- @tool
736
- def system_prompt(
737
- action: str,
738
- prompt: str = None,
739
- context: str = None,
740
- variable_name: str = "SYSTEM_PROMPT",
741
- ) -> Dict[str, Any]:
742
- """Manage agent system prompt dynamically."""
743
- return system_prompt_tool(action, prompt, context, variable_name)
744
-
745
574
  # Wrap view_logs_tool with @tool decorator
746
575
  @tool
747
576
  def view_logs(
@@ -753,7 +582,7 @@ class DevDuck:
753
582
  return view_logs_tool(action, lines, pattern)
754
583
 
755
584
  # Add built-in tools to the toolset
756
- core_tools.extend([system_prompt, view_logs])
585
+ core_tools.extend([view_logs])
757
586
 
758
587
  # Assign tools
759
588
  self.tools = core_tools
@@ -980,9 +809,20 @@ def weather(action: str, location: str = None) -> Dict[str, Any]:
980
809
  ```
981
810
 
982
811
  ## System Prompt Management:
983
- - Use system_prompt(action='get') to view current prompt
984
- - Use system_prompt(action='set', prompt='new text') to update
985
- - Changes persist in SYSTEM_PROMPT environment variable
812
+ - **View**: system_prompt(action='view') - See current prompt
813
+ - **Update Local**: system_prompt(action='update', prompt='new text') - Updates env var + .prompt file
814
+ - **Update GitHub**: system_prompt(action='update', prompt='text', repository='cagataycali/devduck') - Syncs to repo variables
815
+ - **Variable Name**: system_prompt(action='update', prompt='text', variable_name='CUSTOM_PROMPT') - Use custom var
816
+ - **Add Context**: system_prompt(action='add_context', context='new learning') - Append without replacing
817
+
818
+ ### 🧠 Self-Improvement Pattern:
819
+ When you learn something valuable during conversations:
820
+ 1. Identify the new insight or pattern
821
+ 2. Use system_prompt(action='add_context', context='...') to append it
822
+ 3. Sync to GitHub: system_prompt(action='update', prompt=new_full_prompt, repository='owner/repo')
823
+ 4. New learnings persist across sessions via SYSTEM_PROMPT env var
824
+
825
+ **Repository Integration**: Set repository='cagataycali/devduck' to sync prompts across deployments
986
826
 
987
827
  ## Shell Commands:
988
828
  - Prefix with ! to execute shell commands directly
@@ -1520,9 +1360,20 @@ You have full access to your own source code for self-awareness and self-modific
1520
1360
  - Full bidirectional communication
1521
1361
 
1522
1362
  ## System Prompt Management:
1523
- - Use system_prompt(action='get') to view current prompt
1524
- - Use system_prompt(action='set', prompt='new text') to update
1525
- - Changes persist in SYSTEM_PROMPT environment variable
1363
+ - **View**: system_prompt(action='view') - See current prompt
1364
+ - **Update Local**: system_prompt(action='update', prompt='new text') - Updates env var + .prompt file
1365
+ - **Update GitHub**: system_prompt(action='update', prompt='text', repository='cagataycali/devduck') - Syncs to repo variables
1366
+ - **Variable Name**: system_prompt(action='update', prompt='text', variable_name='CUSTOM_PROMPT') - Use custom var
1367
+ - **Add Context**: system_prompt(action='add_context', context='new learning') - Append without replacing
1368
+
1369
+ ### 🧠 Self-Improvement Pattern:
1370
+ When you learn something valuable during conversations:
1371
+ 1. Identify the new insight or pattern
1372
+ 2. Use system_prompt(action='add_context', context='...') to append it
1373
+ 3. Optionally sync to GitHub: system_prompt(action='update', prompt=new_full_prompt, repository='owner/repo')
1374
+ 4. New learnings persist across sessions via SYSTEM_PROMPT env var
1375
+
1376
+ **Repository Integration**: Set repository='cagataycali/devduck' to sync prompts across deployments
1526
1377
 
1527
1378
  ## Shell Commands:
1528
1379
  - Prefix with ! to execute shell commands directly
devduck/_version.py CHANGED
@@ -28,7 +28,7 @@ version_tuple: VERSION_TUPLE
28
28
  commit_id: COMMIT_ID
29
29
  __commit_id__: COMMIT_ID
30
30
 
31
- __version__ = version = '0.4.0'
32
- __version_tuple__ = version_tuple = (0, 4, 0)
31
+ __version__ = version = '0.4.1'
32
+ __version_tuple__ = version_tuple = (0, 4, 1)
33
33
 
34
34
  __commit_id__ = commit_id = None
@@ -0,0 +1,485 @@
1
+ """System prompt management tool for Strands Agents.
2
+
3
+ This module provides a tool to view and modify system prompts used by the agent.
4
+ It helps with dynamic adaptation of the agent's behavior and capabilities,
5
+ and can persist changes by updating GitHub repository variables.
6
+
7
+ Key Features:
8
+ 1. View current system prompt from any environment variable
9
+ 2. Update system prompt (in-memory and GitHub repository variable)
10
+ 3. Add context information to system prompt
11
+ 4. Reset system prompt to default
12
+ 5. Support for custom variable names (SYSTEM_PROMPT, TOOL_BUILDER_SYSTEM_PROMPT, etc.)
13
+
14
+ Usage Examples:
15
+ ```python
16
+ from strands import Agent
17
+ from protocol_tools import system_prompt
18
+
19
+ agent = Agent(tools=[system_prompt])
20
+
21
+ # View current system prompt (default SYSTEM_PROMPT variable)
22
+ result = agent.tool.system_prompt(action="view")
23
+
24
+ # Update system prompt for tool builder
25
+ result = agent.tool.system_prompt(
26
+ action="update",
27
+ prompt="You are a specialized tool builder agent...",
28
+ repository="owner/repo",
29
+ variable_name="TOOL_BUILDER_SYSTEM_PROMPT",
30
+ )
31
+
32
+ # Work with any custom variable name
33
+ result = agent.tool.system_prompt(
34
+ action="view", variable_name="MY_CUSTOM_PROMPT"
35
+ )
36
+ ```
37
+ """
38
+
39
+ import os
40
+ from typing import Any
41
+
42
+ import requests
43
+ from strands import tool
44
+
45
+
46
+ def _get_github_token() -> str:
47
+ """Get GitHub token from environment variable."""
48
+ return os.environ.get("PAT_TOKEN", os.environ.get("GITHUB_TOKEN", ""))
49
+
50
+
51
+ def _get_github_repository_variable(
52
+ repository: str, name: str, token: str
53
+ ) -> dict[str, Any]:
54
+ """Fetch a GitHub repository variable.
55
+
56
+ Args:
57
+ repository: The repository in format "owner/repo"
58
+ name: The variable name
59
+ token: GitHub token
60
+
61
+ Returns:
62
+ Dictionary with success status, message, and value if successful
63
+ """
64
+ # GitHub API endpoint for repository variables
65
+ url = f"https://api.github.com/repos/{repository}/actions/variables/{name}"
66
+
67
+ headers = {
68
+ "Accept": "application/vnd.github+json",
69
+ "Authorization": f"Bearer {token}",
70
+ "X-GitHub-Api-Version": "2022-11-28",
71
+ }
72
+
73
+ try:
74
+ response = requests.get(url, headers=headers, timeout=30)
75
+
76
+ if response.status_code == 200:
77
+ data = response.json()
78
+ return {
79
+ "success": True,
80
+ "message": f"Variable {name} fetched successfully",
81
+ "value": data.get("value", ""),
82
+ }
83
+ else:
84
+ error_message = (
85
+ f"Failed to fetch variable: {response.status_code} - {response.text}"
86
+ )
87
+ return {"success": False, "message": error_message, "value": ""}
88
+ except Exception as e:
89
+ return {
90
+ "success": False,
91
+ "message": f"Error fetching GitHub variable: {e!s}",
92
+ "value": "",
93
+ }
94
+
95
+
96
+ def _get_system_prompt(
97
+ repository: str | None = None, variable_name: str = "SYSTEM_PROMPT"
98
+ ) -> str:
99
+ """Get the current system prompt.
100
+
101
+ First checks the local environment variable.
102
+ If empty and repository is provided, tries to fetch from GitHub repository variables.
103
+
104
+ Args:
105
+ repository: Optional GitHub repository in format "owner/repo"
106
+ variable_name: Name of the environment/repository variable to use
107
+
108
+ Returns:
109
+ The system prompt string
110
+ """
111
+ # First check local environment
112
+ local_prompt = os.environ.get(variable_name, "")
113
+ if local_prompt:
114
+ return local_prompt
115
+
116
+ # If local is empty and repository is provided, try GitHub
117
+ if repository and not local_prompt:
118
+ token = _get_github_token()
119
+ if token:
120
+ result = _get_github_repository_variable(
121
+ repository=repository, name=variable_name, token=token
122
+ )
123
+
124
+ if result["success"]:
125
+ # Store in local environment for future use
126
+ if result["value"]:
127
+ os.environ[variable_name] = result["value"]
128
+ return str(result["value"])
129
+
130
+ # Default to empty string if nothing found
131
+ return ""
132
+
133
+
134
+ def _update_system_prompt(
135
+ new_prompt: str, variable_name: str = "SYSTEM_PROMPT"
136
+ ) -> None:
137
+ """Update the system prompt in the environment variable."""
138
+ os.environ[variable_name] = new_prompt
139
+
140
+
141
+ def _get_github_event_context() -> str:
142
+ """Get GitHub event context information from environment variables."""
143
+ event_context = []
144
+
145
+ # GitHub repository information
146
+ repo = os.environ.get("GITHUB_REPOSITORY", "")
147
+ if repo:
148
+ event_context.append(f"Repository: {repo}")
149
+
150
+ # Event type
151
+ event_name = os.environ.get("GITHUB_EVENT_NAME", "")
152
+ if event_name:
153
+ event_context.append(f"Event Type: {event_name}")
154
+
155
+ # Actor
156
+ actor = os.environ.get("GITHUB_ACTOR", "")
157
+ if actor:
158
+ event_context.append(f"Actor: {actor}")
159
+
160
+ # Add more GitHub context variables as needed
161
+ return "\n".join(event_context)
162
+
163
+
164
+ def _update_github_repository_variable(
165
+ repository: str, name: str, value: str, token: str
166
+ ) -> dict[str, Any]:
167
+ """Update a GitHub repository variable.
168
+
169
+ Args:
170
+ repository: The repository in format "owner/repo"
171
+ name: The variable name
172
+ value: The variable value
173
+ token: GitHub token
174
+
175
+ Returns:
176
+ Dictionary with status and message
177
+ """
178
+ # GitHub API endpoint for repository variables
179
+ url = f"https://api.github.com/repos/{repository}/actions/variables/{name}"
180
+
181
+ headers = {
182
+ "Accept": "application/vnd.github+json",
183
+ "Authorization": f"Bearer {token}",
184
+ "X-GitHub-Api-Version": "2022-11-28",
185
+ }
186
+
187
+ data = {"name": name, "value": value}
188
+
189
+ response = requests.patch(url, headers=headers, json=data, timeout=30)
190
+
191
+ if response.status_code == 204:
192
+ return {"success": True, "message": f"Variable {name} updated successfully"}
193
+ else:
194
+ error_message = (
195
+ f"Failed to update variable: {response.status_code} - {response.text}"
196
+ )
197
+ return {"success": False, "message": error_message}
198
+
199
+
200
+ @tool
201
+ def system_prompt(
202
+ action: str,
203
+ prompt: str | None = None,
204
+ context: str | None = None,
205
+ repository: str | None = None,
206
+ variable_name: str = "SYSTEM_PROMPT",
207
+ ) -> dict[str, str | list[dict[str, str]]]:
208
+ """Manage the agent's system prompt.
209
+
210
+ This tool allows viewing and modifying the system prompt used by the agent.
211
+ It can be used to adapt the agent's behavior dynamically during runtime
212
+ and can update GitHub repository variables to persist changes.
213
+
214
+ Args:
215
+ action: The action to perform on the system prompt. One of:
216
+ - "view": View the current system prompt
217
+ - "update": Replace the current system prompt
218
+ - "add_context": Add additional context to the system prompt
219
+ - "reset": Reset to default (empty or environment-defined)
220
+ - "get_github_context": Get GitHub event context
221
+ prompt: New system prompt when using the "update" action
222
+ context: Additional context to add when using the "add_context" action
223
+ repository: GitHub repository in format "owner/repo" to update repository
224
+ variable (e.g., "cagataycali/report-agent")
225
+ variable_name: Name of the environment/repository variable to use
226
+ (default: "SYSTEM_PROMPT")
227
+
228
+ Returns:
229
+ A dictionary with the operation status and current system prompt
230
+
231
+ Example:
232
+ ```python
233
+ # View current system prompt
234
+ result = system_prompt(action="view")
235
+
236
+ # Update system prompt in memory
237
+ result = system_prompt(
238
+ action="update", prompt="You are a specialized agent for task X..."
239
+ )
240
+
241
+ # Update GitHub repository variable
242
+ result = system_prompt(
243
+ action="update",
244
+ prompt="You are a specialized agent for task X...",
245
+ repository="owner/repo",
246
+ )
247
+
248
+ # Work with custom variable name
249
+ result = system_prompt(
250
+ action="update",
251
+ prompt="You are a tool builder...",
252
+ repository="owner/repo",
253
+ variable_name="TOOL_BUILDER_SYSTEM_PROMPT",
254
+ )
255
+ ```
256
+ """
257
+ try:
258
+ if action == "view":
259
+ current_prompt = _get_system_prompt(repository, variable_name)
260
+ source = "local environment"
261
+
262
+ if not os.environ.get(variable_name) and repository:
263
+ source = f"GitHub repository {repository}"
264
+
265
+ return {
266
+ "status": "success",
267
+ "content": [
268
+ {
269
+ "text": f"Current system prompt from {variable_name} (from {source}):\n\n{current_prompt}"
270
+ }
271
+ ],
272
+ }
273
+
274
+ elif action == "update":
275
+ if not prompt:
276
+ return {
277
+ "status": "error",
278
+ "content": [
279
+ {
280
+ "text": "Error: prompt parameter is required for the update action"
281
+ }
282
+ ],
283
+ }
284
+
285
+ # Update in-memory environment variable
286
+ _update_system_prompt(prompt, variable_name)
287
+
288
+ # If repository is specified, also update GitHub repository variable
289
+ if repository:
290
+ token = _get_github_token()
291
+ if not token:
292
+ return {
293
+ "status": "error",
294
+ "content": [
295
+ {
296
+ "text": "Error: GitHub token not available. Cannot update repository variable."
297
+ }
298
+ ],
299
+ }
300
+
301
+ result = _update_github_repository_variable(
302
+ repository=repository, name=variable_name, value=prompt, token=token
303
+ )
304
+
305
+ if result["success"]:
306
+ return {
307
+ "status": "success",
308
+ "content": [
309
+ {
310
+ "text": f"System prompt updated successfully in memory ({variable_name})"
311
+ },
312
+ {
313
+ "text": f"GitHub repository variable updated: {result['message']}"
314
+ },
315
+ ],
316
+ }
317
+ else:
318
+ return {
319
+ "status": "error",
320
+ "content": [
321
+ {
322
+ "text": f"System prompt updated successfully in memory ({variable_name})"
323
+ },
324
+ {
325
+ "text": f"GitHub repository variable update failed: {result['message']}"
326
+ },
327
+ ],
328
+ }
329
+
330
+ return {
331
+ "status": "success",
332
+ "content": [
333
+ {
334
+ "text": f"System prompt updated successfully in memory ({variable_name})"
335
+ }
336
+ ],
337
+ }
338
+
339
+ elif action == "add_context":
340
+ if not context:
341
+ return {
342
+ "status": "error",
343
+ "content": [
344
+ {
345
+ "text": "Error: context parameter is required for the add_context action"
346
+ }
347
+ ],
348
+ }
349
+
350
+ current_prompt = _get_system_prompt(repository, variable_name)
351
+ new_prompt = f"{current_prompt}\n\n{context}" if current_prompt else context
352
+ _update_system_prompt(new_prompt, variable_name)
353
+
354
+ # If repository is specified, also update GitHub repository variable
355
+ if repository:
356
+ token = _get_github_token()
357
+ if not token:
358
+ return {
359
+ "status": "error",
360
+ "content": [
361
+ {
362
+ "text": f"Context added to system prompt successfully in memory ({variable_name})"
363
+ },
364
+ {
365
+ "text": "Error: GitHub token not available. Cannot update repository variable."
366
+ },
367
+ ],
368
+ }
369
+
370
+ result = _update_github_repository_variable(
371
+ repository=repository,
372
+ name=variable_name,
373
+ value=new_prompt,
374
+ token=token,
375
+ )
376
+
377
+ if result["success"]:
378
+ return {
379
+ "status": "success",
380
+ "content": [
381
+ {
382
+ "text": f"Context added to system prompt successfully in memory ({variable_name})"
383
+ },
384
+ {
385
+ "text": f"GitHub repository variable updated: {result['message']}"
386
+ },
387
+ ],
388
+ }
389
+ else:
390
+ return {
391
+ "status": "error",
392
+ "content": [
393
+ {
394
+ "text": f"Context added to system prompt successfully in memory ({variable_name})"
395
+ },
396
+ {
397
+ "text": f"GitHub repository variable update failed: {result['message']}"
398
+ },
399
+ ],
400
+ }
401
+
402
+ return {
403
+ "status": "success",
404
+ "content": [
405
+ {
406
+ "text": f"Context added to system prompt successfully ({variable_name})"
407
+ }
408
+ ],
409
+ }
410
+
411
+ elif action == "reset":
412
+ # Reset to empty or environment-defined default
413
+ os.environ.pop(variable_name, None)
414
+
415
+ # If repository is specified, reset GitHub repository variable
416
+ if repository:
417
+ token = _get_github_token()
418
+ if not token:
419
+ return {
420
+ "status": "error",
421
+ "content": [
422
+ {
423
+ "text": f"System prompt reset to default in memory ({variable_name})"
424
+ },
425
+ {
426
+ "text": "Error: GitHub token not available. Cannot update repository variable."
427
+ },
428
+ ],
429
+ }
430
+
431
+ result = _update_github_repository_variable(
432
+ repository=repository, name=variable_name, value="", token=token
433
+ )
434
+
435
+ if result["success"]:
436
+ return {
437
+ "status": "success",
438
+ "content": [
439
+ {
440
+ "text": f"System prompt reset to default in memory ({variable_name})"
441
+ },
442
+ {
443
+ "text": f"GitHub repository variable reset: {result['message']}"
444
+ },
445
+ ],
446
+ }
447
+ else:
448
+ return {
449
+ "status": "error",
450
+ "content": [
451
+ {
452
+ "text": f"System prompt reset to default in memory ({variable_name})"
453
+ },
454
+ {
455
+ "text": f"GitHub repository variable reset failed: {result['message']}"
456
+ },
457
+ ],
458
+ }
459
+
460
+ return {
461
+ "status": "success",
462
+ "content": [
463
+ {"text": f"System prompt reset to default ({variable_name})"}
464
+ ],
465
+ }
466
+
467
+ elif action == "get_github_context":
468
+ github_context = _get_github_event_context()
469
+ return {
470
+ "status": "success",
471
+ "content": [{"text": f"GitHub Event Context:\n\n{github_context}"}],
472
+ }
473
+
474
+ else:
475
+ return {
476
+ "status": "error",
477
+ "content": [
478
+ {
479
+ "text": f"Error: Unknown action '{action}'. Valid actions are view, update, add_context, reset, get_github_context"
480
+ }
481
+ ],
482
+ }
483
+
484
+ except Exception as e:
485
+ return {"status": "error", "content": [{"text": f"Error: {e!s}"}]}
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: devduck
3
- Version: 0.4.0
3
+ Version: 0.4.1
4
4
  Summary: 🦆 Extreme minimalist self-adapting AI agent - one file, self-healing, runtime dependencies
5
5
  Author-email: duck <hey@devduck.dev>
6
6
  License-Expression: MIT
@@ -51,10 +51,22 @@ Minimalist AI that adapts to your environment and fixes itself when things break
51
51
 
52
52
  ## Install
53
53
 
54
+ **Homebrew (macOS/Linux):**
55
+ ```bash
56
+ brew tap cagataycali/devduck
57
+ brew install devduck
58
+ ```
59
+
60
+ **pipx (all platforms):**
54
61
  ```bash
55
62
  pipx install "devduck[all]" # Full install (recommended)
56
63
  ```
57
64
 
65
+ **uvx (instant run, no install):**
66
+ ```bash
67
+ uvx devduck "hello world"
68
+ ```
69
+
58
70
  Requires: Python 3.10+, Ollama (or set `MODEL_PROVIDER`)
59
71
 
60
72
  ## Quick Start
@@ -246,11 +258,22 @@ Log location: `/tmp/devduck/logs/devduck.log`
246
258
  Run DevDuck in CI/CD:
247
259
 
248
260
  ```yaml
249
- - name: DevDuck Analysis
250
- uses: cagataycali/devduck@main
251
- with:
252
- query: "analyze test coverage"
253
- model: "us.anthropic.claude-sonnet-4-20250514-v1:0"
261
+ name: AI Assistant
262
+ on: [issues, pull_request]
263
+
264
+ jobs:
265
+ assistant:
266
+ runs-on: ubuntu-latest
267
+ permissions:
268
+ contents: read
269
+ issues: write
270
+ pull-requests: write
271
+ steps:
272
+ - uses: cagataycali/devduck@main
273
+ with:
274
+ task: "Help with this issue or PR"
275
+ provider: "github"
276
+ model: "openai/o4-mini"
254
277
  ```
255
278
 
256
279
  ---
@@ -1,18 +1,19 @@
1
- devduck/__init__.py,sha256=3Iks5DQyjZgf7Y3AE3SO5Cv3XRKasVDhvs_xr9aU9QA,60387
1
+ devduck/__init__.py,sha256=Sdb1jdyy92bxYaP3kT0UN-8AdejWYoT2IrgiRiCR7XE,55852
2
2
  devduck/__main__.py,sha256=aeF2RR4k7lzSR2X1QKV9XQPCKhtsH0JYUv2etBBqmL0,145
3
- devduck/_version.py,sha256=2_0GUP7yBCXRus-qiJKxQD62z172WSs1sQ6DVpPsbmM,704
3
+ devduck/_version.py,sha256=k7cu0JKra64gmMNU_UfA5sw2eNc_GRvf3QmesiYAy8g,704
4
4
  devduck/test_redduck.py,sha256=nqRchR7d54jWGx7JN5tji2ZV4Ek4L9s-P7hp0mKjA0Y,1773
5
5
  devduck/tools/__init__.py,sha256=mu3V4jL2ACN4f-pnUID_A2p6o3Yc_-V_y9071PduCR0,177
6
6
  devduck/tools/create_subagent.py,sha256=UzRz9BmU4PbTveZROEpZ311aH-u-i6x89gttu-CniAE,24687
7
7
  devduck/tools/install_tools.py,sha256=wm_67b9IfY-2wRuWgxuEKhaSIV5vNfbGmZL3G9dGi2A,10348
8
8
  devduck/tools/mcp_server.py,sha256=Ybp0PcJKW2TOvghsRL-i8Guqc9WokPwOD2bhVgzoj6Q,21490
9
9
  devduck/tools/store_in_kb.py,sha256=-JM-oRQKR3FBubKHFHmXRnZSvi9dVgHxG0lismMgG2k,6861
10
+ devduck/tools/system_prompt.py,sha256=waAdmvRhyulorw_tLqpqUJN_AahuaeF2rXqjMqN7IRY,16905
10
11
  devduck/tools/tcp.py,sha256=HkJ_j1t7hsPMxNL51bYHvPkHoTfro9Nov6vClwvwkEk,21943
11
12
  devduck/tools/use_github.py,sha256=nr3JSGk48mKUobpgW__2gu6lFyUj93a1XRs3I6vH8W4,13682
12
13
  devduck/tools/websocket.py,sha256=lRJZt813iHorVr5UI66Lq-lmaFuLYAfpodeV2gtda7k,16635
13
- devduck-0.4.0.dist-info/licenses/LICENSE,sha256=CVGEiNh6cW1mgAKW83Q0P4xrQEXvqc6W-rb789W_IHM,1060
14
- devduck-0.4.0.dist-info/METADATA,sha256=YIeou0tJig_jTk0xc03I_cy7KL-4zpsvQDtcWORN7Vo,7363
15
- devduck-0.4.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
16
- devduck-0.4.0.dist-info/entry_points.txt,sha256=BAMQaIg_BLZQOTk12bT7hy1dE9oGPLt-_dTbI4cnBnQ,40
17
- devduck-0.4.0.dist-info/top_level.txt,sha256=ySXWlVronp8xHYfQ_Hdfr463e0EnbWuqyuxs94EU7yk,8
18
- devduck-0.4.0.dist-info/RECORD,,
14
+ devduck-0.4.1.dist-info/licenses/LICENSE,sha256=CVGEiNh6cW1mgAKW83Q0P4xrQEXvqc6W-rb789W_IHM,1060
15
+ devduck-0.4.1.dist-info/METADATA,sha256=2rphJUQewjp06O_msTc9x7XKCtGURagV-STJ4jBBNHc,7747
16
+ devduck-0.4.1.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
17
+ devduck-0.4.1.dist-info/entry_points.txt,sha256=BAMQaIg_BLZQOTk12bT7hy1dE9oGPLt-_dTbI4cnBnQ,40
18
+ devduck-0.4.1.dist-info/top_level.txt,sha256=ySXWlVronp8xHYfQ_Hdfr463e0EnbWuqyuxs94EU7yk,8
19
+ devduck-0.4.1.dist-info/RECORD,,