File size: 7,129 Bytes
6e02dfb | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 | import os
import shutil
import datetime
import glob
from dotenv import load_dotenv
# --- NEW MODULES ---
from librarian import Librarian
from tig_engine import IntelliMod
from intellimod_bridge import IntelliModBridge
from docling.document_converter import DocumentConverter
load_dotenv()
# --- CONFIGURATION ---
BASE_MEMORY_PATH = "/workspaces/collaborator_agent/memory"
SHORT_TERM_PATH = os.path.join(BASE_MEMORY_PATH, "short")
KNOWLEDGE_PATH = os.path.join(BASE_MEMORY_PATH, "knowledge")
BRIDGE_PATH = "/workspaces/bridge"
INBOX_PATH = os.path.join(BRIDGE_PATH, "inbox")
PROCESSED_PATH = os.path.join(BRIDGE_PATH, "processed")
CORE_PROFILE_PATH = os.path.join(BASE_MEMORY_PATH, "profile_core.md")
TASK_LIST_PATH = os.path.join(BASE_MEMORY_PATH, "current_tasks.md")
# --- INITIALIZE SUBSYSTEMS ---
librarian = Librarian(BASE_MEMORY_PATH)
tig = IntelliMod() # The New Brain (TIG + Abacus)
bridge = IntelliModBridge() # The Connection to your Repo
def ensure_folders():
for folder in [SHORT_TERM_PATH, KNOWLEDGE_PATH, INBOX_PATH, PROCESSED_PATH]:
if not os.path.exists(folder):
os.makedirs(folder)
def load_file_content(filepath):
if not os.path.exists(filepath): return ""
with open(filepath, "r", encoding="utf-8") as f: return f.read()
def get_last_summary():
files = glob.glob(os.path.join(BRIDGE_PATH, "summary_*.md"))
if not files: return "No previous summaries found."
last_file = max(files, key=os.path.getmtime)
return load_file_content(last_file)
def process_inbox():
files = glob.glob(os.path.join(INBOX_PATH, "*.*"))
if not files: return []
print(f"\n[System] Found {len(files)} new files in Inbox. Processing...")
converter = DocumentConverter()
new_knowledge = []
for filepath in files:
filename = os.path.basename(filepath)
if filename.startswith("."): continue
try:
print(f" - Reading: {filename}...")
result = converter.convert(filepath)
markdown_content = result.document.export_to_markdown()
save_path = os.path.join(KNOWLEDGE_PATH, f"read_{filename}.md")
with open(save_path, "w", encoding="utf-8") as f: f.write(markdown_content)
chunks_count = librarian.add_document(filename, markdown_content)
shutil.move(filepath, os.path.join(PROCESSED_PATH, filename))
msg = f"Read and Indexed {filename} ({chunks_count} chunks)."
new_knowledge.append(msg)
print(f" [Success] {msg}")
except Exception as e:
print(f" [!] Error reading {filename}: {e}")
return new_knowledge
def perform_sleep_cycle(chat_history):
print("\n[System] Initiating Sleep Cycle...")
full_log = "\n".join(chat_history)
current_tasks = load_file_content(TASK_LIST_PATH)
sleep_prompt = f"""
You are Kael's subconscious. Summarize the session and update tasks.
--- CHAT LOG ---
{full_log}
--- CURRENT TASKS ---
{current_tasks}
OUTPUT FORMAT:
# SUMMARY
(Summary)
# UPDATED TASKS
(Task list)
"""
# Sleep cycle forces the cheap model via TIG
response_text = tig.run_tig_pipeline(sleep_prompt, force_model="gemini-2.5-flash")
timestamp = datetime.datetime.now().strftime("%Y-%m-%d_%H-%M-%S")
try:
if "# UPDATED TASKS" in response_text:
summary_part = response_text.split("# UPDATED TASKS")[0].strip()
task_part = "# UPDATED TASKS" + response_text.split("# UPDATED TASKS")[1]
with open(os.path.join(BRIDGE_PATH, f"summary_{timestamp}.md"), "w", encoding="utf-8") as f:
f.write(summary_part)
with open(TASK_LIST_PATH, "w", encoding="utf-8") as f:
f.write(task_part.replace("# UPDATED TASKS", "# ACTIVE TASK LIST"))
print(f"[System] Sleep Cycle Complete.")
else:
print("[System] Sleep Cycle saved raw log (format mismatch).")
with open(os.path.join(BRIDGE_PATH, f"summary_{timestamp}.md"), "w", encoding="utf-8") as f:
f.write(response_text)
except Exception as e:
print(f"[Error] Sleep cycle failed parsing: {e}")
def run_chat():
ensure_folders()
# 1. Ingest new files
read_results = process_inbox()
# 2. Load context
core_profile = load_file_content(CORE_PROFILE_PATH)
task_list = load_file_content(TASK_LIST_PATH)
print(f"--- KAEL ONLINE (Powered by IntelliMod) ---")
chat_history = []
if read_results:
chat_history.append(f"**System:** Indexed new files: {', '.join(read_results)}")
while True:
try:
user_input = input("You: ")
# --- COMMANDS ---
if user_input.lower() in ["exit", "quit"]:
perform_sleep_cycle(chat_history)
break
chat_history.append(f"**Jaccob:** {user_input}")
# --- RETRIEVAL ---
retrieved_facts = librarian.query(user_input, n_results=3)
context_block = "\n".join(retrieved_facts) if retrieved_facts else "No specific documents found."
# --- TIG: INTENT & ADVISORY ---
intent = tig.detect_intent(user_input)
recommendation = bridge.get_tig_recommendation(intent)
# Visual Advisory (The "Toggle/Why")
if recommendation and intent != "chat":
print(f"\n [TIG ADVISOR] ----------------------------------------")
print(f" Detected Intent: {intent.upper()}")
print(f" Selected Card: {recommendation['card_name']}")
print(f" Category: {recommendation['category']}")
print(f" ------------------------------------------------------\n")
# --- PROMPT ASSEMBLY ---
full_prompt = f"""
{core_profile}
--- USER'S LIBRARY ---
{context_block}
--- CURRENT STATUS ---
{task_list}
--- RECENT CHAT ---
{chr(10).join(chat_history[-10:])}
--- CURRENT TURN ---
Jaccob: {user_input}
"""
# --- EXECUTION ---
# TIG handles the routing to Abacus/Gemini based on the intent detected above
# We pass 'intent' implicitly by letting TIG detect it, or we could pass it if we upgraded TIG.
# For now, run_tig_pipeline will re-detect, which is fine for safety.
agent_reply = tig.run_tig_pipeline(full_prompt)
print(f"Kael ({tig.active_model}): {agent_reply}")
chat_history.append(f"**Kael:** {agent_reply}")
except Exception as e:
print(f"An error occurred: {e}")
if __name__ == "__main__":
run_chat() |