agentram 0.1.3 → 0.1.5
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.
- package/README.md +13 -1
- package/agentram/cli.py +104 -8
- package/package.json +1 -1
- package/pyproject.toml +4 -1
package/README.md
CHANGED
|
@@ -53,9 +53,10 @@ If using the Claude plugin, `.mcp.json` sets `AGENTRAM_AUTO_INIT=true`, so these
|
|
|
53
53
|
|
|
54
54
|
## Terminal UI CLI
|
|
55
55
|
|
|
56
|
-
AgentRAM
|
|
56
|
+
AgentRAM includes a terminal UI with Claude-like slash autocomplete. It uses `prompt_toolkit` when installed and falls back to plain `input()` otherwise:
|
|
57
57
|
|
|
58
58
|
```bash
|
|
59
|
+
pip install -e ".[tui]"
|
|
59
60
|
agentram
|
|
60
61
|
```
|
|
61
62
|
|
|
@@ -870,3 +871,14 @@ Inside TUI:
|
|
|
870
871
|
```
|
|
871
872
|
|
|
872
873
|
Do not paste raw API keys into `/bind-model`. `api_key_env` means environment variable name, e.g. `OPENAI_API_KEY`.
|
|
874
|
+
|
|
875
|
+
|
|
876
|
+
### Optional Rich TUI
|
|
877
|
+
|
|
878
|
+
For live slash-command dropdown and command metadata, install the optional TUI extra:
|
|
879
|
+
|
|
880
|
+
```bash
|
|
881
|
+
pip install agentram[tui]
|
|
882
|
+
```
|
|
883
|
+
|
|
884
|
+
Without `prompt_toolkit`, AgentRAM still works with basic terminal input; `/` then Enter opens the full slash palette.
|
package/agentram/cli.py
CHANGED
|
@@ -18,6 +18,30 @@ SUBAGENTS: dict[str, str] = {
|
|
|
18
18
|
"documenter": "Update README or usage notes from current implementation. Keep docs concise and runnable.",
|
|
19
19
|
}
|
|
20
20
|
|
|
21
|
+
SLASH_COMMANDS: list[tuple[str, str]] = [
|
|
22
|
+
("/help", "Show commands"),
|
|
23
|
+
("/init", "Create .agentram files"),
|
|
24
|
+
("/status", "Show RAM status"),
|
|
25
|
+
("/retrieve <query>", "Print relevant RAM context"),
|
|
26
|
+
("/goal", "Show Goal Stack"),
|
|
27
|
+
("/set-goal key=value ...", "Update mission/current_goal/current_task/etc"),
|
|
28
|
+
("/drift <task>", "Check goal drift"),
|
|
29
|
+
("/events", "Show latest events"),
|
|
30
|
+
("/replay", "Replay events into memory"),
|
|
31
|
+
("/agents", "List Claude-style subagent presets"),
|
|
32
|
+
("/agent <name> <task>", "Build Claude Code subagent prompt"),
|
|
33
|
+
("/models", "List bound coding models"),
|
|
34
|
+
("/bind-model provider model", "Bind model endpoint"),
|
|
35
|
+
("/orchestrate <task>", "Build multi-model agent plan"),
|
|
36
|
+
("/ask <prompt>", "Execute bound models and return outputs"),
|
|
37
|
+
("/claude-install [path]", "Install .claude commands and agents"),
|
|
38
|
+
("/note <text>", "Save decision note"),
|
|
39
|
+
("/clear", "Clear chat"),
|
|
40
|
+
("/exit", "Quit"),
|
|
41
|
+
("Plain text", "Capture coding chat message and retrieve context"),
|
|
42
|
+
]
|
|
43
|
+
|
|
44
|
+
|
|
21
45
|
SLASH_HELP = """Slash commands:
|
|
22
46
|
/help Show commands
|
|
23
47
|
/init Create .agentram files
|
|
@@ -151,10 +175,19 @@ def run_command(args: argparse.Namespace) -> int:
|
|
|
151
175
|
|
|
152
176
|
def run_tui(context: McpContext) -> None:
|
|
153
177
|
context.init_storage()
|
|
154
|
-
|
|
178
|
+
prompt_session = create_prompt_session()
|
|
179
|
+
input_hint = "live slash autocomplete enabled" if prompt_session else "basic input fallback; install prompt_toolkit for live slash dropdown"
|
|
180
|
+
messages = [
|
|
181
|
+
"system > AgentRAM coding-agent CLI ready",
|
|
182
|
+
f"system > RAM root: {context.ram_root}",
|
|
183
|
+
f"system > {input_hint}",
|
|
184
|
+
]
|
|
155
185
|
while True:
|
|
156
186
|
draw_screen(context, messages)
|
|
157
|
-
|
|
187
|
+
try:
|
|
188
|
+
user_input = read_tui_input(prompt_session).strip()
|
|
189
|
+
except (EOFError, KeyboardInterrupt):
|
|
190
|
+
return
|
|
158
191
|
if user_input in {"0", "q", "quit", "exit", "/exit", "/quit"}:
|
|
159
192
|
return
|
|
160
193
|
if user_input in BUTTONS:
|
|
@@ -170,9 +203,46 @@ def run_tui(context: McpContext) -> None:
|
|
|
170
203
|
del messages[:-10]
|
|
171
204
|
|
|
172
205
|
|
|
206
|
+
|
|
207
|
+
def slash_command_names() -> list[str]:
|
|
208
|
+
return [command.split()[0] for command, _ in SLASH_COMMANDS if command.startswith("/")]
|
|
209
|
+
|
|
210
|
+
|
|
211
|
+
def slash_command_meta() -> dict[str, str]:
|
|
212
|
+
return {command.split()[0]: description for command, description in SLASH_COMMANDS if command.startswith("/")}
|
|
213
|
+
|
|
214
|
+
|
|
215
|
+
def create_prompt_session() -> Any | None:
|
|
216
|
+
try:
|
|
217
|
+
from prompt_toolkit import PromptSession
|
|
218
|
+
from prompt_toolkit.completion import WordCompleter
|
|
219
|
+
except ImportError:
|
|
220
|
+
return None
|
|
221
|
+
|
|
222
|
+
completer = WordCompleter(
|
|
223
|
+
slash_command_names(),
|
|
224
|
+
meta_dict=slash_command_meta(),
|
|
225
|
+
ignore_case=True,
|
|
226
|
+
sentence=True,
|
|
227
|
+
)
|
|
228
|
+
return PromptSession(
|
|
229
|
+
completer=completer,
|
|
230
|
+
complete_while_typing=True,
|
|
231
|
+
reserve_space_for_menu=12,
|
|
232
|
+
bottom_toolbar="Type / for slash commands · /agents for subagents · /ask to call bound models",
|
|
233
|
+
)
|
|
234
|
+
|
|
235
|
+
|
|
236
|
+
def read_tui_input(prompt_session: Any | None) -> str:
|
|
237
|
+
if prompt_session is None:
|
|
238
|
+
return input("You > ")
|
|
239
|
+
return prompt_session.prompt("You > ")
|
|
240
|
+
|
|
173
241
|
def handle_chat_input(context: McpContext, text: str, messages: list[str] | None = None) -> str:
|
|
174
242
|
if not text:
|
|
175
243
|
return SLASH_HELP
|
|
244
|
+
if text == "/":
|
|
245
|
+
return slash_palette_text()
|
|
176
246
|
if text.startswith("/"):
|
|
177
247
|
return handle_slash_command(context, text, messages)
|
|
178
248
|
call_tool(
|
|
@@ -313,8 +383,34 @@ def replay_text(context: McpContext, arguments: dict[str, object]) -> str:
|
|
|
313
383
|
|
|
314
384
|
|
|
315
385
|
def agents_text() -> str:
|
|
316
|
-
|
|
317
|
-
|
|
386
|
+
rows = [
|
|
387
|
+
("agentram-memory", "Memory", "Records durable notes. Never edits code."),
|
|
388
|
+
("agentram-planner", "Planner", "Checks Goal Stack and decomposes work."),
|
|
389
|
+
("agentram-reviewer", "Reviewer", "Reviews changes, tests, and drift risk."),
|
|
390
|
+
("agentram-docs", "Docs", "Updates README and usage docs."),
|
|
391
|
+
]
|
|
392
|
+
lines = ["Claude Code subagents", ""]
|
|
393
|
+
for name, label, description in rows:
|
|
394
|
+
lines.append(f" {name.ljust(22)} {label}")
|
|
395
|
+
lines.append(f" {description}")
|
|
396
|
+
lines.append("")
|
|
397
|
+
lines.append("Use: /agent reviewer <task>")
|
|
398
|
+
lines.append("Install: /claude-install .")
|
|
399
|
+
return "\n".join(lines)
|
|
400
|
+
|
|
401
|
+
|
|
402
|
+
def slash_palette_text(filter_text: str = "") -> str:
|
|
403
|
+
normalized = filter_text.strip().lower().lstrip("/")
|
|
404
|
+
rows = []
|
|
405
|
+
for command, description in SLASH_COMMANDS:
|
|
406
|
+
command_key = command.lower().lstrip("/")
|
|
407
|
+
if normalized and normalized not in command_key:
|
|
408
|
+
continue
|
|
409
|
+
rows.append((command, description))
|
|
410
|
+
command_width = max([len(command) for command, _ in rows] + [12])
|
|
411
|
+
lines = ["Slash commands", ""]
|
|
412
|
+
for command, description in rows:
|
|
413
|
+
lines.append(f" {command.ljust(command_width)} {description}")
|
|
318
414
|
return "\n".join(lines)
|
|
319
415
|
|
|
320
416
|
|
|
@@ -484,7 +580,7 @@ def draw_screen(context: McpContext, messages: list[str]) -> None:
|
|
|
484
580
|
left_width = 30
|
|
485
581
|
right_width = width - left_width - 3
|
|
486
582
|
print("+" + "-" * (width - 2) + "+")
|
|
487
|
-
print(box_text("AgentRAM Code
|
|
583
|
+
print(box_text("◆ AgentRAM Code | RAM + Claude subagents + slash commands", width))
|
|
488
584
|
print("+" + "-" * (width - 2) + "+")
|
|
489
585
|
|
|
490
586
|
sidebar = sidebar_lines(context)
|
|
@@ -495,7 +591,7 @@ def draw_screen(context: McpContext, messages: list[str]) -> None:
|
|
|
495
591
|
right = chat[index] if index < len(chat) else ""
|
|
496
592
|
print("| " + left[: left_width - 2].ljust(left_width - 2) + "| " + right[: right_width - 2].ljust(right_width - 2) + "|")
|
|
497
593
|
print("+" + "-" * (left_width - 1) + "+" + "-" * (right_width) + "+")
|
|
498
|
-
print(box_text("Input:
|
|
594
|
+
print(box_text("Input: type / for live dropdown. Enter '/' for full palette. /ask calls models.", width))
|
|
499
595
|
print("+" + "-" * (width - 2) + "+")
|
|
500
596
|
|
|
501
597
|
|
|
@@ -526,10 +622,10 @@ def sidebar_lines(context: McpContext) -> list[str]:
|
|
|
526
622
|
" 9 help 0 exit",
|
|
527
623
|
"",
|
|
528
624
|
"CLAUDE",
|
|
625
|
+
" / = command palette",
|
|
626
|
+
" /agents",
|
|
529
627
|
" /claude-install .",
|
|
530
628
|
" /models",
|
|
531
|
-
" /bind-model claude <model>",
|
|
532
|
-
" /orchestrate <task>",
|
|
533
629
|
" /ask <prompt>",
|
|
534
630
|
]
|
|
535
631
|
|
package/package.json
CHANGED
package/pyproject.toml
CHANGED
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "agentram"
|
|
7
|
-
version = "0.1.
|
|
7
|
+
version = "0.1.5"
|
|
8
8
|
description = "Async, model-agnostic RAM layer for agentic coding tools."
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
license = "MIT"
|
|
@@ -21,6 +21,9 @@ classifiers = [
|
|
|
21
21
|
requires-python = ">=3.10"
|
|
22
22
|
dependencies = []
|
|
23
23
|
|
|
24
|
+
[project.optional-dependencies]
|
|
25
|
+
tui = ["prompt_toolkit>=3.0"]
|
|
26
|
+
|
|
24
27
|
[project.urls]
|
|
25
28
|
Homepage = "https://github.com/your-org/agentram"
|
|
26
29
|
Repository = "https://github.com/your-org/agentram"
|