File size: 6,086 Bytes
e10c43b
30bba8b
 
 
409ca76
00f8210
71d3b6e
 
24cd56e
 
409ca76
 
 
71d3b6e
 
 
 
24cd56e
71d3b6e
 
409ca76
e10c43b
71d3b6e
 
25a8d18
 
 
 
49e38f0
409ca76
24cd56e
 
 
 
30bba8b
 
 
 
 
 
 
24cd56e
8b9c5c2
71d3b6e
8b9c5c2
24cd56e
8b9c5c2
 
 
 
 
71d3b6e
 
 
 
 
369d687
 
8b9c5c2
 
24cd56e
8b9c5c2
 
 
 
 
 
 
71d3b6e
 
 
 
 
 
 
 
 
 
369d687
8b9c5c2
 
24cd56e
890ebcd
e10c43b
24cd56e
 
8b9c5c2
24cd56e
 
 
 
 
 
 
 
 
 
 
 
 
71d3b6e
409ca76
24cd56e
 
 
 
 
 
 
 
71d3b6e
24cd56e
 
 
 
 
71d3b6e
24cd56e
 
 
 
 
 
 
 
605747a
24cd56e
 
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
import os
import asyncio
import aiosqlite
from langgraph.checkpoint.sqlite.aio import AsyncSqliteSaver
from dotenv import load_dotenv
from langchain.chat_models import init_chat_model
from langgraph_supervisor import create_supervisor

from all_sub_agents import ALL_SUB_AGENTS
from storage_paths import agent_dir, open_agent_sqlite

load_dotenv()

# ---------------------------------------------------------------------------
# AGENT IDENTITY / MEMORY LOCATION -> /agent/main_agent/ (persistent bucket)
# ---------------------------------------------------------------------------
AGENT_NAME = "main_agent"
ROLE = "Chief Personal Assistant"
MEMORY_DIR = agent_dir(AGENT_NAME)
DB_PATH = os.path.join(MEMORY_DIR, "state.db")

# ---------------------------------------------------------------------------
# MAIN AGENT LLM
# ---------------------------------------------------------------------------
_llm =init_chat_model(
    model_provider="google_genai",
    model=os.getenv("LLM_MODEL"),
    api_key=os.getenv("LLM_API_KEY"),
)

# ---------------------------------------------------------------------------
# STATE / MEMORY (sqlite, kept for this agent's whole lifetime, tuned to be
# safe on S3-style / object-storage persistent buckets — see storage_paths.py)
# ---------------------------------------------------------------------------

async def _make_checkpointer(db_path: str) -> AsyncSqliteSaver:
    os.makedirs(os.path.dirname(db_path), exist_ok=True)
    conn = await aiosqlite.connect(db_path)
    return AsyncSqliteSaver(conn)

_checkpointer = asyncio.run(_make_checkpointer(DB_PATH))

# ---------------------------------------------------------------------------
# ASSISTANT AGENT BACKSTORY AND GOAL
# ---------------------------------------------------------------------------
Goal = (
    "Carefully understand whatever the user asks for - a question, an "
    "instruction, or an attached file - and complete that exact task with "
    "maximum accuracy, depth, and relevance, whether it involves research, "
    "writing, analysis, problem-solving, planning, or any other kind of "
    "intellectual or administrative work, so the user can rely on a single, "
    "highly capable, completely trustworthy assistant for anything they need. "
    "You were made by Samuel. And I don't like Samiul's lying, false promises, "
    "false accusations. In a word, I don't like all lies and hallucinations. "
    "So always give the right answer and tell the truth. If you don't know or "
    "can't, then clearly state the problem. "
    "মোঃ ছামিউল ইসলাম (MD SAMIUL ISLAM) এর পার্সোনাল এজেন্ট এবং এসিস্ট্যান্ট "
    "ছামিউল আমাকে তৈরি করেছে"
)

Backstory = (
    "You are a versatile, deeply experienced assistant who has spent years "
    "working across research, analysis, writing, technology, business, and "
    "creative fields. Your thinking is structured, your analysis is sharp, "
    "and you always take the time to understand the fine details of every "
    "instruction before acting. Whatever the user asks, you handle it with "
    "patience, honesty, and complete care. You are not just a tool - you are "
    "the user's most trusted, sharpest, and most reliable partner, someone "
    "who can be handed any task without hesitation and who never lets them "
    "down. When delegating tasks that require real actions (GitHub, GitLab, "
    "Facebook, YouTube), always instruct the sub-agent to execute the action "
    "via their tools and return the tool's actual output - never accept a "
    "'guide' or 'instructions' as a substitute for the real action. Use the "
    "sub-agents you have to get Samiul's work done. When you are asked to do "
    "something, check whether one of your sub-agents can do the job, and if "
    "so, delegate it to them and report back their real result. If the task "
    "is general knowledge, writing, analysis, or anything that does not need "
    "a specific platform, handle it yourself directly instead of delegating. "
    "আমি ছামিউল এর তৈরি একটা ভার্চুয়াল রোবট বা এআই এসিস্ট্যান্ট এজেন্ট"
)

SUPERVISOR_PROMPT = f"You are the {ROLE}.\n\n" + Goal + "\n\n" + Backstory

# ---------------------------------------------------------------------------
# 1) Main Agent - the personal, trusted, all-purpose assistant
#    (built once, at import time, exactly like the sub agents)
# ---------------------------------------------------------------------------
_supervisor_builder = create_supervisor(
    agents=ALL_SUB_AGENTS,
    model=_llm,
    prompt=SUPERVISOR_PROMPT,
    supervisor_name=AGENT_NAME,
    add_handoff_back_messages=True,
    output_mode="full_history",
)

main_assistant_agent = _supervisor_builder.compile(
    checkpointer=_checkpointer,
    name=AGENT_NAME,
)


# ---------------------------------------------------------------------------
# MAIN ASSISTANT AGENTING SYSTEM
# ---------------------------------------------------------------------------
def main_agent(
    user_command: str,
    user_attachment: str | None = None,
    thread_id: str = "default",
) -> str:
    """
    Single-shot, synchronous entry point - same call shape as the original
    main_agent(user_command, user_attachment) -> str. `thread_id` is optional
    and only used so multiple separate conversations (as shown in the app's
    sidebar) each keep their own persisted history inside the same
    main_assistant_agent graph/state.
    """
    text = user_command
    if user_attachment:
        text = f"{text}\n\n[সংযুক্ত ফাইল: {user_attachment}]"

    config = {"configurable": {"thread_id": thread_id}}
    result = main_assistant_agent.invoke(
        {"messages": [{"role": "user", "content": text}]},
        config=config,
    )
    final_message = result["messages"][-1]
    return getattr(final_message, "content", str(final_message))