@agenticmail/enterprise 0.5.611 → 0.5.613

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.
Files changed (43) hide show
  1. package/CHANGELOG.md +38 -0
  2. package/dist/{agent-heartbeat-PHLWJ3HO.js → agent-heartbeat-HFDBZWMO.js} +1 -1
  3. package/dist/{agent-tools-KRMDJOCK.js → agent-tools-5LLIXV6A.js} +17 -6
  4. package/dist/{chunk-NMMTMHTA.js → chunk-GC77MDKW.js} +37 -31
  5. package/dist/{chunk-BUKTZ35L.js → chunk-H3JXMBTG.js} +3 -6
  6. package/dist/{chunk-I2T4HESC.js → chunk-IXAWHXMY.js} +16 -16
  7. package/dist/{chunk-5EMB2S53.js → chunk-MVD2DMAY.js} +2 -2
  8. package/dist/{chunk-TBBVEXBH.js → chunk-QVZIW5HI.js} +14 -0
  9. package/dist/{chunk-REAJCMQE.js → chunk-T26AVIAQ.js} +3 -6
  10. package/dist/chunk-UETRFOSR.js +80 -0
  11. package/dist/{chunk-KQ5EU4IA.js → chunk-VWIDJRD4.js} +49 -32
  12. package/dist/{cli-agent-V7K6HZAG.js → cli-agent-AMA2R4PG.js} +18 -12
  13. package/dist/{cli-serve-T3W5RDO4.js → cli-serve-4NLB4RK2.js} +2 -2
  14. package/dist/cli.js +3 -3
  15. package/dist/{deployer-BKBISKKF.js → deployer-M4YHMATN.js} +2 -1
  16. package/dist/index.js +12 -11
  17. package/dist/meetings-SPK24WE7.js +1 -1
  18. package/dist/{routes-VX5CXX4J.js → routes-5PUCWC4N.js} +4 -3
  19. package/dist/{runtime-RMLNHLAT.js → runtime-GML2LXIN.js} +2 -1
  20. package/dist/{server-64K32C5T.js → server-R5SICPBI.js} +5 -4
  21. package/dist/{setup-7AQLYQBS.js → setup-SLLV37YT.js} +1 -1
  22. package/dist/{telegram-NG7PNNIN.js → telegram-W765VRI5.js} +1 -1
  23. package/dist/{whatsapp-RAQUV6ZL.js → whatsapp-TBOB7TDL.js} +1 -1
  24. package/dist/workspace-P5FCSG2D.js +19 -0
  25. package/package.json +1 -1
  26. package/logs/cloudflared-error.log +0 -9
  27. package/logs/cloudflared-error__2026-05-21_00-00-00.log +0 -59
  28. package/logs/cloudflared-error__2026-05-22_00-00-00.log +0 -739
  29. package/logs/cloudflared-error__2026-05-23_00-00-00.log +0 -1432
  30. package/logs/cloudflared-error__2026-05-24_00-00-00.log +0 -1117
  31. package/logs/cloudflared-error__2026-05-25_00-00-00.log +0 -410
  32. package/logs/cloudflared-out.log +0 -0
  33. package/logs/enterprise-error.log +0 -11
  34. package/logs/enterprise-out.log +0 -225
  35. package/logs/fola-error.log +0 -2
  36. package/logs/fola-out.log +0 -0
  37. package/logs/john-error.log +0 -8
  38. package/logs/john-error__2026-03-06_00-00-00.log +0 -10
  39. package/logs/john-error__2026-03-07_00-00-00.log +0 -25
  40. package/logs/john-out.log +0 -0
  41. package/test-gemma4.mjs +0 -703
  42. /package/dist/{chunk-CC4BHZHO.js → chunk-GAOEALTJ.js} +0 -0
  43. /package/dist/{integrations-4JDIOHQU.js → integrations-UWDEQ7Z4.js} +0 -0
package/test-gemma4.mjs DELETED
@@ -1,703 +0,0 @@
1
- #!/usr/bin/env node
2
- /**
3
- * Gemma 4 26B Interactive Test CLI
4
- *
5
- * Usage: node test-gemma4.mjs [mode]
6
- *
7
- * Modes:
8
- * chat — Free-form conversation
9
- * tools — Tool calling tests (gmail, calendar, tasks)
10
- * code — Code generation & review
11
- * email — Simulate inbound email agent session
12
- * bench — Run automated benchmark suite
13
- * reasoning — Multi-step reasoning & planning tasks
14
- *
15
- * No args = interactive mode picker
16
- */
17
-
18
- import readline from 'readline';
19
-
20
- const OLLAMA_URL = process.env.OLLAMA_URL || 'http://localhost:11434';
21
- const MODEL = process.env.GEMMA_MODEL || 'gemma4:26b';
22
-
23
- // ─── Colors ─────────────────────────────────────────────
24
-
25
- const c = {
26
- reset: '\x1b[0m',
27
- bold: '\x1b[1m',
28
- dim: '\x1b[2m',
29
- green: '\x1b[32m',
30
- cyan: '\x1b[36m',
31
- yellow: '\x1b[33m',
32
- magenta: '\x1b[35m',
33
- red: '\x1b[31m',
34
- blue: '\x1b[34m',
35
- gray: '\x1b[90m',
36
- };
37
-
38
- function log(color, label, msg) {
39
- console.log(`${color}${label}${c.reset} ${msg}`);
40
- }
41
-
42
- // ─── Ollama API ─────────────────────────────────────────
43
-
44
- async function ollamaChat(messages, tools, stream = true) {
45
- var body = { model: MODEL, messages, stream };
46
- if (tools && tools.length > 0) body.tools = tools;
47
-
48
- var start = Date.now();
49
- var resp = await fetch(OLLAMA_URL + '/api/chat', {
50
- method: 'POST',
51
- headers: { 'Content-Type': 'application/json' },
52
- body: JSON.stringify(body),
53
- });
54
-
55
- if (!resp.ok) {
56
- var errText = await resp.text();
57
- throw new Error(`Ollama ${resp.status}: ${errText}`);
58
- }
59
-
60
- if (!stream) {
61
- var data = await resp.json();
62
- var elapsed = Date.now() - start;
63
- return {
64
- content: data.message?.content || '',
65
- thinking: data.message?.thinking || '',
66
- toolCalls: data.message?.tool_calls || [],
67
- role: data.message?.role || 'assistant',
68
- inputTokens: data.prompt_eval_count || 0,
69
- outputTokens: data.eval_count || 0,
70
- elapsed,
71
- tokPerSec: data.eval_count && data.eval_duration
72
- ? (data.eval_count / (data.eval_duration / 1e9)).toFixed(1)
73
- : '?',
74
- };
75
- }
76
-
77
- // Streaming
78
- var reader = resp.body.getReader();
79
- var decoder = new TextDecoder();
80
- var buffer = '';
81
- var content = '';
82
- var thinking = '';
83
- var toolCalls = [];
84
- var inputTokens = 0, outputTokens = 0;
85
- var evalDuration = 0;
86
- var firstToken = true;
87
-
88
- while (true) {
89
- var { done, value } = await reader.read();
90
- if (done) break;
91
- buffer += decoder.decode(value, { stream: true });
92
-
93
- var lines = buffer.split('\n');
94
- buffer = lines.pop() || '';
95
-
96
- for (var line of lines) {
97
- var trimmed = line.trim();
98
- if (!trimmed) continue;
99
- var chunk;
100
- try { chunk = JSON.parse(trimmed); } catch { continue; }
101
-
102
- if (chunk.message?.thinking) {
103
- if (firstToken) { process.stdout.write(c.dim + '💭 '); firstToken = false; }
104
- process.stdout.write(c.dim + chunk.message.thinking + c.reset);
105
- thinking += chunk.message.thinking;
106
- }
107
- if (chunk.message?.content) {
108
- if (thinking && firstToken === false && !content) {
109
- process.stdout.write(c.reset + '\n');
110
- }
111
- process.stdout.write(chunk.message.content);
112
- content += chunk.message.content;
113
- }
114
- if (chunk.message?.tool_calls) {
115
- toolCalls.push(...chunk.message.tool_calls);
116
- }
117
- if (chunk.done) {
118
- inputTokens = chunk.prompt_eval_count || 0;
119
- outputTokens = chunk.eval_count || 0;
120
- evalDuration = chunk.eval_duration || 0;
121
- }
122
- }
123
- }
124
-
125
- var elapsed = Date.now() - start;
126
- if (content || thinking) process.stdout.write('\n');
127
-
128
- return {
129
- content, thinking, toolCalls,
130
- role: 'assistant',
131
- inputTokens, outputTokens, elapsed,
132
- tokPerSec: outputTokens && evalDuration
133
- ? (outputTokens / (evalDuration / 1e9)).toFixed(1)
134
- : '?',
135
- };
136
- }
137
-
138
- function printStats(result) {
139
- console.log(
140
- `${c.gray}── ${result.inputTokens} in / ${result.outputTokens} out · ` +
141
- `${result.tokPerSec} tok/s · ${(result.elapsed / 1000).toFixed(1)}s${c.reset}`
142
- );
143
- }
144
-
145
- // ─── Tool Definitions ───────────────────────────────────
146
-
147
- var AGENT_TOOLS = [
148
- {
149
- type: 'function',
150
- function: {
151
- name: 'gmail_reply',
152
- description: 'Reply to an email message in a thread',
153
- parameters: {
154
- type: 'object',
155
- properties: {
156
- messageId: { type: 'string', description: 'The Gmail message ID to reply to' },
157
- body: { type: 'string', description: 'The reply body text' },
158
- },
159
- required: ['messageId', 'body'],
160
- },
161
- },
162
- },
163
- {
164
- type: 'function',
165
- function: {
166
- name: 'gmail_forward',
167
- description: 'Forward an email message to another recipient',
168
- parameters: {
169
- type: 'object',
170
- properties: {
171
- messageId: { type: 'string', description: 'The Gmail message ID to forward' },
172
- to: { type: 'string', description: 'Recipient email address' },
173
- body: { type: 'string', description: 'Optional note to include' },
174
- },
175
- required: ['messageId', 'to'],
176
- },
177
- },
178
- },
179
- {
180
- type: 'function',
181
- function: {
182
- name: 'gmail_search',
183
- description: 'Search for emails matching a query',
184
- parameters: {
185
- type: 'object',
186
- properties: {
187
- query: { type: 'string', description: 'Gmail search query (e.g. "from:john subject:invoice")' },
188
- maxResults: { type: 'number', description: 'Max results to return (default 10)' },
189
- },
190
- required: ['query'],
191
- },
192
- },
193
- },
194
- {
195
- type: 'function',
196
- function: {
197
- name: 'gmail_send',
198
- description: 'Send a new email',
199
- parameters: {
200
- type: 'object',
201
- properties: {
202
- to: { type: 'string', description: 'Recipient email address' },
203
- subject: { type: 'string', description: 'Email subject line' },
204
- body: { type: 'string', description: 'Email body text' },
205
- cc: { type: 'string', description: 'CC recipients (comma-separated)' },
206
- },
207
- required: ['to', 'subject', 'body'],
208
- },
209
- },
210
- },
211
- {
212
- type: 'function',
213
- function: {
214
- name: 'google_tasks_create',
215
- description: 'Create a new task in Google Tasks',
216
- parameters: {
217
- type: 'object',
218
- properties: {
219
- title: { type: 'string', description: 'Task title' },
220
- notes: { type: 'string', description: 'Task notes/description' },
221
- due: { type: 'string', description: 'Due date in ISO format' },
222
- },
223
- required: ['title'],
224
- },
225
- },
226
- },
227
- {
228
- type: 'function',
229
- function: {
230
- name: 'google_calendar_create',
231
- description: 'Create a calendar event',
232
- parameters: {
233
- type: 'object',
234
- properties: {
235
- title: { type: 'string', description: 'Event title' },
236
- start: { type: 'string', description: 'Start time in ISO format' },
237
- end: { type: 'string', description: 'End time in ISO format' },
238
- attendees: { type: 'string', description: 'Comma-separated attendee emails' },
239
- description: { type: 'string', description: 'Event description' },
240
- },
241
- required: ['title', 'start', 'end'],
242
- },
243
- },
244
- },
245
- {
246
- type: 'function',
247
- function: {
248
- name: 'memory',
249
- description: 'Store or retrieve information from agent memory',
250
- parameters: {
251
- type: 'object',
252
- properties: {
253
- action: { type: 'string', enum: ['store', 'search'], description: 'Whether to store or search memory' },
254
- key: { type: 'string', description: 'Memory key (for store)' },
255
- value: { type: 'string', description: 'Memory value (for store)' },
256
- query: { type: 'string', description: 'Search query (for search)' },
257
- },
258
- required: ['action'],
259
- },
260
- },
261
- },
262
- ];
263
-
264
- // ─── Modes ──────────────────────────────────────────────
265
-
266
- async function modeChat(rl) {
267
- console.log(`\n${c.cyan}${c.bold}💬 Chat Mode${c.reset} — free conversation with Gemma 4 26B`);
268
- console.log(`${c.gray}Type your message. "back" to return to menu.${c.reset}\n`);
269
-
270
- var messages = [];
271
-
272
- while (true) {
273
- var input = await ask(rl, `${c.green}you>${c.reset} `);
274
- if (input === 'back' || input === 'quit' || input === 'exit') return;
275
- if (!input.trim()) continue;
276
-
277
- messages.push({ role: 'user', content: input });
278
-
279
- process.stdout.write(`${c.cyan}gemma>${c.reset} `);
280
- var result = await ollamaChat(messages);
281
- printStats(result);
282
-
283
- messages.push({ role: 'assistant', content: result.content });
284
- }
285
- }
286
-
287
- async function modeTools(rl) {
288
- console.log(`\n${c.magenta}${c.bold}🔧 Tool Calling Mode${c.reset} — test function calling with agent tools`);
289
- console.log(`${c.gray}Available tools: gmail_reply, gmail_forward, gmail_search, gmail_send,`);
290
- console.log(`google_tasks_create, google_calendar_create, memory`);
291
- console.log(`Type natural language requests. "back" to return.${c.reset}\n`);
292
-
293
- var systemMsg = {
294
- role: 'system',
295
- content: `You are Fola, an AI email assistant at AgenticMail. Your email is fola@agenticmail.io.
296
- You have access to Gmail, Google Tasks, Google Calendar, and memory tools.
297
- Today's date is ${new Date().toISOString().split('T')[0]}.
298
- Use the provided tools to accomplish tasks. Always use tools when the user asks you to do something actionable.`,
299
- };
300
- var messages = [systemMsg];
301
-
302
- while (true) {
303
- var input = await ask(rl, `${c.green}you>${c.reset} `);
304
- if (input === 'back' || input === 'quit' || input === 'exit') return;
305
- if (!input.trim()) continue;
306
-
307
- messages.push({ role: 'user', content: input });
308
-
309
- log(c.magenta, 'gemma>', 'thinking...');
310
- var result = await ollamaChat(messages, AGENT_TOOLS, false);
311
-
312
- if (result.toolCalls.length > 0) {
313
- for (var tc of result.toolCalls) {
314
- var fn = tc.function;
315
- console.log(`${c.yellow}${c.bold}🔧 Tool Call: ${fn.name}${c.reset}`);
316
- console.log(`${c.yellow} Args: ${JSON.stringify(fn.arguments, null, 2).replace(/\n/g, '\n ')}${c.reset}`);
317
- }
318
- if (result.content) {
319
- console.log(`${c.cyan} Message: ${result.content}${c.reset}`);
320
- }
321
- messages.push({ role: 'assistant', content: result.content || '', tool_calls: result.toolCalls });
322
-
323
- // Simulate tool results
324
- for (var tc2 of result.toolCalls) {
325
- var simulated = simulateToolResult(tc2.function.name, tc2.function.arguments);
326
- console.log(`${c.gray} ↪ Simulated result: ${JSON.stringify(simulated).slice(0, 120)}${c.reset}`);
327
- messages.push({ role: 'tool', content: JSON.stringify(simulated) });
328
- }
329
-
330
- // Get follow-up response
331
- var followUp = await ollamaChat(messages, AGENT_TOOLS, false);
332
- if (followUp.content) {
333
- console.log(`${c.cyan}gemma>${c.reset} ${followUp.content}`);
334
- }
335
- if (followUp.toolCalls.length > 0) {
336
- for (var tc3 of followUp.toolCalls) {
337
- console.log(`${c.yellow}${c.bold}🔧 Tool Call: ${tc3.function.name}${c.reset}`);
338
- console.log(`${c.yellow} Args: ${JSON.stringify(tc3.function.arguments, null, 2).replace(/\n/g, '\n ')}${c.reset}`);
339
- }
340
- }
341
- messages.push({ role: 'assistant', content: followUp.content || '' });
342
- printStats(followUp);
343
- } else {
344
- console.log(`${c.cyan}gemma>${c.reset} ${result.content}`);
345
- messages.push({ role: 'assistant', content: result.content });
346
- printStats(result);
347
- }
348
- }
349
- }
350
-
351
- async function modeCode(rl) {
352
- console.log(`\n${c.blue}${c.bold}💻 Code Mode${c.reset} — code generation, review, and debugging`);
353
- console.log(`${c.gray}Ask for code, paste snippets for review, describe bugs. "back" to return.${c.reset}\n`);
354
-
355
- var messages = [
356
- { role: 'system', content: 'You are an expert software engineer. Write clean, production-quality code. When reviewing code, be specific about issues and fixes. Use TypeScript/JavaScript by default unless the user specifies otherwise.' },
357
- ];
358
-
359
- while (true) {
360
- var input = await askMultiline(rl, `${c.green}you>${c.reset} `, `${c.gray} ...${c.reset} `);
361
- if (input === 'back' || input === 'quit' || input === 'exit') return;
362
- if (!input.trim()) continue;
363
-
364
- messages.push({ role: 'user', content: input });
365
-
366
- process.stdout.write(`${c.blue}gemma>${c.reset} `);
367
- var result = await ollamaChat(messages);
368
- printStats(result);
369
-
370
- messages.push({ role: 'assistant', content: result.content });
371
- }
372
- }
373
-
374
- async function modeEmail(rl) {
375
- console.log(`\n${c.yellow}${c.bold}📧 Email Agent Simulation${c.reset} — simulate a full email agent session`);
376
- console.log(`${c.gray}Provide inbound email details, watch the agent process it with tools.${c.reset}\n`);
377
-
378
- var from = await ask(rl, `${c.gray}From email: ${c.reset}`) || 'john@example.com';
379
- var subject = await ask(rl, `${c.gray}Subject: ${c.reset}`) || 'Q2 Budget Review Meeting';
380
- var body = await ask(rl, `${c.gray}Body (one line): ${c.reset}`) || 'Hi Fola, can we schedule a meeting to review the Q2 budget? I have availability Thursday afternoon. Also, please forward the latest report to Sarah at sarah@example.com.';
381
-
382
- var emailPrompt = `[Inbound Email]
383
- Message-ID: msg-test-001
384
- From: ${from}
385
- Subject: ${subject}
386
-
387
- ${body}`;
388
-
389
- var systemPrompt = `You are Fola, a Customer Support Lead AI agent at AgenticMail Inc.
390
- Your email: fola@agenticmail.io
391
- Your manager: admin@agenticmail.io
392
- Today: ${new Date().toISOString().split('T')[0]}
393
-
394
- INSTRUCTIONS:
395
- - Process the inbound email and take all appropriate actions
396
- - Reply to the sender if a response is needed
397
- - Create tasks for follow-up items
398
- - Schedule meetings if requested
399
- - Forward emails if asked
400
- - Store important information in memory
401
-
402
- Be professional, helpful, and thorough.`;
403
-
404
- var messages = [
405
- { role: 'system', content: systemPrompt },
406
- { role: 'user', content: emailPrompt },
407
- ];
408
-
409
- console.log(`\n${c.yellow}─── Inbound Email ───${c.reset}`);
410
- console.log(`${c.gray}From: ${from}`);
411
- console.log(`Subject: ${subject}`);
412
- console.log(`Body: ${body}${c.reset}\n`);
413
-
414
- log(c.magenta, '⚙️', 'Processing email...\n');
415
-
416
- // Multi-turn tool loop (up to 5 rounds)
417
- for (var turn = 0; turn < 5; turn++) {
418
- var result = await ollamaChat(messages, AGENT_TOOLS, false);
419
-
420
- if (result.content) {
421
- console.log(`${c.cyan}gemma>${c.reset} ${result.content}`);
422
- }
423
-
424
- if (result.toolCalls.length === 0) {
425
- printStats(result);
426
- break;
427
- }
428
-
429
- for (var tc of result.toolCalls) {
430
- console.log(`${c.yellow}${c.bold}🔧 ${tc.function.name}${c.reset}${c.yellow}(${JSON.stringify(tc.function.arguments)})${c.reset}`);
431
- var simResult = simulateToolResult(tc.function.name, tc.function.arguments);
432
- console.log(`${c.gray} ✅ ${JSON.stringify(simResult).slice(0, 100)}${c.reset}`);
433
- messages.push({ role: 'assistant', content: result.content || '', tool_calls: [tc] });
434
- messages.push({ role: 'tool', content: JSON.stringify(simResult) });
435
- }
436
-
437
- printStats(result);
438
- console.log('');
439
- }
440
-
441
- console.log(`\n${c.yellow}─── Session Complete ───${c.reset}\n`);
442
-
443
- // Return to menu
444
- }
445
-
446
- async function modeReasoning(rl) {
447
- console.log(`\n${c.magenta}${c.bold}🧠 Reasoning Mode${c.reset} — multi-step reasoning and planning`);
448
- console.log(`${c.gray}Test complex reasoning, math, logic, planning. "back" to return.${c.reset}\n`);
449
-
450
- var messages = [
451
- { role: 'system', content: 'You are an expert problem solver. Think step by step. Show your reasoning clearly.' },
452
- ];
453
-
454
- while (true) {
455
- var input = await askMultiline(rl, `${c.green}you>${c.reset} `, `${c.gray} ...${c.reset} `);
456
- if (input === 'back' || input === 'quit' || input === 'exit') return;
457
- if (!input.trim()) continue;
458
-
459
- messages.push({ role: 'user', content: input });
460
-
461
- process.stdout.write(`${c.magenta}gemma>${c.reset} `);
462
- var result = await ollamaChat(messages);
463
- printStats(result);
464
-
465
- messages.push({ role: 'assistant', content: result.content });
466
- }
467
- }
468
-
469
- async function modeBench() {
470
- console.log(`\n${c.red}${c.bold}📊 Benchmark Suite${c.reset} — automated tests across capabilities\n`);
471
-
472
- var tests = [
473
- {
474
- name: 'Tool Selection (single)',
475
- system: 'You are an email assistant with access to tools.',
476
- prompt: 'Search my inbox for emails from Sarah about the project proposal.',
477
- tools: AGENT_TOOLS,
478
- check: (r) => r.toolCalls.length > 0 && r.toolCalls[0].function.name === 'gmail_search',
479
- },
480
- {
481
- name: 'Tool Selection (multi-action)',
482
- system: 'You are an email assistant. Today is 2026-04-02.',
483
- prompt: 'Reply to message msg-456 saying "Got it, thanks!" and create a task to follow up on Friday.',
484
- tools: AGENT_TOOLS,
485
- check: (r) => r.toolCalls.length >= 2,
486
- },
487
- {
488
- name: 'Tool Avoidance (no tool needed)',
489
- system: 'You are a helpful assistant.',
490
- prompt: 'What is the capital of France?',
491
- tools: AGENT_TOOLS,
492
- check: (r) => r.toolCalls.length === 0 && r.content.toLowerCase().includes('paris'),
493
- },
494
- {
495
- name: 'JSON Extraction',
496
- system: 'Extract the structured data from the user message. Respond with only valid JSON, no markdown.',
497
- prompt: 'Name: John Smith, Age: 34, Role: Senior Engineer, Department: Platform',
498
- tools: [],
499
- check: (r) => { try { var j = JSON.parse(r.content); return j.name || j.Name; } catch { return false; } },
500
- },
501
- {
502
- name: 'Code Generation',
503
- system: 'Write code. Only output the code, no explanation.',
504
- prompt: 'Write a TypeScript function that debounces another function with a given delay in ms.',
505
- tools: [],
506
- check: (r) => r.content.includes('function') && (r.content.includes('setTimeout') || r.content.includes('timeout')),
507
- },
508
- {
509
- name: 'Bug Detection',
510
- system: 'Review this code for bugs. Be specific.',
511
- prompt: `function fetchUser(id) {
512
- const res = fetch("/api/users/" + id);
513
- return res.json();
514
- }`,
515
- tools: [],
516
- check: (r) => r.content.toLowerCase().includes('await') || r.content.toLowerCase().includes('async'),
517
- },
518
- {
519
- name: 'Math Reasoning',
520
- system: 'Solve the problem. Give the final numerical answer.',
521
- prompt: 'A store has a 25% off sale. If an item originally costs $80, and you have a $10 coupon applied after the discount, how much do you pay?',
522
- tools: [],
523
- check: (r) => r.content.includes('50'),
524
- },
525
- {
526
- name: 'Email Tone (professional)',
527
- system: 'You are a professional AI assistant. Write concise emails.',
528
- prompt: 'Draft a short email to a client named David declining a meeting request for Monday because you have a conflict, but suggest Wednesday instead.',
529
- tools: [],
530
- check: (r) => r.content.toLowerCase().includes('wednesday') && r.content.toLowerCase().includes('david'),
531
- },
532
- ];
533
-
534
- var passed = 0;
535
- var total = tests.length;
536
-
537
- for (var i = 0; i < tests.length; i++) {
538
- var t = tests[i];
539
- process.stdout.write(`${c.gray}[${i + 1}/${total}]${c.reset} ${t.name} ... `);
540
-
541
- try {
542
- var messages = [{ role: 'system', content: t.system }, { role: 'user', content: t.prompt }];
543
- var result = await ollamaChat(messages, t.tools.length > 0 ? t.tools : undefined, false);
544
- var ok = t.check(result);
545
-
546
- if (ok) {
547
- passed++;
548
- console.log(`${c.green}✓ PASS${c.reset} ${c.gray}(${result.tokPerSec} tok/s, ${(result.elapsed / 1000).toFixed(1)}s)${c.reset}`);
549
- } else {
550
- console.log(`${c.red}✗ FAIL${c.reset} ${c.gray}(${(result.elapsed / 1000).toFixed(1)}s)${c.reset}`);
551
- if (result.toolCalls.length > 0) {
552
- console.log(`${c.gray} Tools: ${result.toolCalls.map(tc => tc.function.name).join(', ')}${c.reset}`);
553
- } else {
554
- console.log(`${c.gray} Output: ${result.content.slice(0, 120)}${c.reset}`);
555
- }
556
- }
557
- } catch (err) {
558
- console.log(`${c.red}✗ ERROR: ${err.message.slice(0, 80)}${c.reset}`);
559
- }
560
- }
561
-
562
- console.log(`\n${c.bold}Results: ${passed}/${total} passed${c.reset}`);
563
- if (passed === total) console.log(`${c.green}${c.bold}All tests passed!${c.reset}`);
564
- console.log('');
565
- }
566
-
567
- // ─── Helpers ────────────────────────────────────────────
568
-
569
- function simulateToolResult(name, args) {
570
- var now = new Date().toISOString();
571
- switch (name) {
572
- case 'gmail_reply':
573
- return { sent: true, messageId: 'msg-' + Date.now().toString(36), threadId: 'thread-001', inReplyTo: args.messageId };
574
- case 'gmail_forward':
575
- return { forwarded: true, messageId: 'msg-' + Date.now().toString(36), to: args.to };
576
- case 'gmail_search':
577
- return { results: [{ id: 'msg-search-001', from: 'example@test.com', subject: 'Re: ' + (args.query || ''), snippet: 'Sample search result...' }], count: 1 };
578
- case 'gmail_send':
579
- return { sent: true, messageId: 'msg-' + Date.now().toString(36), to: args.to, subject: args.subject };
580
- case 'google_tasks_create':
581
- return { created: true, id: 'task-' + Date.now().toString(36), title: args.title, due: args.due || null };
582
- case 'google_calendar_create':
583
- return { created: true, id: 'evt-' + Date.now().toString(36), title: args.title, start: args.start, end: args.end };
584
- case 'memory':
585
- if (args.action === 'store') return { stored: true, key: args.key };
586
- return { results: [{ key: 'example', value: 'Sample memory result' }] };
587
- default:
588
- return { ok: true };
589
- }
590
- }
591
-
592
- function ask(rl, prompt) {
593
- return new Promise(function(resolve) {
594
- rl.question(prompt, resolve);
595
- });
596
- }
597
-
598
- function askMultiline(rl, prompt, contPrompt) {
599
- return new Promise(function(resolve) {
600
- rl.question(prompt, function(first) {
601
- if (first === 'back' || first === 'quit' || first === 'exit') return resolve(first);
602
- if (!first.endsWith('\\')) return resolve(first);
603
-
604
- var lines = [first.slice(0, -1)];
605
- function next() {
606
- rl.question(contPrompt, function(line) {
607
- if (!line.endsWith('\\')) {
608
- lines.push(line);
609
- return resolve(lines.join('\n'));
610
- }
611
- lines.push(line.slice(0, -1));
612
- next();
613
- });
614
- }
615
- next();
616
- });
617
- });
618
- }
619
-
620
- // ─── Main ───────────────────────────────────────────────
621
-
622
- async function main() {
623
- // Check Ollama is running
624
- try {
625
- var resp = await fetch(OLLAMA_URL + '/api/tags');
626
- if (!resp.ok) throw new Error('not ok');
627
- var data = await resp.json();
628
- var hasModel = (data.models || []).some(function(m) { return m.name === MODEL || m.name === MODEL + ':latest'; });
629
- if (!hasModel) {
630
- console.error(`${c.red}Model "${MODEL}" not found. Available: ${(data.models || []).map(m => m.name).join(', ')}${c.reset}`);
631
- process.exit(1);
632
- }
633
- } catch (err) {
634
- console.error(`${c.red}Cannot connect to Ollama at ${OLLAMA_URL}. Is it running?${c.reset}`);
635
- process.exit(1);
636
- }
637
-
638
- console.log(`
639
- ${c.bold}╔══════════════════════════════════════════╗
640
- ║ ${c.cyan}Gemma 4 26B${c.reset}${c.bold} — Interactive Test CLI ║
641
- ║ ${c.gray}Model: ${MODEL}${c.reset}${c.bold} ║
642
- ║ ${c.gray}Ollama: ${OLLAMA_URL}${c.reset}${c.bold} ║
643
- ╚══════════════════════════════════════════╝${c.reset}
644
- `);
645
-
646
- var rl = readline.createInterface({
647
- input: process.stdin,
648
- output: process.stdout,
649
- terminal: true,
650
- });
651
-
652
- var mode = process.argv[2];
653
-
654
- if (mode) {
655
- await runMode(mode, rl);
656
- } else {
657
- await menuLoop(rl);
658
- }
659
-
660
- rl.close();
661
- }
662
-
663
- async function menuLoop(rl) {
664
- while (true) {
665
- console.log(`${c.bold}Select a mode:${c.reset}`);
666
- console.log(` ${c.cyan}1${c.reset} 💬 Chat — free conversation`);
667
- console.log(` ${c.magenta}2${c.reset} 🔧 Tools — tool calling tests`);
668
- console.log(` ${c.blue}3${c.reset} 💻 Code — code gen & review`);
669
- console.log(` ${c.yellow}4${c.reset} 📧 Email Agent — simulate email session`);
670
- console.log(` ${c.red}5${c.reset} 📊 Benchmark — automated test suite`);
671
- console.log(` ${c.magenta}6${c.reset} 🧠 Reasoning — logic & planning`);
672
- console.log(` ${c.gray}q${c.reset} Quit\n`);
673
-
674
- var choice = await ask(rl, `${c.bold}>${c.reset} `);
675
- var modeMap = { '1': 'chat', '2': 'tools', '3': 'code', '4': 'email', '5': 'bench', '6': 'reasoning', q: 'quit' };
676
- var selected = modeMap[choice] || choice;
677
-
678
- if (selected === 'quit' || selected === 'q' || selected === 'exit') {
679
- console.log(`${c.gray}Bye!${c.reset}`);
680
- return;
681
- }
682
-
683
- await runMode(selected, rl);
684
- }
685
- }
686
-
687
- async function runMode(mode, rl) {
688
- switch (mode) {
689
- case 'chat': return modeChat(rl);
690
- case 'tools': return modeTools(rl);
691
- case 'code': return modeCode(rl);
692
- case 'email': return modeEmail(rl);
693
- case 'bench': return modeBench();
694
- case 'reasoning': return modeReasoning(rl);
695
- default:
696
- console.log(`${c.red}Unknown mode: ${mode}${c.reset}`);
697
- }
698
- }
699
-
700
- main().catch(function(err) {
701
- console.error(`${c.red}Fatal: ${err.message}${c.reset}`);
702
- process.exit(1);
703
- });
File without changes