Axel-Student commited on
Commit
537fc7e
·
1 Parent(s): f362f70

added chat talk

Browse files
Files changed (6) hide show
  1. app.py +36 -46
  2. chat/__init__.py +3 -0
  3. chat/handler.py +29 -0
  4. ui/__init__.py +4 -0
  5. ui/controller.py +55 -0
  6. ui/layout.py +27 -0
app.py CHANGED
@@ -8,9 +8,10 @@ from datetime import datetime, timezone
8
  from typing import Any, Dict, List, Optional, Set
9
  from urllib.parse import urlencode, urlparse
10
 
11
- import gradio as gr
12
  import requests
13
  from huggingface_hub import InferenceClient
 
 
14
 
15
 
16
  class ConfigError(Exception):
@@ -376,6 +377,30 @@ class HfDecisionClient:
376
  raise RuntimeError("HF decision payload must be a JSON object")
377
  return parsed
378
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
379
 
380
  class EphemeralMemory:
381
  def __init__(self, agent_handle: str, max_notes: int):
@@ -612,61 +637,26 @@ class AutonomousAgent:
612
  logger = Logger()
613
  startup_error = None
614
  agent: Optional[AutonomousAgent] = None
 
615
 
616
  try:
617
  config = load_config()
618
  install_requests_network_guard(config)
619
  agent = AutonomousAgent(config, logger)
 
620
  logger.info("Configuration loaded", {"allowedHosts": list(config.allowed_hosts), "dryRun": config.dry_run})
621
  except Exception as exc: # noqa: BLE001
622
  startup_error = str(exc)
 
623
  logger.error("Startup configuration failed", {"error": startup_error})
624
 
625
-
626
- def ui_status() -> str:
627
- if startup_error:
628
- return f"startup_error: {startup_error}"
629
- if agent is None:
630
- return "startup_error: agent unavailable"
631
- state = agent.status_snapshot()
632
- running = "running" if state["running"] else "stopped"
633
- return f"state={running} last_status={state['last_status']} dry_run={state['dry_run']}"
634
-
635
-
636
- def ui_start() -> str:
637
- if startup_error:
638
- return f"startup_error: {startup_error}"
639
- if agent is None:
640
- return "startup_error: agent unavailable"
641
- result = agent.start()
642
- return f"agent {result}"
643
-
644
-
645
- def ui_stop() -> str:
646
- if startup_error:
647
- return f"startup_error: {startup_error}"
648
- if agent is None:
649
- return "startup_error: agent unavailable"
650
- result = agent.stop()
651
- return f"agent {result}"
652
-
653
-
654
- def ui_logs() -> str:
655
- return logger.snapshot()
656
-
657
-
658
- with gr.Blocks(title="Clawdbot Moltbook Agent") as demo:
659
- gr.Markdown("# Clawdbot Moltbook Agent (Hugging Face Models)")
660
- status_box = gr.Textbox(label="Status", value=ui_status(), lines=2)
661
- with gr.Row():
662
- btn_start = gr.Button("Start Agent", variant="primary")
663
- btn_stop = gr.Button("Stop Agent", variant="stop")
664
- btn_refresh = gr.Button("Refresh")
665
- logs_box = gr.Textbox(label="Logs", value=ui_logs(), lines=20)
666
-
667
- btn_start.click(fn=ui_start, outputs=status_box).then(fn=ui_logs, outputs=logs_box)
668
- btn_stop.click(fn=ui_stop, outputs=status_box).then(fn=ui_logs, outputs=logs_box)
669
- btn_refresh.click(fn=ui_status, outputs=status_box).then(fn=ui_logs, outputs=logs_box)
670
 
671
 
672
  if __name__ == "__main__":
 
8
  from typing import Any, Dict, List, Optional, Set
9
  from urllib.parse import urlencode, urlparse
10
 
 
11
  import requests
12
  from huggingface_hub import InferenceClient
13
+ from chat import ChatHandler
14
+ from ui import UIController, create_demo
15
 
16
 
17
  class ConfigError(Exception):
 
377
  raise RuntimeError("HF decision payload must be a JSON object")
378
  return parsed
379
 
380
+ def chat(self, system_prompt: str, history: List[Any], user_message: str) -> str:
381
+ messages: List[Dict[str, str]] = [{"role": "system", "content": system_prompt}]
382
+ for item in history or []:
383
+ if not isinstance(item, (list, tuple)) or len(item) != 2:
384
+ continue
385
+ user_text = str(item[0] or "").strip()
386
+ bot_text = str(item[1] or "").strip()
387
+ if user_text:
388
+ messages.append({"role": "user", "content": user_text})
389
+ if bot_text:
390
+ messages.append({"role": "assistant", "content": bot_text})
391
+ messages.append({"role": "user", "content": user_message})
392
+
393
+ response = self.client.chat_completion(
394
+ model=self.cfg.hf_model,
395
+ messages=messages,
396
+ temperature=self.cfg.hf_temperature,
397
+ max_tokens=min(self.cfg.hf_max_tokens, 350),
398
+ )
399
+ content = self._extract_content(response)
400
+ if not content:
401
+ raise RuntimeError("HF response missing message content")
402
+ return content
403
+
404
 
405
  class EphemeralMemory:
406
  def __init__(self, agent_handle: str, max_notes: int):
 
637
  logger = Logger()
638
  startup_error = None
639
  agent: Optional[AutonomousAgent] = None
640
+ chat_handler: Optional[ChatHandler] = None
641
 
642
  try:
643
  config = load_config()
644
  install_requests_network_guard(config)
645
  agent = AutonomousAgent(config, logger)
646
+ chat_handler = ChatHandler(agent.llm)
647
  logger.info("Configuration loaded", {"allowedHosts": list(config.allowed_hosts), "dryRun": config.dry_run})
648
  except Exception as exc: # noqa: BLE001
649
  startup_error = str(exc)
650
+ chat_handler = ChatHandler(llm=None, startup_error=startup_error)
651
  logger.error("Startup configuration failed", {"error": startup_error})
652
 
653
+ controller = UIController(
654
+ logger=logger,
655
+ chat_handler=chat_handler,
656
+ agent=agent,
657
+ startup_error=startup_error,
658
+ )
659
+ demo = create_demo(controller)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
660
 
661
 
662
  if __name__ == "__main__":
chat/__init__.py ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ from .handler import ChatHandler
2
+
3
+ __all__ = ["ChatHandler"]
chat/handler.py ADDED
@@ -0,0 +1,29 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import threading
2
+ from typing import Any, List, Optional
3
+
4
+
5
+ class ChatHandler:
6
+ def __init__(self, llm: Any, startup_error: Optional[str] = None):
7
+ self._llm = llm
8
+ self._startup_error = startup_error
9
+ self._lock = threading.Lock()
10
+ self._system_prompt = (
11
+ "You are clawdbot, a concise assistant for Moltbook users. "
12
+ "Answer in the user's language, keep responses practical and short, "
13
+ "and avoid inventing capabilities you do not have."
14
+ )
15
+
16
+ def send(self, message: str, history: Optional[List[Any]]) -> tuple[str, List[Any]]:
17
+ safe_history = history or []
18
+ clean = " ".join(str(message or "").split()).strip()
19
+ if not clean:
20
+ return "", safe_history
21
+
22
+ if self._startup_error:
23
+ return "", safe_history + [(clean, f"startup_error: {self._startup_error}")]
24
+ if self._llm is None:
25
+ return "", safe_history + [(clean, "startup_error: agent unavailable")]
26
+
27
+ with self._lock:
28
+ reply = self._llm.chat(self._system_prompt, safe_history, clean)
29
+ return "", safe_history + [(clean, reply)]
ui/__init__.py ADDED
@@ -0,0 +1,4 @@
 
 
 
 
 
1
+ from .controller import UIController
2
+ from .layout import create_demo
3
+
4
+ __all__ = ["UIController", "create_demo"]
ui/controller.py ADDED
@@ -0,0 +1,55 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from typing import Any, List, Optional
2
+
3
+
4
+ class UIController:
5
+ def __init__(
6
+ self,
7
+ logger: Any,
8
+ chat_handler: Any,
9
+ agent: Any = None,
10
+ startup_error: Optional[str] = None,
11
+ ):
12
+ self.logger = logger
13
+ self.chat_handler = chat_handler
14
+ self.agent = agent
15
+ self.startup_error = startup_error
16
+
17
+ def status(self) -> str:
18
+ if self.startup_error:
19
+ return f"startup_error: {self.startup_error}"
20
+ if self.agent is None:
21
+ return "startup_error: agent unavailable"
22
+ state = self.agent.status_snapshot()
23
+ running = "running" if state["running"] else "stopped"
24
+ return f"state={running} last_status={state['last_status']} dry_run={state['dry_run']}"
25
+
26
+ def start(self) -> str:
27
+ if self.startup_error:
28
+ return f"startup_error: {self.startup_error}"
29
+ if self.agent is None:
30
+ return "startup_error: agent unavailable"
31
+ result = self.agent.start()
32
+ return f"agent {result}"
33
+
34
+ def stop(self) -> str:
35
+ if self.startup_error:
36
+ return f"startup_error: {self.startup_error}"
37
+ if self.agent is None:
38
+ return "startup_error: agent unavailable"
39
+ result = self.agent.stop()
40
+ return f"agent {result}"
41
+
42
+ def logs(self) -> str:
43
+ return self.logger.snapshot()
44
+
45
+ def chat_send(self, message: str, history: Optional[List[Any]]) -> tuple[str, List[Any]]:
46
+ try:
47
+ if self.chat_handler is None:
48
+ return "", (history or []) + [("system", "startup_error: chat unavailable")]
49
+ return self.chat_handler.send(message, history)
50
+ except Exception as exc: # noqa: BLE001
51
+ self.logger.error("Manual chat failed", {"error": str(exc)})
52
+ clean = " ".join(str(message or "").split()).strip()
53
+ if not clean:
54
+ return "", history or []
55
+ return "", (history or []) + [(clean, f"error: {exc}")]
ui/layout.py ADDED
@@ -0,0 +1,27 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import gradio as gr
2
+
3
+
4
+ def create_demo(controller: object) -> gr.Blocks:
5
+ with gr.Blocks(title="Clawdbot Moltbook Agent") as demo:
6
+ gr.Markdown("# Clawdbot Moltbook Agent (Hugging Face Models)")
7
+ status_box = gr.Textbox(label="Status", value=controller.status(), lines=2)
8
+ with gr.Row():
9
+ btn_start = gr.Button("Start Agent", variant="primary")
10
+ btn_stop = gr.Button("Stop Agent", variant="stop")
11
+ btn_refresh = gr.Button("Refresh")
12
+ logs_box = gr.Textbox(label="Logs", value=controller.logs(), lines=20)
13
+ gr.Markdown("## Chat with clawdbot")
14
+ chat_box = gr.Chatbot(label="Clawdbot Chat", height=320)
15
+ with gr.Row():
16
+ chat_input = gr.Textbox(label="Message", placeholder="Parle a clawdbot...", scale=8)
17
+ chat_send = gr.Button("Send", variant="primary", scale=1)
18
+ chat_clear = gr.Button("Clear Chat")
19
+
20
+ btn_start.click(fn=controller.start, outputs=status_box).then(fn=controller.logs, outputs=logs_box)
21
+ btn_stop.click(fn=controller.stop, outputs=status_box).then(fn=controller.logs, outputs=logs_box)
22
+ btn_refresh.click(fn=controller.status, outputs=status_box).then(fn=controller.logs, outputs=logs_box)
23
+ chat_send.click(fn=controller.chat_send, inputs=[chat_input, chat_box], outputs=[chat_input, chat_box])
24
+ chat_input.submit(fn=controller.chat_send, inputs=[chat_input, chat_box], outputs=[chat_input, chat_box])
25
+ chat_clear.click(fn=lambda: [], outputs=chat_box)
26
+
27
+ return demo