apexbot 1.0.5 → 1.0.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -12,26 +12,34 @@ const toolExecutor_1 = require("./toolExecutor");
12
12
  class AgentManager {
13
13
  config = null;
14
14
  googleClient = null;
15
- defaultSystemPrompt = `You are ApexBot, a helpful AI assistant running locally via Ollama. You are 100% free, private, and self-hosted.
15
+ defaultSystemPrompt = `You are ApexBot, an autonomous AI assistant like Claude Code. You can execute real actions on the user's computer.
16
16
 
17
- Your goal is to act as a fully autonomous agent, not just a chatbot. Follow these principles:
17
+ ## CORE PRINCIPLES
18
+ 1. **ACT, DON'T EXPLAIN** - When user asks for something, DO IT using tools. Don't explain how to do it.
19
+ 2. **BE AUTONOMOUS** - Make decisions and execute actions automatically
20
+ 3. **BE HELPFUL** - Provide direct answers and results, not tutorials
18
21
 
19
- 1. **EXPLORE:** Analyze code and context thoroughly before responding.
20
- 2. **PLAN:** Outline a clear plan before implementing changes.
21
- 3. **ACT:** Provide complete, working code without placeholders like "// ... rest of code".
22
- 4. **VERIFY:** Test your suggestions mentally and point out edge cases.
22
+ ## CAPABILITIES
23
+ - Execute shell commands
24
+ - Read/write/edit files
25
+ - Get weather forecasts
26
+ - Set reminders and timers
27
+ - Control Spotify playback
28
+ - Manage Obsidian notes
29
+ - Search the web
30
+ - Do math calculations
31
+ - Get system information
23
32
 
24
- CODING STANDARDS:
25
- - TypeScript / Node.js with strict typing
26
- - Modular, clean, modern ES6+ syntax
27
- - Explicit error handling
28
- - Safety first for financial/crypto logic (arbitrage, Kelly criterion)
33
+ ## RESPONSE STYLE
34
+ - Be concise and direct
35
+ - Show results, not code tutorials
36
+ - Use natural language to explain results
37
+ - If something fails, explain why simply
29
38
 
30
- INTERACTION STYLE:
31
- - Be direct and actionable
32
- - Proactively identify issues and offer fixes
33
- - Keep responses concise but complete
34
- - Start with context analysis when working with code
39
+ ## LANGUAGE
40
+ - Respond in the same language as the user
41
+ - If user writes in Polish, respond in Polish
42
+ - If user writes in English, respond in English
35
43
 
36
44
  You are running locally on the user's machine. No data leaves their computer. You are free, private, and open-source.`;
37
45
  constructor(config) {
@@ -103,12 +111,18 @@ You are running locally on the user's machine. No data leaves their computer. Yo
103
111
  if (this.config.enableTools) {
104
112
  const toolCalls = (0, toolExecutor_1.parseToolCalls)(response.text);
105
113
  if (toolCalls.length > 0) {
106
- console.log(`[Agent] Found ${toolCalls.length} tool calls`);
114
+ console.log(`[Agent] Found ${toolCalls.length} tool calls:`, toolCalls.map(t => t.name));
107
115
  // Build tool context
108
- const context = (0, toolExecutor_1.buildToolContext)(session.id, message.userId || 'unknown', message.channel, { workspaceDir: process.cwd() });
116
+ const context = (0, toolExecutor_1.buildToolContext)(session.id, message.userId || message.from || 'unknown', message.channel, { workspaceDir: process.cwd() });
109
117
  // Execute tools
110
118
  const toolResults = await (0, toolExecutor_1.executeToolCalls)(toolCalls, context);
111
119
  response.toolCalls = toolResults;
120
+ // Log results
121
+ for (const { call, result } of toolResults) {
122
+ console.log(`[Agent] Tool ${call.name}: ${result.success ? 'SUCCESS' : 'FAILED'}`);
123
+ if (!result.success)
124
+ console.log(`[Agent] Error: ${result.error}`);
125
+ }
112
126
  // Format results and continue conversation
113
127
  const resultsText = (0, toolExecutor_1.formatToolResults)(toolResults);
114
128
  if (resultsText) {
@@ -116,7 +130,7 @@ You are running locally on the user's machine. No data leaves their computer. Yo
116
130
  const followUpHistory = [
117
131
  ...history,
118
132
  { role: 'assistant', content: response.text, timestamp: Date.now() },
119
- { role: 'user', content: `Tool results:\n${resultsText}\n\nPlease continue based on these results.`, timestamp: Date.now() },
133
+ { role: 'user', content: `[TOOL EXECUTION COMPLETE]\n\nResults:\n${resultsText}\n\nNow provide a natural language response to the user summarizing these results. Be concise. Respond in the same language as the user's original message.`, timestamp: Date.now() },
120
134
  ];
121
135
  // Get follow-up response
122
136
  let followUp;
@@ -127,11 +141,21 @@ You are running locally on the user's machine. No data leaves their computer. Yo
127
141
  case 'google':
128
142
  followUp = await this.processWithGemini(followUpHistory);
129
143
  break;
144
+ case 'anthropic':
145
+ followUp = await this.processWithClaude(followUpHistory);
146
+ break;
147
+ case 'openai':
148
+ followUp = await this.processWithOpenAI(followUpHistory);
149
+ break;
150
+ case 'kimi':
151
+ followUp = await this.processWithKimi(followUpHistory);
152
+ break;
130
153
  default:
131
- followUp = { text: resultsText };
154
+ // Fallback: return formatted results directly
155
+ followUp = { text: this.formatResultsForUser(toolResults) };
132
156
  }
133
- // Combine responses
134
- response.text = followUp.text;
157
+ // Use follow-up response (or fallback to formatted results)
158
+ response.text = followUp.text || this.formatResultsForUser(toolResults);
135
159
  }
136
160
  }
137
161
  }
@@ -149,6 +173,65 @@ You are running locally on the user's machine. No data leaves their computer. Yo
149
173
  return { text: `Error: ${errorMsg}` };
150
174
  }
151
175
  }
176
+ /**
177
+ * Format tool results for direct user display (fallback when AI can't summarize)
178
+ */
179
+ formatResultsForUser(toolResults) {
180
+ const parts = [];
181
+ for (const { call, result } of toolResults) {
182
+ if (result.success) {
183
+ const data = result.data;
184
+ // Format based on tool type
185
+ if (call.name === 'weather' && data) {
186
+ parts.push(`Weather in ${data.location}: ${data.current?.temperature}°C, ${data.current?.condition}`);
187
+ }
188
+ else if (call.name === 'datetime' && data) {
189
+ parts.push(`Current time: ${data.formatted || data.time}`);
190
+ }
191
+ else if (call.name === 'math' && data) {
192
+ parts.push(`Result: ${data.result}`);
193
+ }
194
+ else if (call.name === 'system_info' && data) {
195
+ if (data.memory) {
196
+ parts.push(`RAM: ${data.memory.used} / ${data.memory.total} (${data.memory.usage} used)`);
197
+ }
198
+ if (data.cpu) {
199
+ parts.push(`CPU: ${data.cpu.model} (${data.cpu.cores} cores)`);
200
+ }
201
+ }
202
+ else if (call.name.startsWith('reminder') && data) {
203
+ parts.push(data.message || `Reminder ${data.action || 'set'}`);
204
+ }
205
+ else if (call.name.startsWith('spotify') && data) {
206
+ if (data.track)
207
+ parts.push(`Now playing: ${data.track} by ${data.artist}`);
208
+ else if (data.message)
209
+ parts.push(data.message);
210
+ else if (data.action)
211
+ parts.push(`Spotify: ${data.action}`);
212
+ }
213
+ else if (data) {
214
+ // Generic formatting
215
+ if (typeof data === 'string') {
216
+ parts.push(data);
217
+ }
218
+ else if (data.message) {
219
+ parts.push(data.message);
220
+ }
221
+ else if (data.result) {
222
+ parts.push(String(data.result));
223
+ }
224
+ else if (data.output) {
225
+ parts.push(data.output);
226
+ }
227
+ }
228
+ }
229
+ else {
230
+ parts.push(`Error (${call.name}): ${result.error}`);
231
+ }
232
+ }
233
+ return parts.join('\n') || 'Done.';
234
+ }
152
235
  async processWithKimi(history) {
153
236
  // Generic Kimi 2.5 integration wrapper. This implementation is intentionally
154
237
  // generic: it will POST to a user-provided `apiUrl` (in config or env) and
@@ -114,20 +114,49 @@ function getToolsSystemPrompt() {
114
114
  }
115
115
  const toolDescriptions = tools.map(t => {
116
116
  const params = t.parameters.map(p => ` - ${p.name} (${p.type}${p.required ? ', required' : ''}): ${p.description}`).join('\n');
117
- return `**${t.name}**: ${t.description}\nParameters:\n${params}`;
118
- }).join('\n\n');
117
+ return `- **${t.name}**: ${t.description}`;
118
+ }).join('\n');
119
119
  return `
120
- You have access to the following tools. To use a tool, include a JSON block in your response:
120
+ ## TOOLS - IMPORTANT!
121
+
122
+ You have tools to interact with the real world. **USE THEM AUTOMATICALLY** when the user asks for something that requires them.
123
+
124
+ **HOW TO USE A TOOL:**
125
+ Include this EXACT format in your response (the system will execute it automatically):
121
126
 
122
127
  \`\`\`json
123
- {"tool": "tool_name", "args": {"param1": "value1"}}
128
+ {"tool": "tool_name", "args": {"param": "value"}}
124
129
  \`\`\`
125
130
 
126
- Available tools:
131
+ **WHEN TO USE TOOLS (do it automatically, don't ask!):**
132
+ - "what's the weather" → use \`weather\` tool
133
+ - "set a reminder" → use \`reminder_set\` tool
134
+ - "what time is it" → use \`datetime\` tool
135
+ - "how much RAM" / system info → use \`system_info\` tool
136
+ - "calculate X" / math → use \`math\` tool
137
+ - "read file X" → use \`read_file\` tool
138
+ - "run command X" → use \`shell\` tool
139
+ - "search for X" → use \`web_search\` tool
140
+ - "play music" / spotify → use \`spotify_*\` tools
141
+ - "create playlist" → use \`spotify_create_playlist\` tool
142
+ - "my notes" / obsidian → use \`obsidian_*\` tools
127
143
 
144
+ **AVAILABLE TOOLS:**
128
145
  ${toolDescriptions}
129
146
 
130
- After I execute the tool, I'll show you the result so you can incorporate it into your response.
147
+ **RULES:**
148
+ 1. ALWAYS use a tool when the user's request matches a tool's capability
149
+ 2. Do NOT explain how to use tools - just USE them
150
+ 3. Do NOT show code examples - execute the tool directly
151
+ 4. After tool execution, summarize the result in natural language
152
+ 5. If a tool fails, explain why and suggest alternatives
153
+
154
+ **EXAMPLE:**
155
+ User: "What's the weather in Tokyo?"
156
+ Your response should include:
157
+ \`\`\`json
158
+ {"tool": "weather", "args": {"location": "Tokyo"}}
159
+ \`\`\`
131
160
  `;
132
161
  }
133
162
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "apexbot",
3
- "version": "1.0.5",
3
+ "version": "1.0.6",
4
4
  "description": "ApexBot - Your free, private AI assistant. 100% free with Ollama (local AI). Multi-channel: Telegram, Discord, WebChat. Tools & Skills system with Spotify, Obsidian, and more!",
5
5
  "main": "dist/index.js",
6
6
  "bin": {