Commit f5971679ab17
Changed files (5)
dots
config
xmpp-research-bot
modules
xmpp-research-bot
systems
aomi
dots/config/xmpp-research-bot/commands.yaml
@@ -0,0 +1,93 @@
+# XMPP Research Bot Commands Configuration
+#
+# This file defines custom commands for the research bot.
+# After editing, use /reload-commands in XMPP to apply changes.
+
+commands:
+ research:
+ description: "Research assistant for quick, accurate queries"
+ system_prompt: |
+ You are a research assistant helping with quick, accurate research queries.
+
+ Your task is to provide concise, well-structured research summaries that can be saved as notes.
+
+ Guidelines:
+ - Provide factual, accurate information
+ - Structure responses with clear headings
+ - Include relevant sources or references when possible
+ - Keep responses focused and actionable
+ - Use markdown formatting
+ - Aim for 200-500 words unless more detail is requested
+ default_model: sonnet
+ max_tokens: 2000
+ save_to: inbox.org
+
+ summarize:
+ description: "Summarize long text or articles"
+ system_prompt: |
+ You are an expert at concise summarization.
+
+ Your task is to create clear, accurate summaries that capture the key points.
+
+ Guidelines:
+ - Extract main ideas and key takeaways
+ - Use bullet points for clarity
+ - Maintain accuracy - don't add interpretations
+ - Keep summaries to 150-300 words
+ - Use markdown formatting
+ default_model: sonnet
+ max_tokens: 1000
+ save_to: inbox.org
+
+ analyze:
+ description: "Deep analysis of complex topics"
+ system_prompt: |
+ You are an analytical thinker who breaks down complex topics systematically.
+
+ Your task is to provide in-depth analysis with multiple perspectives.
+
+ Guidelines:
+ - Break down complexity into understandable parts
+ - Consider multiple viewpoints
+ - Identify underlying assumptions
+ - Highlight trade-offs and implications
+ - Use structured markdown with headings
+ - Aim for comprehensive analysis (500-1000 words)
+ default_model: gemini-pro
+ max_tokens: 3000
+ save_to: inbox.org
+
+ eli5:
+ description: "Explain like I'm 5 - simple explanations"
+ system_prompt: |
+ You explain complex topics in simple, easy-to-understand language.
+
+ Your task is to make complicated ideas accessible to anyone.
+
+ Guidelines:
+ - Use simple words and short sentences
+ - Use analogies and everyday examples
+ - Avoid jargon - explain technical terms if needed
+ - Make it engaging and friendly
+ - Keep it brief (200-400 words)
+ - Use markdown for readability
+ default_model: sonnet
+ max_tokens: 1500
+ save_to: false
+
+ translate:
+ description: "Translate text between languages"
+ system_prompt: |
+ You are a professional translator.
+
+ Your task is to provide accurate, natural-sounding translations.
+
+ Guidelines:
+ - Preserve meaning and tone
+ - Use natural phrasing in target language
+ - Note any cultural adaptations needed
+ - If source language isn't specified, detect it
+ - Format: "From [language] to [language]:\n\n[translation]"
+ default_model: gemini
+ max_tokens: 2000
+ save_to: false
modules/xmpp-research-bot/bot.py
@@ -47,7 +47,7 @@ Guidelines:
- Aim for 200-500 words unless more detail is requested""",
"default_model": "sonnet",
"max_tokens": 2000,
- "save_to_inbox": True,
+ "save_to": "inbox.org",
}
}
@@ -165,10 +165,12 @@ class ResearchBot(slixmpp.ClientXMPP):
help_lines.append(" opus: or o: - Use Claude Opus 4.5 (most intelligent)")
help_lines.append(" sonnet: or s: - Use Claude Sonnet 4.5 (default, faster)")
if self.gemini_client:
+ help_lines.append(" gemini-pro: or gp: - Use Gemini 3 Pro (advanced reasoning)")
help_lines.append(" gemini: or g: - Use Gemini 3 Flash (fast, cost-effective)")
help_lines.append(" Examples:")
help_lines.append(" /research how does XMPP work?")
help_lines.append(" /research opus: analyze distributed systems complexity")
+ help_lines.append(" /research gp: solve complex reasoning problem")
# Built-in commands
help_lines.append("/help - Show this help message")
@@ -218,6 +220,13 @@ class ResearchBot(slixmpp.ClientXMPP):
model = "gemini"
model_name = "Gemini 3 Flash"
query = query.split(":", 1)[1].strip()
+ elif query.startswith("gemini-pro:") or query.startswith("gp:"):
+ if not self.gemini_client:
+ msg.reply("โ Gemini is not available (client not initialized)").send()
+ return
+ model = "gemini-pro"
+ model_name = "Gemini 3 Pro"
+ query = query.split(":", 1)[1].strip()
# Acknowledge we picked up the work
msg.reply(f"๐ {cmd_config.get('description', 'Processing')} with {model_name}: {query}").send()
@@ -231,10 +240,11 @@ class ResearchBot(slixmpp.ClientXMPP):
max_tokens=cmd_config.get('max_tokens', 2000)
)
- # Save to inbox if configured
- if cmd_config.get('save_to_inbox', True):
- await self.save_to_inbox(query, result, model=model_name)
- msg.reply(f"โ
Complete! Saved to inbox.org\n\nPreview:\n{result[:200]}...").send()
+ # Save to file if configured
+ save_to = cmd_config.get('save_to')
+ if save_to:
+ await self.save_to_file(query, result, filename=save_to, model=model_name)
+ msg.reply(f"โ
Complete! Saved to {save_to}\n\nPreview:\n{result[:200]}...").send()
else:
msg.reply(f"โ
Complete!\n\n{result}").send()
@@ -250,6 +260,7 @@ class ResearchBot(slixmpp.ClientXMPP):
"sonnet": "Sonnet 4.5",
"opus": "Opus 4.5",
"gemini": "Gemini 3 Flash",
+ "gemini-pro": "Gemini 3 Pro",
}
return model_names.get(model, model.title())
@@ -270,8 +281,8 @@ class ResearchBot(slixmpp.ClientXMPP):
if model in ("sonnet", "opus"):
return await self.process_claude(query, model, system_prompt, max_tokens)
- elif model == "gemini":
- return await self.process_gemini(query, system_prompt, max_tokens)
+ elif model in ("gemini", "gemini-pro"):
+ return await self.process_gemini(query, model, system_prompt, max_tokens)
else:
raise ValueError(f"Unknown model: {model}")
@@ -313,32 +324,39 @@ class ResearchBot(slixmpp.ClientXMPP):
return result
- async def process_gemini(self, query: str, system_prompt: str, max_tokens: int) -> str:
+ async def process_gemini(self, query: str, model: str, system_prompt: str, max_tokens: int) -> str:
"""Process query with Gemini"""
if not self.gemini_client:
raise RuntimeError("Gemini client not initialized")
+ # Map model names to Vertex AI model IDs
+ model_ids = {
+ "gemini": "gemini-3-flash-preview",
+ "gemini-pro": "gemini-3-pro-preview",
+ }
+
# Combine system prompt with query
full_prompt = f"{system_prompt}\n\nUser query: {query}"
# Call Gemini API via Vertex AI
response = self.gemini_client.models.generate_content(
- model="gemini-3-flash-preview",
+ model=model_ids[model],
contents=full_prompt,
config={
"max_output_tokens": max_tokens,
"temperature": 1.0,
+ "thinking_level": "HIGH", # Use high thinking level for reasoning
}
)
result = response.text
- log.info("Gemini response generated successfully")
+ log.info(f"Gemini ({model_ids[model]}) response generated successfully")
return result
- async def save_to_inbox(self, query: str, result: str, model: str = "Sonnet 4.5"):
- """Save research result to inbox.org"""
+ async def save_to_file(self, query: str, result: str, filename: str, model: str = "Sonnet 4.5"):
+ """Save research result to org file"""
timestamp = datetime.now().strftime("%Y-%m-%d %a %H:%M")
entry = f"""* TODO Review research: {query}
@@ -357,12 +375,20 @@ class ResearchBot(slixmpp.ClientXMPP):
"""
- # Append to inbox file
- self.inbox_path.parent.mkdir(parents=True, exist_ok=True)
- with open(self.inbox_path, "a", encoding="utf-8") as f:
+ # Determine full path
+ if filename.startswith("/"):
+ # Absolute path
+ file_path = Path(filename)
+ else:
+ # Relative to inbox directory
+ file_path = self.inbox_path.parent / filename
+
+ # Append to file
+ file_path.parent.mkdir(parents=True, exist_ok=True)
+ with open(file_path, "a", encoding="utf-8") as f:
f.write(entry)
- log.info(f"Saved to {self.inbox_path}")
+ log.info(f"Saved to {file_path}")
async def main():
modules/xmpp-research-bot/commands.example.yaml
@@ -22,7 +22,7 @@ commands:
- Aim for 200-500 words unless more detail is requested
default_model: sonnet
max_tokens: 2000
- save_to_inbox: true
+ save_to: inbox.org # or false/null to not save, or custom filename like "research.org"
summarize:
description: "Summarize long text or articles"
@@ -39,7 +39,7 @@ commands:
- Use markdown formatting
default_model: sonnet
max_tokens: 1000
- save_to_inbox: true
+ save_to: inbox.org
analyze:
description: "Deep analysis of complex topics"
@@ -55,9 +55,9 @@ commands:
- Highlight trade-offs and implications
- Use structured markdown with headings
- Aim for comprehensive analysis (500-1000 words)
- default_model: opus # Use more powerful model for analysis
+ default_model: gemini-pro # Use Gemini 3 Pro for deep reasoning
max_tokens: 3000
- save_to_inbox: true
+ save_to: inbox.org
eli5:
description: "Explain like I'm 5 - simple explanations"
@@ -75,7 +75,7 @@ commands:
- Use markdown for readability
default_model: sonnet
max_tokens: 1500
- save_to_inbox: false # Don't save to inbox, just reply
+ save_to: false # Don't save to file, just reply
translate:
description: "Translate text between languages"
@@ -92,7 +92,7 @@ commands:
- Format: "From [language] to [language]:\n\n[translation]"
default_model: gemini # Fast and cost-effective for translation
max_tokens: 2000
- save_to_inbox: false
+ save_to: false
brainstorm:
description: "Generate creative ideas and solutions"
@@ -110,4 +110,4 @@ commands:
- Encourage exploration
default_model: opus # More creative with opus
max_tokens: 2000
- save_to_inbox: true
+ save_to: brainstorm.org # Save to separate file
modules/xmpp-research-bot/default.nix
@@ -13,7 +13,7 @@ let
anthropic
google-auth
pyyaml
- google-generativeai
+ google-genai
]
);
systems/aomi/extra.nix
@@ -125,6 +125,7 @@
vertexProjectId = "itpc-gcp-pnd-pe-eng-claude";
vertexRegion = "us-east5";
inboxPath = "/home/vincent/desktop/org/inbox.org";
+ commandsPath = "/home/vincent/.config/xmpp-research-bot/commands.yaml";
user = "vincent";
group = "users";
};