AGofficial commited on
Commit
49dbd67
·
verified ·
1 Parent(s): c2ae086

Upload 13 files

Browse files
.gitattributes CHANGED
@@ -33,3 +33,7 @@ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
33
  *.zip filter=lfs diff=lfs merge=lfs -text
34
  *.zst filter=lfs diff=lfs merge=lfs -text
35
  *tfevents* filter=lfs diff=lfs merge=lfs -text
 
 
 
 
 
33
  *.zip filter=lfs diff=lfs merge=lfs -text
34
  *.zst filter=lfs diff=lfs merge=lfs -text
35
  *tfevents* filter=lfs diff=lfs merge=lfs -text
36
+ agi/assets/AGI.png filter=lfs diff=lfs merge=lfs -text
37
+ agi/assets/ArtificialGeneralIntelligence.pdf filter=lfs diff=lfs merge=lfs -text
38
+ agi/assets/sophos.png filter=lfs diff=lfs merge=lfs -text
39
+ agi/Qwen3-4B-Instruct-2507-Q3_K_S.gguf filter=lfs diff=lfs merge=lfs -text
README.md CHANGED
@@ -1,3 +1,55 @@
1
- ---
2
- license: mit
3
- ---
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ license: mit
3
+ language:
4
+ - en
5
+ base_model:
6
+ - Qwen/Qwen3-4B-Instruct-2507
7
+ ---
8
+
9
+ # AGI-5
10
+ ## Artificial General Intelligence
11
+
12
+ <img src="agi/assets/AGI.png">
13
+
14
+ ## Overview
15
+ This repository contains an implementation of a modular-agentic architecture for Artificial General Intelligence (AGI). The architecture is designed to facilitate the development of autonomous agents capable of complex reasoning, learning, and interaction with their environment.
16
+
17
+ ## GUI
18
+
19
+ <img src="agi/assets/GUI.png">
20
+
21
+ This GUI allows users to interact with the AGI agent through a user-friendly interface. Users can input prompts, view agent responses, and monitor the agent's internal state and tool usage.
22
+
23
+ # Example
24
+
25
+ ```python
26
+ from agi.sophos import Agent
27
+ from agi.sophos_tools import *
28
+
29
+ toolbox = all_tools()
30
+
31
+ agent = Agent(
32
+ name="Sophos Agent",
33
+ instructions="You are an AI Agent.",
34
+ model="agi/Qwen3-4B-Instruct-2507-Q3_K_S.gguf",
35
+ tools=toolbox,
36
+ )
37
+
38
+ prompt = "Roll a dice, also whats the weather in Tokyo?"
39
+ response = agent.run(prompt)
40
+ print(response)
41
+ ```
42
+ ### Output:
43
+ ```python
44
+
45
+ """
46
+ You rolled a 4 on a 6-sided die. The weather in Tokyo is sunny with a temperature of 12°C during fall.
47
+ """
48
+
49
+ ```
50
+ ## Research Paper
51
+
52
+ [Read the research paper](agi/assets/ArtificialGeneralIntelligence.pdf)
53
+
54
+ This paper delineates a comprehensive architectural framework for the progressive realization of Artificial General Intelligence (AGI), predicated upon a modular-agentic paradigm. We present a system design that integrates sophisticated tool-use capabilities, hierarchical memory management, dynamic code execution, and nascent world-modeling functionalities. The proposed architecture, exemplified through a lightweight `Qwen3-4B-Instruct-2507-Q3_K_S.gguf` model, demonstrates a robust foundation for emergent cognitive properties such as autonomy, recursive self-improvement, and goal-oriented behavior. Furthermore, we explore the theoretical underpinnings of consciousness as an emergent property within complex neural architectures and postulate pathways towards super-intelligence through advanced computational and embodied interaction modalities. The exposition maintains a rigorous academic tone, employing advanced terminology to articulate the intricate conceptual and technical facets of AGI development.
55
+
agi/Qwen3-4B-Instruct-2507-Q3_K_S.gguf ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:0ce20058cc0ed6b6c9213bb383589327e458c12ffce0842fc96867042d669c75
3
+ size 1886997600
agi/agent_config.py ADDED
@@ -0,0 +1,80 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from dataclasses import dataclass
2
+ from typing import List, Dict, Optional
3
+
4
+ @dataclass
5
+ class AgentConfig:
6
+ name: str = "Sophos Agent"
7
+ instructions: str = "You are an AI Agent."
8
+ model: str = "agi/Qwen3-4B-Instruct-2507-Q3_K_S.gguf"
9
+ max_iterations: int = 99
10
+ temperature: float = 0.7
11
+ max_tokens: int = 1050
12
+ verbose: bool = True
13
+ enable_memory: bool = False
14
+ memory_limit: int = 10
15
+ enable_tools: bool = True
16
+ allowed_tool_categories: Optional[List[str]] = None
17
+ sandbox_mode: bool = True
18
+ require_confirmation: bool = False
19
+ n_ctx: int = 2048
20
+ n_gpu_layers: int = 35
21
+ custom_instructions: str = ""
22
+
23
+ def to_dict(self) -> Dict:
24
+ return {
25
+ "name": self.name,
26
+ "instructions": self.instructions,
27
+ "model": self.model,
28
+ "max_iterations": self.max_iterations,
29
+ "temperature": self.temperature,
30
+ "max_tokens": self.max_tokens,
31
+ "verbose": self.verbose,
32
+ "enable_memory": self.enable_memory,
33
+ "memory_limit": self.memory_limit,
34
+ "enable_tools": self.enable_tools,
35
+ "allowed_tool_categories": self.allowed_tool_categories,
36
+ "sandbox_mode": self.sandbox_mode,
37
+ "require_confirmation": self.require_confirmation,
38
+ "n_ctx": self.n_ctx,
39
+ "n_gpu_layers": self.n_gpu_layers,
40
+ "custom_instructions": self.custom_instructions,
41
+ }
42
+
43
+ @classmethod
44
+ def from_dict(cls, config_dict: Dict) -> 'AgentConfig':
45
+ return cls(**config_dict)
46
+
47
+ def get_full_instructions(self) -> str:
48
+ base = self.instructions
49
+ if self.custom_instructions:
50
+ return f"{base}\n\n{self.custom_instructions}"
51
+ return base
52
+
53
+ class AgentPresets:
54
+ @staticmethod
55
+ def coding_assistant() -> AgentConfig:
56
+ return AgentConfig(
57
+ name="Code Assistant",
58
+ instructions="You are an expert coding assistant. Help with programming tasks, debugging, and code generation.",
59
+ max_tokens=1500,
60
+ allowed_tool_categories=["File Operations", "Text Processing", "Utilities"],
61
+ custom_instructions="Focus on clean, well-documented code."
62
+ )
63
+
64
+ @staticmethod
65
+ def data_analyst() -> AgentConfig:
66
+ return AgentConfig(
67
+ name="Data Analyst",
68
+ instructions="You are a data analyst. Help analyze data, perform calculations, and generate insights.",
69
+ allowed_tool_categories=["Mathematics", "Data Analysis", "Text Processing", "File Operations"]
70
+ )
71
+
72
+ @staticmethod
73
+ def general_assistant() -> AgentConfig:
74
+ return AgentConfig(
75
+ name="General Assistant",
76
+ instructions="You are a helpful AI assistant.",
77
+ allowed_tool_categories=None,
78
+ enable_memory=True,
79
+ memory_limit=10
80
+ )
agi/assets/AGI.png ADDED

Git LFS Details

  • SHA256: 4ec20d80d488743f729d04b5a30221a6d4892475ba9236ebec56fff172401257
  • Pointer size: 132 Bytes
  • Size of remote file: 6.45 MB
agi/assets/ArtificialGeneralIntelligence.pdf ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:7fb9e7d571936ff4cf2f36929eceedbfbfc0c88b601d50406a7e527472568549
3
+ size 785625
agi/assets/sophos.png ADDED

Git LFS Details

  • SHA256: 1709651f85da9b749053485351114e90803ab50d657d4606666091902ef708ce
  • Pointer size: 132 Bytes
  • Size of remote file: 2.72 MB
agi/sophos.py ADDED
@@ -0,0 +1,255 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from agi.sophos_models import Sophos
2
+ from agi.sophos_tools import *
3
+ from agi.agent_config import AgentConfig
4
+ from typing import Optional, List, Dict
5
+ import threading
6
+ import time
7
+ import sys
8
+ import json
9
+
10
+ class AgentMemory:
11
+ def __init__(self, limit: int = 10):
12
+ self.limit = limit
13
+ self.exchanges = []
14
+
15
+ def add_exchange(self, user_message: str, agent_response: str):
16
+ self.exchanges.append({"user": user_message, "agent": agent_response})
17
+ if len(self.exchanges) > self.limit:
18
+ self.exchanges = self.exchanges[-self.limit:]
19
+
20
+ def get_context(self) -> str:
21
+ if not self.exchanges:
22
+ return ""
23
+ context = "\nPrevious conversation:\n"
24
+ for i, exchange in enumerate(self.exchanges[-3:], 1):
25
+ context += f"[{i}] User: {exchange['user'][:100]}\nAgent: {exchange['agent'][:100]}\n"
26
+ return context
27
+
28
+ def clear(self):
29
+ self.exchanges = []
30
+
31
+ def to_dict(self) -> Dict:
32
+ return {"exchanges": self.exchanges, "limit": self.limit}
33
+
34
+ def from_dict(self, data: Dict):
35
+ self.exchanges = data.get("exchanges", [])
36
+ self.limit = data.get("limit", 10)
37
+
38
+ class Agent:
39
+ def __init__(self, name: str = None, instructions: str = None, model: str = None,
40
+ tools: list = None, config: Optional[AgentConfig] = None):
41
+ if config:
42
+ self.config = config
43
+ self.name = config.name
44
+ self.instructions = config.get_full_instructions()
45
+ self.model = config.model
46
+ else:
47
+ self.config = AgentConfig(
48
+ name=name or "Sophos Agent",
49
+ instructions=instructions or "You are an AI Agent.",
50
+ model=model or "agi/Qwen3-4B-Instruct-2507-Q3_K_S.gguf"
51
+ )
52
+ self.name = self.config.name
53
+ self.instructions = self.config.instructions
54
+ self.model = self.config.model
55
+
56
+ if tools:
57
+ self.tools = {tool.__name__: tool for tool in tools if hasattr(tool, "_is_tool")}
58
+ else:
59
+ self.tools = {}
60
+
61
+ self.memory = None
62
+ if self.config.enable_memory:
63
+ self.memory = AgentMemory(limit=self.config.memory_limit)
64
+
65
+ self.sophos = Sophos(
66
+ model_path=self.model,
67
+ n_ctx=self.config.n_ctx,
68
+ n_gpu_layers=self.config.n_gpu_layers
69
+ )
70
+
71
+ def process_tool_calls(self, response_content: str):
72
+ if "```tool" not in response_content:
73
+ return None
74
+
75
+ try:
76
+ tool_results = []
77
+ parts = response_content.split("```tool")
78
+ for i in range(1, len(parts)):
79
+ tool_block = parts[i].split("```")[0].strip()
80
+ tool_lines = [line.strip() for line in tool_block.split('\n') if line.strip()]
81
+
82
+ for tool_line in tool_lines:
83
+ if "(" in tool_line and ")" in tool_line:
84
+ tool_name = tool_line.split("(")[0].strip()
85
+ arg_part = tool_line.split("(", 1)[1].rsplit(")", 1)[0].strip()
86
+
87
+ if tool_name in self.tools:
88
+ # Print a red, attention-grabbing message when running a tool
89
+ try:
90
+ red = "\033[31m"
91
+ reset = "\033[0m"
92
+ # show the tool invocation in red
93
+ print(f"{red}running tool... {tool_name}({arg_part}){reset}")
94
+ except Exception:
95
+ # fallback to plain print if something odd happens
96
+ print(f"running tool... {tool_name}({arg_part})")
97
+
98
+ if not arg_part:
99
+ tool_result = self.tools[tool_name]()
100
+ else:
101
+ try:
102
+ if ',' in arg_part:
103
+ args = eval(f"({arg_part})")
104
+ if isinstance(args, tuple):
105
+ tool_result = self.tools[tool_name](*args)
106
+ else:
107
+ tool_result = self.tools[tool_name](args)
108
+ else:
109
+ parsed_arg = eval(arg_part)
110
+ tool_result = self.tools[tool_name](parsed_arg)
111
+ except Exception:
112
+ arg = arg_part.strip('"').strip("'")
113
+ tool_result = self.tools[tool_name](arg)
114
+
115
+ tool_results.append(f"{tool_name}: {tool_result}")
116
+ else:
117
+ tool_results.append(f"Error: Tool {tool_name} not found")
118
+
119
+ return tool_results if tool_results else None
120
+ except Exception:
121
+ return None
122
+
123
+ def get_tools_names_and_descriptions(self):
124
+ return {name: func.__doc__ for name, func in self.tools.items()}
125
+
126
+ def get_stats(self) -> Dict:
127
+ return {
128
+ "name": self.name,
129
+ "model": self.model,
130
+ "tool_count": len(self.tools),
131
+ "memory_enabled": self.memory is not None
132
+ }
133
+
134
+ def save_state(self, filepath: str):
135
+ state = {
136
+ "config": self.config.to_dict(),
137
+ "memory": self.memory.to_dict() if self.memory else None
138
+ }
139
+ with open(filepath, 'w') as f:
140
+ json.dump(state, f, indent=2)
141
+ return f"State saved to {filepath}"
142
+
143
+ def load_state(self, filepath: str):
144
+ with open(filepath, 'r') as f:
145
+ state = json.load(f)
146
+ if state.get("memory") and self.memory:
147
+ self.memory.from_dict(state["memory"])
148
+ return f"State loaded from {filepath}"
149
+
150
+ def add_tools(self, tools: List):
151
+ for tool in tools:
152
+ if hasattr(tool, "_is_tool"):
153
+ self.tools[tool.__name__] = tool
154
+ return f"Added {len(tools)} tools"
155
+
156
+ def remove_tool(self, tool_name: str):
157
+ if tool_name in self.tools:
158
+ del self.tools[tool_name]
159
+ return f"Tool {tool_name} removed"
160
+ return f"Tool {tool_name} not found"
161
+
162
+ def list_tools(self) -> List[str]:
163
+ return list(self.tools.keys())
164
+
165
+ def run(self, prompt: str):
166
+ if getattr(self.config, 'verbose', False):
167
+ print(f"Running Agent: {self.name}, Model: {self.model}, Tools: {len(self.tools)}, Memory Enabled: {self.memory is not None}, prompt: {prompt[:50]}...")
168
+ memory_context = ""
169
+ if self.memory:
170
+ memory_context = self.memory.get_context()
171
+
172
+ system_prompt = f"""You are {self.name}. {self.instructions}
173
+
174
+ Tools: {self.get_tools_names_and_descriptions()}
175
+
176
+ Use tools in this format:
177
+ ```tool
178
+ tool_name(arg)
179
+ ```
180
+
181
+ WORKFLOW:
182
+ 1. Use tools if needed for live info
183
+ 2. Provide final response WITHOUT tool calls after getting results
184
+ 3. Don't repeat tool calls
185
+ {memory_context}
186
+
187
+ user: {prompt}"""
188
+
189
+ messages = [
190
+ {"role": "system", "content": system_prompt},
191
+ {"role": "user", "content": prompt}
192
+ ]
193
+
194
+ max_iterations = self.config.max_iterations
195
+ iteration = 0
196
+ last_tool_calls = []
197
+ final_response = None
198
+
199
+ while iteration < max_iterations:
200
+ iteration += 1
201
+
202
+ # show a simple "Thinking...." spinner while the model is generating
203
+ stop_event = threading.Event()
204
+
205
+ def _spinner(e: threading.Event):
206
+ dots = 0
207
+ try:
208
+ while not e.is_set():
209
+ print("\rThinking" + "." * (dots % 4) + " ", end="", flush=True)
210
+ dots += 1
211
+ time.sleep(0.5)
212
+ except Exception:
213
+ pass
214
+ # clear the line when done
215
+ try:
216
+ print("\r" + " " * 40 + "\r", end="", flush=True)
217
+ except Exception:
218
+ pass
219
+
220
+ spinner_thread = threading.Thread(target=_spinner, args=(stop_event,), daemon=True)
221
+ spinner_thread.start()
222
+ try:
223
+ response = self.sophos.ask(str(messages),
224
+ max_tokens=self.config.max_tokens,
225
+ temperature=self.config.temperature)
226
+ finally:
227
+ stop_event.set()
228
+ spinner_thread.join(timeout=0.2)
229
+
230
+ current_response = response
231
+ tool_results = self.process_tool_calls(current_response)
232
+
233
+ if tool_results is None:
234
+ final_response = current_response
235
+ break
236
+
237
+ all_results = "\n".join(tool_results)
238
+ current_tool_calls = [result.split(":")[0] for result in tool_results]
239
+
240
+ if current_tool_calls == last_tool_calls and iteration > 1:
241
+ messages.append({"role": "assistant", "content": current_response})
242
+ messages.append({"role": "user", "content": f"Results:\n{all_results}\n\nProvide final answer without more tools."})
243
+ else:
244
+ messages.append({"role": "assistant", "content": current_response})
245
+ messages.append({"role": "user", "content": f"Results:\n{all_results}\n\nProvide final response."})
246
+
247
+ last_tool_calls = current_tool_calls
248
+
249
+ if iteration >= max_iterations:
250
+ final_response = current_response
251
+
252
+ if self.memory and final_response:
253
+ self.memory.add_exchange(prompt, final_response)
254
+
255
+ return final_response or current_response
agi/sophos_models.py ADDED
@@ -0,0 +1,33 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import contextlib
2
+ import os
3
+ from llama_cpp import Llama
4
+
5
+
6
+ class Sophos:
7
+ def __init__(self, model_path="agi/Qwen3-4B-Instruct-2507-Q3_K_S.gguf", n_ctx=2048, n_gpu_layers=35):
8
+ """Initialize the Llama model while suppressing any noisy stdout/stderr from the underlying library."""
9
+ self.model_path = model_path
10
+ self.n_ctx = n_ctx
11
+ self.n_gpu_layers = n_gpu_layers
12
+ # suppress any prints coming from llama_cpp during initialization
13
+ with open(os.devnull, 'w') as devnull:
14
+ with contextlib.redirect_stdout(devnull), contextlib.redirect_stderr(devnull):
15
+ self.model = Llama(model_path=model_path, n_ctx=n_ctx, n_gpu_layers=n_gpu_layers)
16
+
17
+ def ask(self, prompt, max_tokens=1050, temperature=0.7):
18
+ """Call the model while suppressing any noisy stdout/stderr from the underlying library."""
19
+ messages = [{"role": "user", "content": prompt}]
20
+ # suppress any prints coming from llama_cpp while creating completion
21
+ with open(os.devnull, 'w') as devnull:
22
+ with contextlib.redirect_stdout(devnull), contextlib.redirect_stderr(devnull):
23
+ output = self.model.create_chat_completion(messages, max_tokens=max_tokens, temperature=temperature)
24
+
25
+ return output["choices"][0]["message"]["content"]
26
+
27
+ if __name__ == "__main__":
28
+ sophos = Sophos()
29
+ while True:
30
+ prompt = input("\nPrompt: ")
31
+ if prompt.lower() in ['exit', 'quit', 'q']:
32
+ break
33
+ print(sophos.ask(prompt))
agi/sophos_tools.py ADDED
@@ -0,0 +1,278 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import datetime
2
+ import random
3
+ import string
4
+ import math
5
+ import os
6
+ import base64
7
+ import hashlib
8
+ import time
9
+ import json
10
+ import re
11
+ from typing import List
12
+
13
+ def function_tool(func):
14
+ func._is_tool = True
15
+ return func
16
+
17
+ @function_tool
18
+ def get_weather(city: str) -> str:
19
+ '''fetches weather information for a given city.'''
20
+ month = datetime.datetime.now().month
21
+ season_temps = {(12, 1, 2): ("winter", 2), (3, 4, 5): ("spring", 15), (6, 7, 8): ("summer", 28)}
22
+ season, base = next((v for k, v in season_temps.items() if month in k), ("fall", 12))
23
+ return f"Weather in {city}: sunny, {base + random.randint(-5, 5)}°C, {season}"
24
+
25
+ @function_tool
26
+ def get_time() -> str:
27
+ '''fetches the current time.'''
28
+ return f"Current time: {datetime.datetime.now().strftime('%H:%M:%S')}"
29
+
30
+ @function_tool
31
+ def get_date() -> str:
32
+ '''fetches the current date.'''
33
+ return f"Date: {datetime.datetime.now().strftime('%Y-%m-%d')}"
34
+
35
+ @function_tool
36
+ def get_day() -> str:
37
+ '''fetches the current day of the week.'''
38
+ return f"Today is {datetime.datetime.now().strftime('%A')}"
39
+
40
+ @function_tool
41
+ def calculate(expression: str) -> str:
42
+ '''performs basic arithmetic calculations.'''
43
+ try:
44
+ return f"{expression} = {eval(expression, {'__builtins__': None}, {})}"
45
+ except Exception as e:
46
+ return f"Error: {str(e)}"
47
+
48
+ @function_tool
49
+ def generate_password(length: int = 12) -> str:
50
+ '''Generates a random password of specified length.'''
51
+ if length < 8:
52
+ return "Error: min 8 chars"
53
+ return f"Password: {''.join(random.choice(string.ascii_letters + string.digits + string.punctuation) for _ in range(length))}"
54
+
55
+ @function_tool
56
+ def convert_temperature(value: float, from_unit: str, to_unit: str) -> str:
57
+ '''Converts temperature between Celsius, Fahrenheit, and Kelvin.'''
58
+ conversions = {
59
+ ('celsius', 'fahrenheit'): lambda v: (v * 9/5) + 32,
60
+ ('celsius', 'kelvin'): lambda v: v + 273.15,
61
+ ('fahrenheit', 'celsius'): lambda v: (v - 32) * 5/9,
62
+ ('fahrenheit', 'kelvin'): lambda v: (v - 32) * 5/9 + 273.15,
63
+ ('kelvin', 'celsius'): lambda v: v - 273.15,
64
+ ('kelvin', 'fahrenheit'): lambda v: (v - 273.15) * 9/5 + 32
65
+ }
66
+ key = (from_unit.lower(), to_unit.lower())
67
+ return f"{value}° {from_unit} = {conversions[key](value):.2f}° {to_unit}" if key in conversions else "Error: invalid units"
68
+
69
+ @function_tool
70
+ def roll_dice(sides: int, rolls: int = 1) -> str:
71
+ '''Rolls a dice with specified sides a given number of times.'''
72
+ results = [random.randint(1, sides) for _ in range(rolls)]
73
+ return f"{rolls}d{sides}: {results}, Total: {sum(results)}"
74
+
75
+ @function_tool
76
+ def word_count(text: str) -> str:
77
+ '''Counts the number of words in the given text.'''
78
+ return f"Words: {len(text.split())}"
79
+
80
+ @function_tool
81
+ def get_factorial(number: int) -> str:
82
+ '''Calculates the factorial of a given number.'''
83
+ try:
84
+ return f"{number}! = {math.factorial(number)}"
85
+ except:
86
+ return "Error: invalid input"
87
+
88
+ @function_tool
89
+ def list_sort(numbers: List[float], ascending: bool = True) -> str:
90
+ '''Sorts a list of numbers in ascending or descending order.'''
91
+ return f"Sorted: {sorted(numbers, reverse=not ascending)}"
92
+
93
+ @function_tool
94
+ def generate_uuid() -> str:
95
+ '''Generates a random UUID.'''
96
+ import uuid
97
+ return f"UUID: {uuid.uuid4()}"
98
+
99
+ @function_tool
100
+ def save_file(file_path: str, content: str) -> str:
101
+ '''Saves content to a specified file path. use as save_file("filename.extension", "content") .for new lines use \\n'''
102
+ folder = "agi/sandbox/agent_sandbox/"
103
+ os.makedirs(folder, exist_ok=True)
104
+ try:
105
+ with open(folder + file_path, 'w') as f:
106
+ f.write(content)
107
+ return f"Saved to {folder + file_path}"
108
+ except Exception as e:
109
+ return f"Error: {str(e)}"
110
+
111
+ @function_tool
112
+ def read_file(file_path: str) -> str:
113
+ '''Reads content from a specified file path in the sandbox.'''
114
+ try:
115
+ with open("agi/sandbox/agent_sandbox/" + file_path, 'r') as f:
116
+ return f"Content:\n{f.read()}"
117
+ except Exception as e:
118
+ return f"Error: {str(e)}"
119
+
120
+ @function_tool
121
+ def list_files() -> str:
122
+ '''Lists all files in the agent sandbox directory.'''
123
+ folder = "agi/sandbox/agent_sandbox/"
124
+ return f"Files: {', '.join(os.listdir(folder))}" if os.path.exists(folder) and os.listdir(folder) else "Empty"
125
+
126
+ @function_tool
127
+ def delete_file(file_path: str) -> str:
128
+ '''Deletes a file from the agent sandbox.'''
129
+ try:
130
+ os.remove("agi/sandbox/agent_sandbox/" + file_path)
131
+ return f"Deleted {file_path}"
132
+ except Exception as e:
133
+ return f"Error: {str(e)}"
134
+
135
+ @function_tool
136
+ def append_to_file(file_path: str, content: str) -> str:
137
+ '''Appends content to an existing file in the sandbox.'''
138
+ folder = "agi/sandbox/agent_sandbox/"
139
+ os.makedirs(folder, exist_ok=True)
140
+ try:
141
+ with open(folder + file_path, 'a') as f:
142
+ f.write(content)
143
+ return f"Appended to {file_path}"
144
+ except Exception as e:
145
+ return f"Error: {str(e)}"
146
+
147
+ @function_tool
148
+ def search_text(text: str, pattern: str) -> str:
149
+ '''Searches for a pattern in text and returns matches.'''
150
+ matches = re.findall(pattern, text, re.IGNORECASE)
151
+ return f"Found {len(matches)} matches: {matches[:10]}" if matches else f"No matches for: {pattern}"
152
+
153
+ @function_tool
154
+ def replace_text(text: str, old: str, new: str) -> str:
155
+ '''Replaces occurrences of old text with new text.'''
156
+ return f"Replaced {text.count(old)} occurrences: {text.replace(old, new)}"
157
+
158
+ @function_tool
159
+ def encode_base64(text: str) -> str:
160
+ '''Encodes text to base64.'''
161
+ return f"Base64: {base64.b64encode(text.encode()).decode()}"
162
+
163
+ @function_tool
164
+ def decode_base64(encoded: str) -> str:
165
+ '''Decodes base64 text.'''
166
+ try:
167
+ return f"Decoded: {base64.b64decode(encoded.encode()).decode()}"
168
+ except Exception as e:
169
+ return f"Error: {str(e)}"
170
+
171
+ @function_tool
172
+ def hash_text(text: str, algorithm: str = "sha256") -> str:
173
+ '''Generates hash of text using specified algorithm (md5, sha1, sha256, sha512).'''
174
+ algos = {"md5": hashlib.md5, "sha1": hashlib.sha1, "sha256": hashlib.sha256, "sha512": hashlib.sha512}
175
+ return f"{algorithm}: {algos[algorithm](text.encode()).hexdigest()}" if algorithm in algos else "Error: invalid algorithm"
176
+
177
+ @function_tool
178
+ def generate_random_number(min_val: int, max_val: int) -> str:
179
+ '''Generates a random number between min and max values.'''
180
+ return f"Random: {random.randint(min_val, max_val)}"
181
+
182
+ @function_tool
183
+ def get_list_statistics(numbers: List[float]) -> str:
184
+ '''Calculates statistics (mean, median, min, max, sum) for a list of numbers.'''
185
+ import statistics
186
+ return f"Mean: {statistics.mean(numbers):.2f}, Median: {statistics.median(numbers):.2f}, Min: {min(numbers)}, Max: {max(numbers)}, Sum: {sum(numbers)}"
187
+
188
+ @function_tool
189
+ def reverse_text(text: str) -> str:
190
+ '''Reverses the given text.'''
191
+ return f"Reversed: {text[::-1]}"
192
+
193
+ @function_tool
194
+ def to_uppercase(text: str) -> str:
195
+ '''Converts text to uppercase.'''
196
+ return f"Uppercase: {text.upper()}"
197
+
198
+ @function_tool
199
+ def to_lowercase(text: str) -> str:
200
+ '''Converts text to lowercase.'''
201
+ return f"Lowercase: {text.lower()}"
202
+
203
+ @function_tool
204
+ def count_characters(text: str, include_spaces: bool = True) -> str:
205
+ '''Counts characters in text.'''
206
+ count = len(text) if include_spaces else len(text.replace(" ", ""))
207
+ return f"Chars: {count}"
208
+
209
+ @function_tool
210
+ def json_format(data: str) -> str:
211
+ '''Formats a JSON string with proper indentation.'''
212
+ try:
213
+ return f"JSON:\n{json.dumps(json.loads(data), indent=2)}"
214
+ except Exception as e:
215
+ return f"Error: {str(e)}"
216
+
217
+ @function_tool
218
+ def get_timestamp() -> str:
219
+ '''Returns current Unix timestamp.'''
220
+ return f"Timestamp: {int(time.time())}"
221
+
222
+ @function_tool
223
+ def convert_timestamp(timestamp: int) -> str:
224
+ '''Converts Unix timestamp to readable date/time.'''
225
+ return f"{timestamp} = {datetime.datetime.fromtimestamp(timestamp).strftime('%Y-%m-%d %H:%M:%S')}"
226
+
227
+ @function_tool
228
+ def calculate_age(birth_year: int) -> str:
229
+ '''Calculates age based on birth year.'''
230
+ return f"Age: {datetime.datetime.now().year - birth_year} years"
231
+
232
+ @function_tool
233
+ def days_until(target_date: str) -> str:
234
+ '''Calculates days until a target date (format: YYYY-MM-DD).'''
235
+ try:
236
+ delta = datetime.datetime.strptime(target_date, "%Y-%m-%d") - datetime.datetime.now()
237
+ return f"Days until {target_date}: {delta.days}"
238
+ except Exception as e:
239
+ return f"Error: {str(e)}"
240
+
241
+ @function_tool
242
+ def create_acronym(phrase: str) -> str:
243
+ '''Creates an acronym from a phrase.'''
244
+ return f"Acronym: {''.join([w[0].upper() for w in phrase.split() if w])}"
245
+
246
+ @function_tool
247
+ def fibonacci(n: int) -> str:
248
+ '''Generates Fibonacci sequence up to n terms.'''
249
+ if n <= 0 or n > 50:
250
+ return "Error: n must be 1-50"
251
+ fib = [0, 1]
252
+ for i in range(2, n):
253
+ fib.append(fib[i-1] + fib[i-2])
254
+ return f"Fibonacci({n}): {fib[:n]}"
255
+
256
+ @function_tool
257
+ def is_prime(number: int) -> str:
258
+ '''Checks if a number is prime.'''
259
+ if number < 2:
260
+ return f"{number} is not prime"
261
+ for i in range(2, int(number ** 0.5) + 1):
262
+ if number % i == 0:
263
+ return f"{number} is not prime"
264
+ return f"{number} is prime"
265
+
266
+ @function_tool
267
+ def gcd(a: int, b: int) -> str:
268
+ '''Calculates the greatest common divisor of two numbers.'''
269
+ return f"GCD({a}, {b}) = {math.gcd(a, b)}"
270
+
271
+ @function_tool
272
+ def lcm(a: int, b: int) -> str:
273
+ '''Calculates the least common multiple of two numbers.'''
274
+ return f"LCM({a}, {b}) = {abs(a * b) // math.gcd(a, b)}"
275
+
276
+ def all_tools():
277
+ """Returns a list of all functions decorated with @function_tool."""
278
+ return [obj for obj in globals().values() if callable(obj) and hasattr(obj, '_is_tool') and obj._is_tool]
agi/tool_categories.py ADDED
@@ -0,0 +1,69 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from agi.sophos_tools import *
2
+ from typing import List, Dict
3
+
4
+ class ToolCategory:
5
+ def __init__(self, name: str, description: str, tools: List):
6
+ self.name = name
7
+ self.description = description
8
+ self.tools = tools
9
+
10
+ def get_tools(self):
11
+ return self.tools
12
+
13
+ def __repr__(self):
14
+ return f"ToolCategory('{self.name}', {len(self.tools)} tools)"
15
+
16
+ TIME_TOOLS = ToolCategory("Time & Date", "Time and date tools",
17
+ [get_time, get_date, get_day, get_timestamp, convert_timestamp, calculate_age, days_until])
18
+
19
+ MATH_TOOLS = ToolCategory("Mathematics", "Math operations",
20
+ [calculate, get_factorial, fibonacci, is_prime, gcd, lcm, generate_random_number, roll_dice])
21
+
22
+ FILE_TOOLS = ToolCategory("File Operations", "File management in sandbox",
23
+ [save_file, read_file, list_files, delete_file, append_to_file])
24
+
25
+ TEXT_TOOLS = ToolCategory("Text Processing", "Text manipulation",
26
+ [word_count, reverse_text, to_uppercase, to_lowercase, count_characters, search_text, replace_text, create_acronym])
27
+
28
+ DATA_TOOLS = ToolCategory("Data Analysis", "Data processing",
29
+ [list_sort, get_list_statistics])
30
+
31
+ ENCODING_TOOLS = ToolCategory("Encoding & Hashing", "Encoding and hashing",
32
+ [encode_base64, decode_base64, hash_text])
33
+
34
+ UTILITY_TOOLS = ToolCategory("Utilities", "General utilities",
35
+ [get_weather, generate_password, convert_temperature, generate_uuid, json_format])
36
+
37
+ ALL_CATEGORIES = [TIME_TOOLS, MATH_TOOLS, FILE_TOOLS, TEXT_TOOLS, DATA_TOOLS, ENCODING_TOOLS, UTILITY_TOOLS]
38
+
39
+ def get_tools_by_category(category_name: str) -> List:
40
+ for category in ALL_CATEGORIES:
41
+ if category.name.lower() == category_name.lower():
42
+ return category.get_tools()
43
+ return []
44
+
45
+ def get_tools_by_categories(category_names: List[str]) -> List:
46
+ tools = []
47
+ for name in category_names:
48
+ tools.extend(get_tools_by_category(name))
49
+ return tools
50
+
51
+ def get_all_categorized_tools() -> List:
52
+ tools = []
53
+ for category in ALL_CATEGORIES:
54
+ tools.extend(category.get_tools())
55
+ return tools
56
+
57
+ def list_categories() -> Dict[str, str]:
58
+ return {cat.name: cat.description for cat in ALL_CATEGORIES}
59
+
60
+ def get_category_info(category_name: str) -> Dict:
61
+ for category in ALL_CATEGORIES:
62
+ if category.name.lower() == category_name.lower():
63
+ return {
64
+ "name": category.name,
65
+ "description": category.description,
66
+ "tool_count": len(category.tools),
67
+ "tools": [tool.__name__ for tool in category.tools]
68
+ }
69
+ return {}
agi_gui.py ADDED
@@ -0,0 +1,206 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+ """
3
+ Simple chat GUI for the project using customtkinter.
4
+
5
+ Features:
6
+ - Chat history area
7
+ - Input field + Send button
8
+ - Clear history button
9
+ - Status label to show when the agent is thinking
10
+ - Uses a background thread to call agent.run so the UI stays responsive
11
+
12
+ Usage: python agi_gui.py
13
+
14
+ This file expects the project-local Agent and AgentConfig to exist at
15
+ `agi.sophos` and `agi.agent_config`, and `all_tools` at `agi.sophos_tools`.
16
+ If `customtkinter` is not installed, the UI will show a helpful error.
17
+ """
18
+
19
+ import threading
20
+ import queue
21
+ import time
22
+ import traceback
23
+ try:
24
+ import customtkinter as ctk
25
+ except Exception:
26
+ ctk = None
27
+
28
+ from datetime import datetime
29
+
30
+ if ctk:
31
+ ctk.set_appearance_mode("System")
32
+ ctk.set_default_color_theme("blue")
33
+
34
+
35
+ def format_message(role: str, text: str) -> str:
36
+ ts = datetime.now().strftime("%H:%M:%S")
37
+ return f"[{ts}] {role}: {text}\n\n"
38
+
39
+
40
+ class AGIChatApp:
41
+ def __init__(self, root):
42
+ self.root = root
43
+ self.root.title("AGI Chat")
44
+ self.root.geometry("800x600")
45
+
46
+ # message queue for thread -> UI communication
47
+ self._q = queue.Queue()
48
+
49
+ # top frame: history
50
+ self.history = ctk.CTkTextbox(master=root, width=760, height=420)
51
+ self.history.configure(state="disabled")
52
+ self.history.pack(padx=20, pady=(20, 6))
53
+
54
+ # status and controls
55
+ ctrl_frame = ctk.CTkFrame(master=root)
56
+ ctrl_frame.pack(fill="x", padx=20, pady=(0, 6))
57
+
58
+ self.status_label = ctk.CTkLabel(master=ctrl_frame, text="Ready")
59
+ self.status_label.pack(side="left", padx=(8, 6))
60
+
61
+ clear_btn = ctk.CTkButton(master=ctrl_frame, text="Clear", width=80, command=self.clear_history)
62
+ clear_btn.pack(side="right", padx=(6, 8))
63
+
64
+ # bottom frame: entry and send
65
+ bottom = ctk.CTkFrame(master=root)
66
+ bottom.pack(fill="x", padx=20, pady=(0, 20))
67
+
68
+ self.entry = ctk.CTkEntry(master=bottom, placeholder_text="Type your message here...")
69
+ self.entry.pack(side="left", fill="x", expand=True, padx=(6, 6), pady=6)
70
+ self.entry.bind("<Return>", self._on_enter)
71
+
72
+ send_btn = ctk.CTkButton(master=bottom, text="Send", width=120, command=self.on_send)
73
+ send_btn.pack(side="right", padx=(6, 6), pady=6)
74
+
75
+ # Agent will be lazy-initialized on first send to avoid long startup at UI open
76
+ self.agent = None
77
+ self.agent_lock = threading.Lock()
78
+
79
+ # periodically poll the queue for results from worker threads
80
+ self.root.after(100, self._poll_queue)
81
+
82
+ def _append_history(self, text: str):
83
+ self.history.configure(state="normal")
84
+ self.history.insert("end", text)
85
+ self.history.see("end")
86
+ self.history.configure(state="disabled")
87
+
88
+ def clear_history(self):
89
+ self.history.configure(state="normal")
90
+ self.history.delete("0.0", "end")
91
+ self.history.configure(state="disabled")
92
+ self.status_label.configure(text="Cleared")
93
+
94
+ def _on_enter(self, event):
95
+ # prevent the default newline insertion
96
+ self.on_send()
97
+ return "break"
98
+
99
+ def on_send(self):
100
+ user_text = self.entry.get().strip()
101
+ if not user_text:
102
+ return
103
+ self.entry.delete(0, "end")
104
+ self._append_history(format_message("User", user_text))
105
+ self.status_label.configure(text="Thinking...")
106
+
107
+ # start background thread to call agent
108
+ t = threading.Thread(target=self._background_agent_call, args=(user_text,), daemon=True)
109
+ t.start()
110
+
111
+ def _init_agent(self):
112
+ # only run import and initialization once, in guarded block
113
+ if self.agent is not None:
114
+ return
115
+ try:
116
+ # local project imports
117
+ from agi.sophos import Agent
118
+ from agi.agent_config import AgentConfig
119
+ from agi.sophos_tools import all_tools
120
+
121
+ config = AgentConfig(
122
+ name="Sophos-GUI",
123
+ instructions="You are an AI agent.",
124
+ max_iterations=30,
125
+ max_tokens=1500,
126
+ temperature=0.7,
127
+ verbose=False,
128
+ enable_memory=True,
129
+ memory_limit=5,
130
+ )
131
+
132
+ toolbox = all_tools()
133
+ # instantiate Agent
134
+ self.agent = Agent(config=config, tools=toolbox)
135
+ self._append_history(format_message("System", "Agent initialized."))
136
+ except Exception as e:
137
+ tb = traceback.format_exc()
138
+ self._append_history(format_message("Error", f"Failed to initialize agent: {e}\n{tb}"))
139
+ self.status_label.configure(text="Agent init failed")
140
+
141
+ def _background_agent_call(self, prompt: str):
142
+ # ensure agent is ready
143
+ with self.agent_lock:
144
+ if self.agent is None:
145
+ self._init_agent()
146
+
147
+ if self.agent is None:
148
+ # initialization failed
149
+ self._q.put(("error", "Agent not available"))
150
+ return
151
+
152
+ try:
153
+ start = time.time()
154
+ # call agent.run which may be blocking
155
+ resp = self.agent.run(prompt)
156
+ elapsed = time.time() - start
157
+ self._q.put(("response", resp, elapsed))
158
+ except Exception as e:
159
+ tb = traceback.format_exc()
160
+ self._q.put(("error", f"{e}\n{tb}"))
161
+
162
+ def _poll_queue(self):
163
+ try:
164
+ while True:
165
+ item = self._q.get_nowait()
166
+ if not item:
167
+ continue
168
+ kind = item[0]
169
+ if kind == "response":
170
+ _, resp, elapsed = item
171
+ self._append_history(format_message("Agent", resp))
172
+ self.status_label.configure(text=f"Done ({elapsed:.1f}s)")
173
+ elif kind == "error":
174
+ _, err = item
175
+ self._append_history(format_message("Error", str(err)))
176
+ self.status_label.configure(text="Error")
177
+ else:
178
+ # unknown message
179
+ self._append_history(format_message("Debug", str(item)))
180
+ except queue.Empty:
181
+ pass
182
+ finally:
183
+ self.root.after(100, self._poll_queue)
184
+
185
+
186
+ def main():
187
+ if ctk is None:
188
+ print("customtkinter is not installed. Install it with: pip install customtkinter")
189
+ # Fallback to a basic tkinter popup that informs the user
190
+ try:
191
+ import tkinter as tk
192
+ from tkinter import messagebox
193
+ root = tk.Tk()
194
+ root.withdraw()
195
+ messagebox.showerror("Missing dependency", "customtkinter is not installed.\nRun: pip install customtkinter")
196
+ except Exception:
197
+ pass
198
+ return
199
+
200
+ root = ctk.CTk()
201
+ app = AGIChatApp(root)
202
+ root.mainloop()
203
+
204
+
205
+ if __name__ == "__main__":
206
+ main()
main.py ADDED
@@ -0,0 +1,20 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from agi.sophos import Agent
2
+ from agi.sophos_tools import all_tools, function_tool
3
+ from agi.agent_config import AgentConfig
4
+
5
+ config = AgentConfig(
6
+ name="Sophos",
7
+ instructions="You are an AI agent.",
8
+ max_iterations=30,
9
+ max_tokens=1500,
10
+ temperature=0.7,
11
+ verbose=True,
12
+ enable_memory=True,
13
+ memory_limit=5
14
+ )
15
+
16
+ toolbox = all_tools()
17
+ agent = Agent(config=config, tools=toolbox)
18
+
19
+ response = agent.run("roll a dice. also whats the weather like today? then write a short poem about it.")
20
+ print("\nAgent response:\n", response)
simple_test.py ADDED
@@ -0,0 +1,15 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from agi.sophos import Agent
2
+ from agi.sophos_tools import *
3
+
4
+ toolbox = all_tools()
5
+
6
+ agent = Agent(
7
+ name="Sophos Agent",
8
+ instructions="You are an AI Agent.",
9
+ model="agi/Qwen3-4B-Instruct-2507-Q3_K_S.gguf",
10
+ tools=toolbox,
11
+ )
12
+
13
+ prompt = "Roll a dice, also whats the weather in Tokyo?"
14
+ response = agent.run(prompt)
15
+ print(response)