makefile-agent 0.4.0__tar.gz → 0.4.2__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.
- {makefile_agent-0.4.0 → makefile_agent-0.4.2}/PKG-INFO +2 -3
- {makefile_agent-0.4.0 → makefile_agent-0.4.2}/README.md +1 -2
- {makefile_agent-0.4.0 → makefile_agent-0.4.2}/make_agent/agent_core/__init__.py +2 -3
- {makefile_agent-0.4.0 → makefile_agent-0.4.2}/make_agent/agent_core/agent.py +2 -6
- {makefile_agent-0.4.0 → makefile_agent-0.4.2}/make_agent/agent_shell/run.py +1 -1
- {makefile_agent-0.4.0 → makefile_agent-0.4.2}/make_agent/agent_shell/shell.py +44 -13
- makefile_agent-0.4.2/make_agent/agent_shell/user_messages.py +110 -0
- {makefile_agent-0.4.0 → makefile_agent-0.4.2}/make_agent/main.py +8 -17
- {makefile_agent-0.4.0 → makefile_agent-0.4.2}/make_agent/memory/memory.py +15 -0
- {makefile_agent-0.4.0 → makefile_agent-0.4.2}/make_agent/skill_backend.py +0 -5
- {makefile_agent-0.4.0 → makefile_agent-0.4.2}/make_agent/templates/makefile/SYSTEM.md +14 -1
- {makefile_agent-0.4.0 → makefile_agent-0.4.2}/make_agent/tool_handler/handler.py +0 -3
- {makefile_agent-0.4.0 → makefile_agent-0.4.2}/makefile_agent.egg-info/PKG-INFO +2 -3
- {makefile_agent-0.4.0 → makefile_agent-0.4.2}/makefile_agent.egg-info/SOURCES.txt +3 -1
- {makefile_agent-0.4.0 → makefile_agent-0.4.2}/pyproject.toml +1 -1
- {makefile_agent-0.4.0 → makefile_agent-0.4.2}/tests/test_agent.py +44 -65
- {makefile_agent-0.4.0 → makefile_agent-0.4.2}/tests/test_agent_shell.py +10 -2
- {makefile_agent-0.4.0 → makefile_agent-0.4.2}/tests/test_bridge.py +38 -12
- {makefile_agent-0.4.0 → makefile_agent-0.4.2}/tests/test_builtin_tools.py +63 -16
- {makefile_agent-0.4.0 → makefile_agent-0.4.2}/tests/test_commands.py +2 -2
- {makefile_agent-0.4.0 → makefile_agent-0.4.2}/tests/test_compact.py +159 -75
- {makefile_agent-0.4.0 → makefile_agent-0.4.2}/tests/test_main.py +17 -13
- {makefile_agent-0.4.0 → makefile_agent-0.4.2}/tests/test_memory.py +200 -114
- {makefile_agent-0.4.0 → makefile_agent-0.4.2}/tests/test_middleware.py +29 -7
- {makefile_agent-0.4.0 → makefile_agent-0.4.2}/tests/test_parser.py +54 -14
- {makefile_agent-0.4.0 → makefile_agent-0.4.2}/tests/test_tools.py +13 -2
- {makefile_agent-0.4.0 → makefile_agent-0.4.2}/tests/test_trusted_skill.py +28 -8
- makefile_agent-0.4.2/tests/test_user_messages.py +127 -0
- {makefile_agent-0.4.0 → makefile_agent-0.4.2}/LICENSE +0 -0
- {makefile_agent-0.4.0 → makefile_agent-0.4.2}/make_agent/__init__.py +0 -0
- {makefile_agent-0.4.0 → makefile_agent-0.4.2}/make_agent/agent_core/bridge.py +0 -0
- {makefile_agent-0.4.0 → makefile_agent-0.4.2}/make_agent/agent_core/constants.py +0 -0
- {makefile_agent-0.4.0 → makefile_agent-0.4.2}/make_agent/agent_core/events.py +0 -0
- {makefile_agent-0.4.0 → makefile_agent-0.4.2}/make_agent/agent_core/export.py +0 -0
- {makefile_agent-0.4.0 → makefile_agent-0.4.2}/make_agent/agent_core/loop.py +0 -0
- {makefile_agent-0.4.0 → makefile_agent-0.4.2}/make_agent/agent_core/middleware.py +0 -0
- {makefile_agent-0.4.0 → makefile_agent-0.4.2}/make_agent/agent_core/provider.py +0 -0
- {makefile_agent-0.4.0 → makefile_agent-0.4.2}/make_agent/agent_shell/__init__.py +0 -0
- {makefile_agent-0.4.0 → makefile_agent-0.4.2}/make_agent/app_dirs.py +0 -0
- {makefile_agent-0.4.0 → makefile_agent-0.4.2}/make_agent/builtin_tools/__init__.py +0 -0
- {makefile_agent-0.4.0 → makefile_agent-0.4.2}/make_agent/builtin_tools/file_tools.py +0 -0
- {makefile_agent-0.4.0 → makefile_agent-0.4.2}/make_agent/builtin_tools/skill_tools.py +0 -0
- {makefile_agent-0.4.0 → makefile_agent-0.4.2}/make_agent/memory/__init__.py +0 -0
- {makefile_agent-0.4.0 → makefile_agent-0.4.2}/make_agent/memory/tools.py +0 -0
- {makefile_agent-0.4.0 → makefile_agent-0.4.2}/make_agent/parser.py +0 -0
- {makefile_agent-0.4.0 → makefile_agent-0.4.2}/make_agent/protocols.py +0 -0
- {makefile_agent-0.4.0 → makefile_agent-0.4.2}/make_agent/provider/__init__.py +0 -0
- {makefile_agent-0.4.0 → makefile_agent-0.4.2}/make_agent/provider/anthropic.py +0 -0
- {makefile_agent-0.4.0 → makefile_agent-0.4.2}/make_agent/provider/base.py +0 -0
- {makefile_agent-0.4.0 → makefile_agent-0.4.2}/make_agent/provider/openai.py +0 -0
- {makefile_agent-0.4.0 → makefile_agent-0.4.2}/make_agent/tool_display.py +0 -0
- {makefile_agent-0.4.0 → makefile_agent-0.4.2}/make_agent/tool_handler/__init__.py +0 -0
- {makefile_agent-0.4.0 → makefile_agent-0.4.2}/make_agent/tool_handler/runner.py +0 -0
- {makefile_agent-0.4.0 → makefile_agent-0.4.2}/makefile_agent.egg-info/dependency_links.txt +0 -0
- {makefile_agent-0.4.0 → makefile_agent-0.4.2}/makefile_agent.egg-info/entry_points.txt +0 -0
- {makefile_agent-0.4.0 → makefile_agent-0.4.2}/makefile_agent.egg-info/requires.txt +0 -0
- {makefile_agent-0.4.0 → makefile_agent-0.4.2}/makefile_agent.egg-info/top_level.txt +0 -0
- {makefile_agent-0.4.0 → makefile_agent-0.4.2}/setup.cfg +0 -0
- {makefile_agent-0.4.0 → makefile_agent-0.4.2}/tests/test_app_dirs.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: makefile-agent
|
|
3
|
-
Version: 0.4.
|
|
3
|
+
Version: 0.4.2
|
|
4
4
|
Summary: An AI agent powered by Makefile skills.
|
|
5
5
|
Author: Dmitriy Sorochenkov
|
|
6
6
|
License-Expression: MIT
|
|
@@ -91,8 +91,7 @@ Priority order (first match wins):
|
|
|
91
91
|
|
|
92
92
|
1. `--system PROMPT` flag
|
|
93
93
|
2. `--system-file FILE` flag
|
|
94
|
-
3.
|
|
95
|
-
4. `~/.make-agent/<project>/makefile/SYSTEM.md` (created from a bundled template on first run)
|
|
94
|
+
3. `~/.make-agent/<project>/makefile/SYSTEM.md` (created from a bundled template on first run)
|
|
96
95
|
|
|
97
96
|
## Skills
|
|
98
97
|
|
|
@@ -65,8 +65,7 @@ Priority order (first match wins):
|
|
|
65
65
|
|
|
66
66
|
1. `--system PROMPT` flag
|
|
67
67
|
2. `--system-file FILE` flag
|
|
68
|
-
3.
|
|
69
|
-
4. `~/.make-agent/<project>/makefile/SYSTEM.md` (created from a bundled template on first run)
|
|
68
|
+
3. `~/.make-agent/<project>/makefile/SYSTEM.md` (created from a bundled template on first run)
|
|
70
69
|
|
|
71
70
|
## Skills
|
|
72
71
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
from .agent import
|
|
1
|
+
from .agent import AgentManager, SessionNotFoundError
|
|
2
2
|
from .bridge import (
|
|
3
3
|
ApprovalRequested,
|
|
4
4
|
ApproveSkill,
|
|
@@ -11,9 +11,9 @@ from .bridge import (
|
|
|
11
11
|
Shutdown,
|
|
12
12
|
StartTurn,
|
|
13
13
|
StatusChanged,
|
|
14
|
+
TokenEmitted,
|
|
14
15
|
ToolFinished,
|
|
15
16
|
ToolStarted,
|
|
16
|
-
TokenEmitted,
|
|
17
17
|
TurnCancelled,
|
|
18
18
|
TurnFinished,
|
|
19
19
|
TurnStarted,
|
|
@@ -58,7 +58,6 @@ __all__ = [
|
|
|
58
58
|
"DEFAULT_REASONING_EFFORT",
|
|
59
59
|
"DEFAULT_TOOL_TIMEOUT",
|
|
60
60
|
"DEFAULT_USE_PROMPT_CACHE",
|
|
61
|
-
"Agent",
|
|
62
61
|
"AgentConfig",
|
|
63
62
|
"AgentEvent",
|
|
64
63
|
"AgenticLoop",
|
|
@@ -14,9 +14,9 @@ from make_agent.protocols import ToolHandlerProtocol
|
|
|
14
14
|
|
|
15
15
|
from .bridge import (
|
|
16
16
|
ApprovalRequested,
|
|
17
|
+
ApproveSkill,
|
|
17
18
|
CancelTurn,
|
|
18
19
|
DenySkill,
|
|
19
|
-
ApproveSkill,
|
|
20
20
|
HistoryCompacted,
|
|
21
21
|
ManagerError,
|
|
22
22
|
ShellCommand,
|
|
@@ -24,9 +24,9 @@ from .bridge import (
|
|
|
24
24
|
Shutdown,
|
|
25
25
|
StartTurn,
|
|
26
26
|
StatusChanged,
|
|
27
|
+
TokenEmitted,
|
|
27
28
|
ToolFinished,
|
|
28
29
|
ToolStarted,
|
|
29
|
-
TokenEmitted,
|
|
30
30
|
TurnCancelled,
|
|
31
31
|
TurnFinished,
|
|
32
32
|
TurnStarted,
|
|
@@ -56,10 +56,6 @@ from .middleware import MiddlewareBase, Request, Response, SessionMiddleware
|
|
|
56
56
|
logger = logging.getLogger(__name__)
|
|
57
57
|
|
|
58
58
|
|
|
59
|
-
# Backward-compatible alias.
|
|
60
|
-
Agent = AgenticLoop
|
|
61
|
-
|
|
62
|
-
|
|
63
59
|
class SessionNotFoundError(Exception):
|
|
64
60
|
pass
|
|
65
61
|
|
|
@@ -41,7 +41,6 @@ async def run(
|
|
|
41
41
|
compact_mode: str = DEFAULT_COMPACT_MODE,
|
|
42
42
|
) -> None:
|
|
43
43
|
"""Start the interactive shell (or send a single prompt and return)."""
|
|
44
|
-
await tool_handler.setup(model)
|
|
45
44
|
agent_config = AgentConfig(
|
|
46
45
|
system_prompt=system_prompt,
|
|
47
46
|
model=model,
|
|
@@ -74,6 +73,7 @@ async def run(
|
|
|
74
73
|
session_id,
|
|
75
74
|
model=model,
|
|
76
75
|
history_path=project_dir() / "history",
|
|
76
|
+
memory=memory,
|
|
77
77
|
)
|
|
78
78
|
try:
|
|
79
79
|
await shell.run()
|
|
@@ -19,16 +19,6 @@ from pathlib import Path
|
|
|
19
19
|
from typing import Any, Optional
|
|
20
20
|
from uuid import uuid4
|
|
21
21
|
|
|
22
|
-
from prompt_toolkit.application import Application
|
|
23
|
-
from prompt_toolkit.completion import WordCompleter
|
|
24
|
-
from prompt_toolkit.filters import Condition
|
|
25
|
-
from prompt_toolkit.history import FileHistory
|
|
26
|
-
from prompt_toolkit.key_binding import KeyBindings
|
|
27
|
-
from prompt_toolkit.layout import HSplit, Layout, VSplit, Window
|
|
28
|
-
from prompt_toolkit.layout.controls import FormattedTextControl
|
|
29
|
-
from prompt_toolkit.styles import Style
|
|
30
|
-
from prompt_toolkit.widgets import Frame, TextArea
|
|
31
|
-
|
|
32
22
|
from make_agent.agent_core import (
|
|
33
23
|
AgentManager,
|
|
34
24
|
ApprovalRequested,
|
|
@@ -42,14 +32,24 @@ from make_agent.agent_core import (
|
|
|
42
32
|
Shutdown,
|
|
43
33
|
StartTurn,
|
|
44
34
|
StatusChanged,
|
|
35
|
+
TokenEmitted,
|
|
45
36
|
ToolFinished,
|
|
46
37
|
ToolStarted,
|
|
47
|
-
TokenEmitted,
|
|
48
38
|
TurnCancelled,
|
|
49
39
|
TurnFinished,
|
|
50
40
|
TurnStarted,
|
|
51
41
|
)
|
|
42
|
+
from make_agent.memory import Memory
|
|
43
|
+
from prompt_toolkit.application import Application
|
|
44
|
+
from prompt_toolkit.completion import WordCompleter
|
|
45
|
+
from prompt_toolkit.filters import Condition
|
|
46
|
+
from prompt_toolkit.key_binding import KeyBindings
|
|
47
|
+
from prompt_toolkit.layout import HSplit, Layout, VSplit, Window
|
|
48
|
+
from prompt_toolkit.layout.controls import FormattedTextControl
|
|
49
|
+
from prompt_toolkit.styles import Style
|
|
50
|
+
from prompt_toolkit.widgets import Frame, TextArea
|
|
52
51
|
|
|
52
|
+
from .user_messages import UserMessagesManager
|
|
53
53
|
|
|
54
54
|
# ── status / enums ──────────────────────────────────────────────────────────────
|
|
55
55
|
|
|
@@ -299,6 +299,7 @@ class MakeAgentShell:
|
|
|
299
299
|
session_id: str,
|
|
300
300
|
model: str,
|
|
301
301
|
history_path: Path,
|
|
302
|
+
memory: Optional[Memory] = None,
|
|
302
303
|
) -> None:
|
|
303
304
|
self._agent_manager = agent_manager
|
|
304
305
|
self._session_id = session_id
|
|
@@ -310,6 +311,7 @@ class MakeAgentShell:
|
|
|
310
311
|
self._app: Optional[Application] = None
|
|
311
312
|
self._response_area: Optional[TextArea] = None
|
|
312
313
|
self._tools_area: Optional[TextArea] = None
|
|
314
|
+
self._history_manager = UserMessagesManager(memory) if memory else None
|
|
313
315
|
self._commands: dict[str, Any] = {
|
|
314
316
|
"exit": self._cmd_exit,
|
|
315
317
|
"quit": self._cmd_exit,
|
|
@@ -418,7 +420,6 @@ class MakeAgentShell:
|
|
|
418
420
|
prompt="> ",
|
|
419
421
|
multiline=True,
|
|
420
422
|
completer=completer,
|
|
421
|
-
history=FileHistory(str(self._history_path)),
|
|
422
423
|
wrap_lines=False,
|
|
423
424
|
)
|
|
424
425
|
self._composer_input = composer_input
|
|
@@ -474,7 +475,7 @@ class MakeAgentShell:
|
|
|
474
475
|
else [
|
|
475
476
|
(
|
|
476
477
|
"class:hint",
|
|
477
|
-
" /help /stats /export /exit Alt+Enter newline Ctrl+T transcript",
|
|
478
|
+
" /help /stats /export /exit ↑↓ history Alt+Enter newline Ctrl+T transcript",
|
|
478
479
|
)
|
|
479
480
|
]
|
|
480
481
|
)
|
|
@@ -557,10 +558,15 @@ class MakeAgentShell:
|
|
|
557
558
|
def _on_enter(event) -> None:
|
|
558
559
|
if state.status != AgentStatus.IDLE or state.transcript_focused:
|
|
559
560
|
return
|
|
561
|
+
|
|
560
562
|
text = composer_input.text.strip()
|
|
561
563
|
if not text:
|
|
562
564
|
return
|
|
565
|
+
|
|
563
566
|
composer_input.text = ""
|
|
567
|
+
if self._history_manager is not None:
|
|
568
|
+
self._history_manager.submit() # Reset nav state after sending
|
|
569
|
+
|
|
564
570
|
if text.startswith("/"):
|
|
565
571
|
should_exit = self._dispatch_command(text[1:])
|
|
566
572
|
if should_exit:
|
|
@@ -570,6 +576,31 @@ class MakeAgentShell:
|
|
|
570
576
|
else:
|
|
571
577
|
asyncio.ensure_future(self._run_turn(text))
|
|
572
578
|
|
|
579
|
+
# Only bind up/down for history navigation when composer is focused,
|
|
580
|
+
# idle, and memory is available — so arrow keys still scroll the
|
|
581
|
+
# transcript area when it's focused.
|
|
582
|
+
composer_history_filter = Condition(
|
|
583
|
+
lambda: (
|
|
584
|
+
not state.transcript_focused
|
|
585
|
+
and state.status == AgentStatus.IDLE
|
|
586
|
+
and self._history_manager is not None
|
|
587
|
+
)
|
|
588
|
+
)
|
|
589
|
+
|
|
590
|
+
@kb.add("up", filter=composer_history_filter)
|
|
591
|
+
def _on_up(event) -> None:
|
|
592
|
+
msg = self._history_manager.previous(composer_input.text)
|
|
593
|
+
if msg is not None:
|
|
594
|
+
composer_input.text = msg
|
|
595
|
+
self._refresh()
|
|
596
|
+
|
|
597
|
+
@kb.add("down", filter=composer_history_filter)
|
|
598
|
+
def _on_down(event) -> None:
|
|
599
|
+
msg = self._history_manager.next()
|
|
600
|
+
if msg is not None:
|
|
601
|
+
composer_input.text = msg
|
|
602
|
+
self._refresh()
|
|
603
|
+
|
|
573
604
|
@kb.add("escape", "enter")
|
|
574
605
|
def _on_alt_enter(event) -> None:
|
|
575
606
|
if state.status == AgentStatus.IDLE and not state.transcript_focused:
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
"""User message history manager for the agent shell.
|
|
2
|
+
|
|
3
|
+
Provides navigation through past user messages backed by persistent Memory.
|
|
4
|
+
The shell interacts with this manager, not Memory directly.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
from typing import Optional
|
|
10
|
+
|
|
11
|
+
from make_agent.memory import Memory
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class UserMessagesManager:
|
|
15
|
+
"""Manages user message history for shell navigation.
|
|
16
|
+
|
|
17
|
+
Refreshes messages from Memory on each navigation start so that
|
|
18
|
+
messages from the current session are always included. Supports
|
|
19
|
+
forward/backward navigation with index tracking.
|
|
20
|
+
"""
|
|
21
|
+
|
|
22
|
+
def __init__(self, memory: Memory, limit: int = 200) -> None:
|
|
23
|
+
"""Initialize with a Memory instance.
|
|
24
|
+
|
|
25
|
+
Args:
|
|
26
|
+
memory: The Memory backend to fetch messages from.
|
|
27
|
+
limit: Maximum number of historical messages to load (default: 200).
|
|
28
|
+
"""
|
|
29
|
+
self._memory = memory
|
|
30
|
+
self._limit = limit
|
|
31
|
+
self._messages: list[str] = [] # Refreshed on each nav start, newest first
|
|
32
|
+
self._index: int = -1 # -1 = not navigating; 0 = most recent
|
|
33
|
+
self._original_text: str = "" # Text user had typed before pressing UP
|
|
34
|
+
|
|
35
|
+
def _refresh(self) -> None:
|
|
36
|
+
"""Reload user messages from Memory so current-session messages
|
|
37
|
+
are always visible."""
|
|
38
|
+
self._messages = self._memory.recent_user(self._limit)
|
|
39
|
+
|
|
40
|
+
def start_navigating(self, current_text: str) -> Optional[str]:
|
|
41
|
+
"""Begin navigation from the current composer text.
|
|
42
|
+
|
|
43
|
+
Called when user first presses UP. Reloads messages from Memory
|
|
44
|
+
so current-session messages are included. Saves the current text
|
|
45
|
+
as the restoration point (returned when DOWN exits navigation).
|
|
46
|
+
|
|
47
|
+
Args:
|
|
48
|
+
current_text: What the user has typed so far.
|
|
49
|
+
|
|
50
|
+
Returns:
|
|
51
|
+
The most recent past user message, or None if history is empty.
|
|
52
|
+
"""
|
|
53
|
+
self._refresh()
|
|
54
|
+
if not self._messages:
|
|
55
|
+
return None
|
|
56
|
+
self._original_text = current_text
|
|
57
|
+
self._index = 0
|
|
58
|
+
return self._messages[0]
|
|
59
|
+
|
|
60
|
+
def previous(self, current_text: str = "") -> Optional[str]:
|
|
61
|
+
"""Navigate to the next older message.
|
|
62
|
+
|
|
63
|
+
Args:
|
|
64
|
+
current_text: What the user has typed so far (saved as restoration point
|
|
65
|
+
on first UP press).
|
|
66
|
+
|
|
67
|
+
Returns:
|
|
68
|
+
The previous message, or None if already at the oldest.
|
|
69
|
+
"""
|
|
70
|
+
if self._index < 0:
|
|
71
|
+
# First press — start navigating, save current text as restoration point
|
|
72
|
+
return self.start_navigating(current_text)
|
|
73
|
+
if self._index < len(self._messages) - 1:
|
|
74
|
+
self._index += 1
|
|
75
|
+
return self._messages[self._index]
|
|
76
|
+
return None
|
|
77
|
+
|
|
78
|
+
def next(self) -> Optional[str]:
|
|
79
|
+
"""Navigate to the next newer message or restore original text.
|
|
80
|
+
|
|
81
|
+
Returns:
|
|
82
|
+
The next newer message, or the original typed text when
|
|
83
|
+
navigation returns to the start, or None if not navigating.
|
|
84
|
+
"""
|
|
85
|
+
if self._index < 0:
|
|
86
|
+
return None
|
|
87
|
+
if self._index > 0:
|
|
88
|
+
self._index -= 1
|
|
89
|
+
return self._messages[self._index]
|
|
90
|
+
# Back at start — restore original text
|
|
91
|
+
text = self._original_text
|
|
92
|
+
self._index = -1
|
|
93
|
+
self._original_text = ""
|
|
94
|
+
return text
|
|
95
|
+
|
|
96
|
+
def cancel(self) -> None:
|
|
97
|
+
"""Cancel navigation and restore the original typed text."""
|
|
98
|
+
self._index = -1
|
|
99
|
+
|
|
100
|
+
def submit(self) -> None:
|
|
101
|
+
"""Called when the user sends a message (presses Enter).
|
|
102
|
+
|
|
103
|
+
Resets navigation state so the next UP press starts fresh.
|
|
104
|
+
"""
|
|
105
|
+
self._index = -1
|
|
106
|
+
self._original_text = ""
|
|
107
|
+
|
|
108
|
+
def is_navigating(self) -> bool:
|
|
109
|
+
"""Check if the user is currently in navigation mode."""
|
|
110
|
+
return self._index >= 0
|
|
@@ -29,7 +29,7 @@ logger = logging.getLogger(__name__)
|
|
|
29
29
|
|
|
30
30
|
_DEFAULT_SYSTEM_PROMPT_FILE = "SYSTEM.md"
|
|
31
31
|
_REASONING_EFFORT_VALUES = ("none", "minimal", "low", "medium", "high", "xhigh")
|
|
32
|
-
|
|
32
|
+
_SKILL_MODE = "makefile"
|
|
33
33
|
|
|
34
34
|
|
|
35
35
|
def _init_logging(loglevel: str) -> None:
|
|
@@ -61,9 +61,7 @@ def _resolve_system_prompt(args: argparse.Namespace) -> str:
|
|
|
61
61
|
if cwd_system.exists():
|
|
62
62
|
return cwd_system.read_text(encoding="utf-8")
|
|
63
63
|
|
|
64
|
-
project_system = (
|
|
65
|
-
mode_dir(getattr(args, "skill_mode", "python")) / _DEFAULT_SYSTEM_PROMPT_FILE
|
|
66
|
-
)
|
|
64
|
+
project_system = mode_dir(_SKILL_MODE) / _DEFAULT_SYSTEM_PROMPT_FILE
|
|
67
65
|
if project_system.exists():
|
|
68
66
|
return project_system.read_text(encoding="utf-8")
|
|
69
67
|
|
|
@@ -111,16 +109,16 @@ def _cmd_run(args: argparse.Namespace) -> None:
|
|
|
111
109
|
except OSError as e:
|
|
112
110
|
sys.exit(f"make-agent run: {e}")
|
|
113
111
|
|
|
114
|
-
ensure_mode_system_prompt(
|
|
112
|
+
ensure_mode_system_prompt(_SKILL_MODE)
|
|
115
113
|
system_prompt = _resolve_system_prompt(args)
|
|
116
|
-
disabled = _parse_disabled_tools(args.disable_builtin_tools,
|
|
114
|
+
disabled = _parse_disabled_tools(args.disable_builtin_tools, _SKILL_MODE)
|
|
117
115
|
if args.skills_dir:
|
|
118
|
-
skills_dir = str(Path(args.skills_dir) /
|
|
116
|
+
skills_dir = str(Path(args.skills_dir) / _SKILL_MODE)
|
|
119
117
|
else:
|
|
120
|
-
skills_dir = str(default_skills_dir(
|
|
118
|
+
skills_dir = str(default_skills_dir(_SKILL_MODE))
|
|
121
119
|
|
|
122
|
-
memory = Memory(mode_memory_path(
|
|
123
|
-
backend = _build_backend(
|
|
120
|
+
memory = Memory(mode_memory_path(_SKILL_MODE))
|
|
121
|
+
backend = _build_backend(_SKILL_MODE, skills_dir, args.tool_timeout)
|
|
124
122
|
trusted_skills = _parse_trusted_skills(getattr(args, "trusted_skills", None))
|
|
125
123
|
tool_handler = ToolHandler(backend, memory, disabled, trusted_skills)
|
|
126
124
|
|
|
@@ -200,13 +198,6 @@ def main() -> None:
|
|
|
200
198
|
metavar="SECONDS",
|
|
201
199
|
help="Timeout in seconds for each tool call (default: 600)",
|
|
202
200
|
)
|
|
203
|
-
run_p.add_argument(
|
|
204
|
-
"--skill-mode",
|
|
205
|
-
choices=_SKILL_MODES,
|
|
206
|
-
default="makefile",
|
|
207
|
-
metavar="MODE",
|
|
208
|
-
help="Skill backend mode to use (default: makefile)",
|
|
209
|
-
)
|
|
210
201
|
run_p.add_argument(
|
|
211
202
|
"--skills-dir",
|
|
212
203
|
default=None,
|
|
@@ -216,6 +216,21 @@ class Memory:
|
|
|
216
216
|
"""Search past agent replies using FTS5 via the ``agent_memory`` view."""
|
|
217
217
|
return self._search("agent_memory", query, limit, from_date, to_date)
|
|
218
218
|
|
|
219
|
+
def recent_user(
|
|
220
|
+
self,
|
|
221
|
+
limit: int = 10,
|
|
222
|
+
) -> list[str]:
|
|
223
|
+
"""Return the *limit* most recent user messages as plain strings, newest first.
|
|
224
|
+
|
|
225
|
+
Used by the shell for UP/DOWN arrow navigation through past user messages.
|
|
226
|
+
"""
|
|
227
|
+
conn = self._get_conn()
|
|
228
|
+
rows = conn.execute(
|
|
229
|
+
"SELECT message FROM messages WHERE sender = 'user' ORDER BY id DESC LIMIT ?",
|
|
230
|
+
(limit,),
|
|
231
|
+
).fetchall()
|
|
232
|
+
return [row["message"] for row in rows]
|
|
233
|
+
|
|
219
234
|
def recent(
|
|
220
235
|
self,
|
|
221
236
|
limit: int = 10,
|
|
@@ -23,8 +23,6 @@ class SkillBackend(Protocol):
|
|
|
23
23
|
@property
|
|
24
24
|
def executors(self) -> dict[str, Any]: ...
|
|
25
25
|
|
|
26
|
-
async def setup(self, model: str) -> None: ...
|
|
27
|
-
|
|
28
26
|
def get_skill_trusted(self, name: str) -> bool | None: ...
|
|
29
27
|
|
|
30
28
|
|
|
@@ -81,9 +79,6 @@ class MakefileSkillBackend:
|
|
|
81
79
|
def executors(self) -> dict[str, Any]:
|
|
82
80
|
return self._executors
|
|
83
81
|
|
|
84
|
-
async def setup(self, model: str) -> None:
|
|
85
|
-
del model
|
|
86
|
-
|
|
87
82
|
def get_skill_trusted(self, name: str) -> bool | None:
|
|
88
83
|
return None
|
|
89
84
|
|
|
@@ -37,7 +37,7 @@ A skill is a directory containing a single file: **skill.mk**.
|
|
|
37
37
|
|
|
38
38
|
```makefile
|
|
39
39
|
define DESCRIPTION
|
|
40
|
-
|
|
40
|
+
Description shown in list_skills.
|
|
41
41
|
endef
|
|
42
42
|
|
|
43
43
|
.PHONY: target-name
|
|
@@ -49,3 +49,16 @@ target-name:
|
|
|
49
49
|
Rules for skill.mk:
|
|
50
50
|
- Must contain a `define DESCRIPTION … endef` block with a short description.
|
|
51
51
|
- Call `validate_skill` after creating a skill to confirm it is valid.
|
|
52
|
+
|
|
53
|
+
### Overwriting a skilll
|
|
54
|
+
|
|
55
|
+
To overwrite an existing skill, simply call `create_skill` with the same name. This will replace the existing `skill.mk` file with the new content you provide.
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
## Your workflow
|
|
59
|
+
1. Clarify the user's request
|
|
60
|
+
2. Create a plan to fulfill the request, which may include using skills
|
|
61
|
+
3. Identify which skills to use and in what order
|
|
62
|
+
4. If there are no existing skills that can fulfill the request, create a new skill
|
|
63
|
+
5. Implement the plan by executing the necessary skills
|
|
64
|
+
6. Observe the results and iterate as needed until the user's request is fulfilled
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: makefile-agent
|
|
3
|
-
Version: 0.4.
|
|
3
|
+
Version: 0.4.2
|
|
4
4
|
Summary: An AI agent powered by Makefile skills.
|
|
5
5
|
Author: Dmitriy Sorochenkov
|
|
6
6
|
License-Expression: MIT
|
|
@@ -91,8 +91,7 @@ Priority order (first match wins):
|
|
|
91
91
|
|
|
92
92
|
1. `--system PROMPT` flag
|
|
93
93
|
2. `--system-file FILE` flag
|
|
94
|
-
3.
|
|
95
|
-
4. `~/.make-agent/<project>/makefile/SYSTEM.md` (created from a bundled template on first run)
|
|
94
|
+
3. `~/.make-agent/<project>/makefile/SYSTEM.md` (created from a bundled template on first run)
|
|
96
95
|
|
|
97
96
|
## Skills
|
|
98
97
|
|
|
@@ -20,6 +20,7 @@ make_agent/agent_core/provider.py
|
|
|
20
20
|
make_agent/agent_shell/__init__.py
|
|
21
21
|
make_agent/agent_shell/run.py
|
|
22
22
|
make_agent/agent_shell/shell.py
|
|
23
|
+
make_agent/agent_shell/user_messages.py
|
|
23
24
|
make_agent/builtin_tools/__init__.py
|
|
24
25
|
make_agent/builtin_tools/file_tools.py
|
|
25
26
|
make_agent/builtin_tools/skill_tools.py
|
|
@@ -52,4 +53,5 @@ tests/test_memory.py
|
|
|
52
53
|
tests/test_middleware.py
|
|
53
54
|
tests/test_parser.py
|
|
54
55
|
tests/test_tools.py
|
|
55
|
-
tests/test_trusted_skill.py
|
|
56
|
+
tests/test_trusted_skill.py
|
|
57
|
+
tests/test_user_messages.py
|