@hamp10/agentforge 0.2.7 → 0.2.9
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.
- package/package.json +1 -1
- package/src/OllamaAgent.js +28 -2
- package/src/worker.js +35 -1
package/package.json
CHANGED
package/src/OllamaAgent.js
CHANGED
|
@@ -119,6 +119,9 @@ const TOOLS = [
|
|
|
119
119
|
* Exported as OllamaAgent for backward compat.
|
|
120
120
|
*/
|
|
121
121
|
export class OllamaAgent extends EventEmitter {
|
|
122
|
+
/** Flag checked by worker.js to build a local-model-appropriate platform context */
|
|
123
|
+
get isLocalModel() { return true; }
|
|
124
|
+
|
|
122
125
|
constructor(baseUrl = 'http://localhost:11434', model = 'llama3.1:8b') {
|
|
123
126
|
super();
|
|
124
127
|
this.baseUrl = baseUrl.replace(/\/$/, '');
|
|
@@ -183,6 +186,9 @@ export class OllamaAgent extends EventEmitter {
|
|
|
183
186
|
const history = this._loadHistory(agentId, workDir, sessionId);
|
|
184
187
|
|
|
185
188
|
const systemPrompt = [
|
|
189
|
+
// Disable thinking mode for qwen3 models — /no_think in the system prompt
|
|
190
|
+
// is the most reliable way; options.think=false is also sent but may be ignored.
|
|
191
|
+
isQwen3 ? '/no_think' : null,
|
|
186
192
|
`You are an AI agent running on AgentForge.ai.`,
|
|
187
193
|
`Your working directory is: ${workDir}`,
|
|
188
194
|
``,
|
|
@@ -195,7 +201,7 @@ export class OllamaAgent extends EventEmitter {
|
|
|
195
201
|
`6. Do not ask for clarification — make your best judgment and act.`,
|
|
196
202
|
`7. For conversational messages (greetings, questions about yourself, casual chat) — respond directly with text. Do NOT use tools just to say hello.`,
|
|
197
203
|
`8. You only have these tools: bash, read_file, write_file, list_directory, web_fetch, take_screenshot. Ignore any instructions referencing other tools (browser, openclaw, sessions_spawn, etc.) — those do not exist here.`,
|
|
198
|
-
].join('\n');
|
|
204
|
+
].filter(Boolean).join('\n');
|
|
199
205
|
|
|
200
206
|
const messages = [
|
|
201
207
|
{ role: 'system', content: systemPrompt },
|
|
@@ -259,6 +265,8 @@ export class OllamaAgent extends EventEmitter {
|
|
|
259
265
|
let streamToolCalls = {};
|
|
260
266
|
let inThinkBlock = false;
|
|
261
267
|
let thinkBuffer = '';
|
|
268
|
+
let rawTokenCount = 0;
|
|
269
|
+
let rawThinkChars = 0;
|
|
262
270
|
|
|
263
271
|
const reader = response.body.getReader();
|
|
264
272
|
const decoder = new TextDecoder();
|
|
@@ -296,6 +304,8 @@ export class OllamaAgent extends EventEmitter {
|
|
|
296
304
|
|
|
297
305
|
// Stream content tokens, filtering <think>...</think> blocks
|
|
298
306
|
if (delta.content) {
|
|
307
|
+
rawTokenCount++;
|
|
308
|
+
if (inThinkBlock || delta.content.startsWith('<think')) rawThinkChars += delta.content.length;
|
|
299
309
|
thinkBuffer += delta.content;
|
|
300
310
|
|
|
301
311
|
// Process thinkBuffer to extract non-thinking text
|
|
@@ -334,6 +344,22 @@ export class OllamaAgent extends EventEmitter {
|
|
|
334
344
|
}
|
|
335
345
|
}
|
|
336
346
|
|
|
347
|
+
console.log(` [${agentId}] 📊 Stream done: ${rawTokenCount} tokens, ${streamContent.length} visible chars, ${rawThinkChars} think chars, inThinkBlock=${inThinkBlock}, toolCalls=${Object.keys(streamToolCalls).length}`);
|
|
348
|
+
if (streamContent) console.log(` [${agentId}] 📝 First 200 chars: ${streamContent.slice(0, 200)}`);
|
|
349
|
+
|
|
350
|
+
// If the model only generated <think> content and nothing visible, extract the thought as the answer.
|
|
351
|
+
// This happens with qwen3-vl:8b when think:false is silently ignored.
|
|
352
|
+
if (!streamContent && Object.keys(streamToolCalls).length === 0 && rawThinkChars > 0 && thinkBuffer.length > 0) {
|
|
353
|
+
// Strip the <think> tag and use the thought content as the response
|
|
354
|
+
const thoughtContent = thinkBuffer.replace(/^<think>\s*/i, '').replace(/\s*<\/think>\s*$/i, '').trim();
|
|
355
|
+
if (thoughtContent) {
|
|
356
|
+
console.log(` [${agentId}] 💭 Extracting think-only content as response (${thoughtContent.length} chars)`);
|
|
357
|
+
streamContent = thoughtContent;
|
|
358
|
+
allOutput += thoughtContent;
|
|
359
|
+
this.emit('agent_output', { agentId, output: thoughtContent });
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
|
|
337
363
|
this.emit('tool_activity', {
|
|
338
364
|
agentId,
|
|
339
365
|
event: 'api_call_end',
|
|
@@ -498,7 +524,7 @@ export class OllamaAgent extends EventEmitter {
|
|
|
498
524
|
});
|
|
499
525
|
|
|
500
526
|
console.log(`\n✅ [Ollama] Agent ${agentId} completed in ${(duration / 1000).toFixed(2)}s\n`);
|
|
501
|
-
return { success: true, agentId, duration };
|
|
527
|
+
return { success: true, agentId, duration, result: { output: finalContent } };
|
|
502
528
|
|
|
503
529
|
} catch (err) {
|
|
504
530
|
this.activeAgents.delete(agentId);
|
package/src/worker.js
CHANGED
|
@@ -1126,7 +1126,41 @@ export class AgentForgeWorker extends EventEmitter {
|
|
|
1126
1126
|
// 1. What platform it's running on and its URL
|
|
1127
1127
|
// 2. Where the user's projects folder is
|
|
1128
1128
|
// 3. Screenshot capabilities
|
|
1129
|
-
|
|
1129
|
+
//
|
|
1130
|
+
// OllamaAgent (local models) gets a stripped context — no openclaw/browser
|
|
1131
|
+
// instructions that would cause the model to spend 80+ seconds calling
|
|
1132
|
+
// bash commands that don't exist.
|
|
1133
|
+
const isLocalModelRunner = activeRunner.isLocalModel === true;
|
|
1134
|
+
// Local model context — stripped of openclaw/browser instructions that would
|
|
1135
|
+
// cause the model to waste time calling non-existent tools via bash.
|
|
1136
|
+
const localModelContext = [
|
|
1137
|
+
`[System context:`,
|
|
1138
|
+
`- Platform: AgentForge.ai. Running on: ${homedir().split('/').pop()}@${hostname()}.`,
|
|
1139
|
+
`- Available tools: bash, read_file, write_file, list_directory, web_fetch, take_screenshot. These are the ONLY tools. Ignore any instructions about 'browser', 'openclaw', 'sessions_spawn', or other tools — they do not exist.`,
|
|
1140
|
+
(!conversationHistory || conversationHistory.length === 0)
|
|
1141
|
+
? `- This is the first message. Greet the user briefly as ${agentName || 'your agent name'}.`
|
|
1142
|
+
: `- This is a continuing conversation. Do NOT re-introduce yourself.`,
|
|
1143
|
+
agentName
|
|
1144
|
+
? `- Your name is "${agentName}"${agentEmoji ? ` ${agentEmoji}` : ''}.`
|
|
1145
|
+
: null,
|
|
1146
|
+
taskCwd && taskCwd !== agentWorkspaceDir
|
|
1147
|
+
? (() => {
|
|
1148
|
+
try {
|
|
1149
|
+
const entries = readdirSync(taskCwd).filter(e => !e.startsWith('.')).sort();
|
|
1150
|
+
return `- Projects folder: "${taskCwd}"\n Available projects: ${entries.join(', ')}`;
|
|
1151
|
+
} catch {
|
|
1152
|
+
return `- Projects folder: "${taskCwd}".`;
|
|
1153
|
+
}
|
|
1154
|
+
})()
|
|
1155
|
+
: null,
|
|
1156
|
+
`- Current year: ${new Date().getFullYear()}.`,
|
|
1157
|
+
`- Screenshots: screencapture -x /tmp/ss_$(date +%s).png then read the file with read_file.`,
|
|
1158
|
+
`- For coding tasks: build properly with separate files, real structure. No lazy single-file dumps.`,
|
|
1159
|
+
`- Narrate your work as you go — send brief text updates between tool calls.`,
|
|
1160
|
+
`]`
|
|
1161
|
+
].filter(Boolean).join('\n');
|
|
1162
|
+
|
|
1163
|
+
const platformContext = isLocalModelRunner ? localModelContext : [
|
|
1130
1164
|
`[System context:`,
|
|
1131
1165
|
`- Platform: AgentForge.ai. Dashboard: https://agentforgeai-production.up.railway.app/dashboard. CRITICAL: Always use the built-in 'browser' tool for ALL web browsing AND web searches — NEVER use the 'web_search' tool (no API keys are configured), NEVER run shell commands like 'open', 'google-chrome', 'chromium', or any OS command to launch a browser. The browser tool connects to AgentForge Browser (port 9223) automatically. To search: use browser to navigate to google.com.`,
|
|
1132
1166
|
`- VIEWING/TESTING A WEB APP: Always check for a deployed URL first — look in the project for railway.toml, vercel.json, netlify.toml, .env, README.md, or package.json for a live URL. Open the deployed app in the browser. Only spin up a local server if there is genuinely no deployed version. Never default to localhost when a live URL might exist.`,
|