agentram 0.1.29 → 0.1.30

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.
Files changed (2) hide show
  1. package/agentram/cli.py +77 -23
  2. package/package.json +1 -1
package/agentram/cli.py CHANGED
@@ -475,9 +475,11 @@ def run_textual_tui(context: McpContext) -> bool:
475
475
  def __init__(self, mcp_context: McpContext) -> None:
476
476
  super().__init__()
477
477
  self.context = mcp_context
478
- self.messages: list[str] = []
479
- self.busy = False
480
- self.suggestions: list[str] = []
478
+ self.messages: list[str] = []
479
+ self.busy = False
480
+ self.prompt_queue: list[str] = []
481
+ self.processing_task: asyncio.Task[None] | None = None
482
+ self.suggestions: list[str] = []
481
483
  self.setup_done = False
482
484
  self.prompt_history: list[str] = []
483
485
  self.history_index: int | None = None
@@ -769,23 +771,37 @@ def run_textual_tui(context: McpContext) -> bool:
769
771
  self.chat.clear()
770
772
  self.chat.write("system > Chat cleared.")
771
773
  return
772
- if self.busy:
773
- self.chat.write("agentram > busy, wait current task")
774
- return
775
- self.busy = True
776
- self.chat.write("agentram > thinking...")
777
- try:
778
- response = await asyncio.to_thread(handle_chat_input, self.context, text, self.messages)
779
- except Exception as error: # noqa: BLE001 - TUI boundary
780
- response = f"error: {error}"
781
- finally:
782
- self.busy = False
783
- if response == "__clear__":
784
- self.chat.clear()
785
- self.chat.write("system > Chat cleared.")
786
- elif response:
787
- self.chat.write("agentram > " + response)
788
- self.refresh_sidebar()
774
+ if self.busy:
775
+ self.prompt_queue.append(text)
776
+ self.chat.write(f"agentram > queued #{len(self.prompt_queue)}")
777
+ return
778
+ self.prompt_queue.append(text)
779
+ self.processing_task = asyncio.create_task(self.process_prompt_queue())
780
+
781
+ async def process_prompt_queue(self) -> None:
782
+ if self.busy:
783
+ return
784
+ self.busy = True
785
+ try:
786
+ while self.prompt_queue:
787
+ text = self.prompt_queue.pop(0)
788
+ pending = len(self.prompt_queue)
789
+ suffix = f" ({pending} queued)" if pending else ""
790
+ self.chat.write(f"agentram > thinking...{suffix}")
791
+ try:
792
+ response = await asyncio.to_thread(handle_chat_input, self.context, text, self.messages)
793
+ except Exception as error: # noqa: BLE001 - TUI boundary
794
+ response = f"error: {error}"
795
+ if response == "__clear__":
796
+ self.chat.clear()
797
+ self.chat.write("system > Chat cleared.")
798
+ elif response:
799
+ self.chat.write("agentram > " + response)
800
+ self.refresh_sidebar()
801
+ finally:
802
+ self.busy = False
803
+ self.processing_task = None
804
+ self.query_one("#input", Input).focus()
789
805
 
790
806
  AgentRAMTextualApp(context).run()
791
807
  return True
@@ -1188,7 +1204,7 @@ def supervisor_workflow_text(context: McpContext, prompt: str) -> str:
1188
1204
  main_agent = agents.get("main")
1189
1205
  small_agent = agents.get("small")
1190
1206
  memory_context = retrieve_text(context, prompt, task_id="codex", limit=8)
1191
- route = classify_agent_runtime_route(context, prompt)
1207
+ route = classify_agent_runtime_route(context, prompt, main_agent)
1192
1208
  intent = str(route.get("intent", "chat"))
1193
1209
  outputs: dict[str, str] = {}
1194
1210
 
@@ -1252,7 +1268,28 @@ def supervisor_workflow_text(context: McpContext, prompt: str) -> str:
1252
1268
  ]
1253
1269
  )
1254
1270
 
1255
- def classify_agent_runtime_route(context: McpContext, prompt: str) -> dict[str, object]:
1271
+ def classify_agent_runtime_route(context: McpContext, prompt: str, main_agent: AgentModelEndpoint | None = None) -> dict[str, object]:
1272
+ if main_agent:
1273
+ try:
1274
+ response = call_agent_endpoint(main_agent, build_agent_runtime_router_prompt(prompt))
1275
+ data = json.loads(extract_json_object(response))
1276
+ intent = str(data.get("intent", "")).strip().lower()
1277
+ if intent in {"planning", "execution", "memory", "chat"}:
1278
+ return {
1279
+ "intent": intent,
1280
+ "confidence": float(data.get("confidence", 0.75)),
1281
+ "reason": str(data.get("reason", "main-agent router")),
1282
+ "source": "main-agent",
1283
+ }
1284
+ except Exception as error: # noqa: BLE001 - router boundary
1285
+ fallback = heuristic_agent_runtime_route(prompt)
1286
+ fallback["source"] = "heuristic"
1287
+ fallback["router_error"] = str(error)
1288
+ return fallback
1289
+
1290
+ return heuristic_agent_runtime_route(prompt)
1291
+
1292
+ def heuristic_agent_runtime_route(prompt: str) -> dict[str, object]:
1256
1293
  lower = prompt.lower()
1257
1294
  execute_words = [
1258
1295
  "bắt đầu làm", "bat dau lam", "làm đi", "lam di", "tiến hành", "tien hanh", "thực hiện", "thuc hien",
@@ -1263,12 +1300,29 @@ def classify_agent_runtime_route(context: McpContext, prompt: str) -> dict[str,
1263
1300
  return {"intent": "execution", "confidence": 0.9, "source": "heuristic"}
1264
1301
  if any(word in lower for word in plan_words):
1265
1302
  return {"intent": "planning", "confidence": 0.85, "source": "heuristic"}
1266
- decision = classify_prompt_intent(context, prompt)
1303
+ decision = heuristic_intent(prompt)
1267
1304
  intent = str(decision.get("intent", "chat"))
1268
1305
  if intent == "coding":
1269
1306
  decision["intent"] = "execution"
1307
+ decision["source"] = "heuristic"
1270
1308
  return decision
1271
1309
 
1310
+ def build_agent_runtime_router_prompt(prompt: str) -> str:
1311
+ return "\n".join(
1312
+ [
1313
+ "You are AgentRAM orchestration router using the main agent model.",
1314
+ "Classify which agent should handle the user prompt. Do not edit files. Do not run tools. Return only JSON.",
1315
+ "Schema: {\"intent\":\"planning|execution|memory|chat\",\"confidence\":0.0,\"reason\":\"short\"}",
1316
+ "planning = user asks to plan, design, set roadmap, discuss goal, no execution yet.",
1317
+ "execution = user approves plan, says start/do it, or asks coding/refactor/fix/test/file work.",
1318
+ "memory = user asks to remember/save/note a decision/fact.",
1319
+ "chat = normal conversation.",
1320
+ "Nếu user prompt bằng tiếng Việt, reason dùng tiếng Việt.",
1321
+ "User prompt:",
1322
+ prompt,
1323
+ ]
1324
+ )
1325
+
1272
1326
  def runtime_execution_plan(context: McpContext, supervisor: AgentModelEndpoint | None, prompt: str, memory_context: str, route: dict[str, object]) -> str:
1273
1327
  state = context.goal_store.load().context_block()
1274
1328
  if state:
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agentram",
3
- "version": "0.1.29",
3
+ "version": "0.1.30",
4
4
  "description": "Async, model-agnostic Working RAM for coding agents.",
5
5
  "license": "MIT",
6
6
  "homepage": "https://github.com/trancongnghia/AGENT_RAM#readme",