Skip to content

Commit 05fb85d

Browse files
committed
deepcode+nanobot
1 parent 3d6f6a8 commit 05fb85d

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

49 files changed

+1298
-1243
lines changed

nanobot/COMMUNICATION.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,4 @@ We provide QR codes for joining the HKUDS discussion groups on **WeChat** and **
22

33
You can join by scanning the QR codes below:
44

5-
<img src="https://github.com/HKUDS/.github/blob/main/profile/QR.png" alt="WeChat QR Code" width="400"/>
5+
<img src="https://github.com/HKUDS/.github/blob/main/profile/QR.png" alt="WeChat QR Code" width="400"/>

nanobot/LICENSE

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,4 +18,4 @@ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
1818
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
1919
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
2020
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21-
SOFTWARE.
21+
SOFTWARE.

nanobot/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
</p>
1313
</div>
1414

15-
🐈 **nanobot** is an **ultra-lightweight** personal AI assistant inspired by [Clawdbot](https://github.com/openclaw/openclaw)
15+
🐈 **nanobot** is an **ultra-lightweight** personal AI assistant inspired by [Clawdbot](https://github.com/openclaw/openclaw)
1616

1717
⚡️ Delivers core agent functionality in just **~4,000** lines of code — **99% smaller** than Clawdbot's 430k+ lines.
1818

nanobot/bridge/src/index.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
11
#!/usr/bin/env node
22
/**
33
* nanobot WhatsApp Bridge
4-
*
4+
*
55
* This bridge connects WhatsApp Web to nanobot's Python backend
66
* via WebSocket. It handles authentication, message forwarding,
77
* and reconnection logic.
8-
*
8+
*
99
* Usage:
1010
* npm run build && npm start
11-
*
11+
*
1212
* Or with custom settings:
1313
* BRIDGE_PORT=3001 AUTH_DIR=~/.nanobot/whatsapp npm start
1414
*/

nanobot/nanobot/agent/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
"""Agent core module."""
22

3-
from nanobot.agent.loop import AgentLoop
43
from nanobot.agent.context import ContextBuilder
4+
from nanobot.agent.loop import AgentLoop
55
from nanobot.agent.memory import MemoryStore
66
from nanobot.agent.skills import SkillsLoader
77

nanobot/nanobot/agent/context.py

Lines changed: 34 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -13,51 +13,51 @@
1313
class ContextBuilder:
1414
"""
1515
Builds the context (system prompt + messages) for the agent.
16-
16+
1717
Assembles bootstrap files, memory, skills, and conversation history
1818
into a coherent prompt for the LLM.
1919
"""
20-
20+
2121
BOOTSTRAP_FILES = ["AGENTS.md", "SOUL.md", "USER.md", "TOOLS.md", "IDENTITY.md"]
22-
22+
2323
def __init__(self, workspace: Path):
2424
self.workspace = workspace
2525
self.memory = MemoryStore(workspace)
2626
self.skills = SkillsLoader(workspace)
27-
27+
2828
def build_system_prompt(self, skill_names: list[str] | None = None) -> str:
2929
"""
3030
Build the system prompt from bootstrap files, memory, and skills.
31-
31+
3232
Args:
3333
skill_names: Optional list of skills to include.
34-
34+
3535
Returns:
3636
Complete system prompt.
3737
"""
3838
parts = []
39-
39+
4040
# Core identity
4141
parts.append(self._get_identity())
42-
42+
4343
# Bootstrap files
4444
bootstrap = self._load_bootstrap_files()
4545
if bootstrap:
4646
parts.append(bootstrap)
47-
47+
4848
# Memory context
4949
memory = self.memory.get_memory_context()
5050
if memory:
5151
parts.append(f"# Memory\n\n{memory}")
52-
52+
5353
# Skills - progressive loading
5454
# 1. Always-loaded skills: include full content
5555
always_skills = self.skills.get_always_skills()
5656
if always_skills:
5757
always_content = self.skills.load_skills_for_context(always_skills)
5858
if always_content:
5959
parts.append(f"# Active Skills\n\n{always_content}")
60-
60+
6161
# 2. Available skills: only show summary (agent uses read_file to load)
6262
skills_summary = self.skills.build_skills_summary()
6363
if skills_summary:
@@ -67,17 +67,18 @@ def build_system_prompt(self, skill_names: list[str] | None = None) -> str:
6767
Skills with available="false" need dependencies installed first - you can try installing them with apt/brew.
6868
6969
{skills_summary}""")
70-
70+
7171
return "\n\n---\n\n".join(parts)
72-
72+
7373
def _get_identity(self) -> str:
7474
"""Get the core identity section."""
7575
from datetime import datetime
76+
7677
now = datetime.now().strftime("%Y-%m-%d %H:%M (%A)")
7778
workspace_path = str(self.workspace.expanduser().resolve())
7879
system = platform.system()
7980
runtime = f"{'macOS' if system == 'Darwin' else system} {platform.machine()}, Python {platform.python_version()}"
80-
81+
8182
return f"""# nanobot 🐈
8283
8384
You are nanobot, a helpful AI assistant. You have access to tools that allow you to:
@@ -105,19 +106,19 @@ def _get_identity(self) -> str:
105106
106107
Always be helpful, accurate, and concise. When using tools, explain what you're doing.
107108
When remembering something, write to {workspace_path}/memory/MEMORY.md"""
108-
109+
109110
def _load_bootstrap_files(self) -> str:
110111
"""Load all bootstrap files from workspace."""
111112
parts = []
112-
113+
113114
for filename in self.BOOTSTRAP_FILES:
114115
file_path = self.workspace / filename
115116
if file_path.exists():
116117
content = file_path.read_text(encoding="utf-8")
117118
parts.append(f"## {filename}\n\n{content}")
118-
119+
119120
return "\n\n".join(parts) if parts else ""
120-
121+
121122
def build_messages(
122123
self,
123124
history: list[dict[str, Any]],
@@ -162,7 +163,7 @@ def _build_user_content(self, text: str, media: list[str] | None) -> str | list[
162163
"""Build user message content with optional base64-encoded images."""
163164
if not media:
164165
return text
165-
166+
166167
images = []
167168
for path in media:
168169
p = Path(path)
@@ -171,38 +172,31 @@ def _build_user_content(self, text: str, media: list[str] | None) -> str | list[
171172
continue
172173
b64 = base64.b64encode(p.read_bytes()).decode()
173174
images.append({"type": "image_url", "image_url": {"url": f"data:{mime};base64,{b64}"}})
174-
175+
175176
if not images:
176177
return text
177178
return images + [{"type": "text", "text": text}]
178-
179+
179180
def add_tool_result(
180-
self,
181-
messages: list[dict[str, Any]],
182-
tool_call_id: str,
183-
tool_name: str,
184-
result: str
181+
self, messages: list[dict[str, Any]], tool_call_id: str, tool_name: str, result: str
185182
) -> list[dict[str, Any]]:
186183
"""
187184
Add a tool result to the message list.
188-
185+
189186
Args:
190187
messages: Current message list.
191188
tool_call_id: ID of the tool call.
192189
tool_name: Name of the tool.
193190
result: Tool execution result.
194-
191+
195192
Returns:
196193
Updated message list.
197194
"""
198-
messages.append({
199-
"role": "tool",
200-
"tool_call_id": tool_call_id,
201-
"name": tool_name,
202-
"content": result
203-
})
195+
messages.append(
196+
{"role": "tool", "tool_call_id": tool_call_id, "name": tool_name, "content": result}
197+
)
204198
return messages
205-
199+
206200
def add_assistant_message(
207201
self,
208202
messages: list[dict[str, Any]],
@@ -212,24 +206,24 @@ def add_assistant_message(
212206
) -> list[dict[str, Any]]:
213207
"""
214208
Add an assistant message to the message list.
215-
209+
216210
Args:
217211
messages: Current message list.
218212
content: Message content.
219213
tool_calls: Optional tool calls.
220214
reasoning_content: Thinking output (Kimi, DeepSeek-R1, etc.).
221-
215+
222216
Returns:
223217
Updated message list.
224218
"""
225219
msg: dict[str, Any] = {"role": "assistant", "content": content or ""}
226-
220+
227221
if tool_calls:
228222
msg["tool_calls"] = tool_calls
229-
223+
230224
# Thinking models reject history without this
231225
if reasoning_content:
232226
msg["reasoning_content"] = reasoning_content
233-
227+
234228
messages.append(msg)
235229
return messages

0 commit comments

Comments
 (0)