@ducci/jarvis 1.0.8 → 1.0.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.
Files changed (2) hide show
  1. package/package.json +2 -2
  2. package/src/server/agent.js +94 -52
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ducci/jarvis",
3
- "version": "1.0.8",
3
+ "version": "1.0.9",
4
4
  "description": "A fully automated agent system that lives on a server.",
5
5
  "main": "./src/index.js",
6
6
  "type": "module",
@@ -20,7 +20,7 @@
20
20
  "setup": "node ./src/scripts/onboarding.js",
21
21
  "dev": "nodemon ./src/server/app.js",
22
22
  "prepare": "cd ui && npm install && npm run build",
23
- "publish": "node scripts/publish.js",
23
+ "release": "node scripts/publish.js",
24
24
  "test": "echo \"Error: no test specified\" && exit 1"
25
25
  },
26
26
  "keywords": [
@@ -85,7 +85,20 @@ async function runAgentLoop(client, config, session, tools, toolDefs, prepareMes
85
85
  status: 'model_error',
86
86
  runToolCalls,
87
87
  checkpoint: null,
88
- errorDetail: e.apiErrors ?? { message: e.message },
88
+ errorDetail: e.apiErrors ?? { message: e.message, stack: e.stack },
89
+ contextInfo: { messageCount: preparedMessages.length },
90
+ };
91
+ }
92
+
93
+ if (!modelResult.choices || modelResult.choices.length === 0) {
94
+ return {
95
+ iteration,
96
+ response: 'Model returned an empty response.',
97
+ logSummary: `Model error on iteration ${iteration}: Empty choices array.`,
98
+ status: 'model_error',
99
+ runToolCalls,
100
+ checkpoint: null,
101
+ errorDetail: { message: 'Empty choices array from LLM' },
89
102
  contextInfo: { messageCount: preparedMessages.length },
90
103
  };
91
104
  }
@@ -168,7 +181,20 @@ async function runAgentLoop(client, config, session, tools, toolDefs, prepareMes
168
181
  status: 'model_error',
169
182
  runToolCalls,
170
183
  checkpoint: null,
171
- errorDetail: e.apiErrors ?? { message: e.message },
184
+ errorDetail: e.apiErrors ?? { message: e.message, stack: e.stack },
185
+ contextInfo: { messageCount: wrapUpMessages.length },
186
+ };
187
+ }
188
+
189
+ if (!wrapUpResult.choices || wrapUpResult.choices.length === 0) {
190
+ return {
191
+ iteration,
192
+ response: 'Wrap-up call returned an empty response.',
193
+ logSummary: 'Iteration limit reached. Wrap-up returned empty choices.',
194
+ status: 'model_error',
195
+ runToolCalls,
196
+ checkpoint: null,
197
+ errorDetail: { message: 'Empty choices array in wrap-up' },
172
198
  contextInfo: { messageCount: wrapUpMessages.length },
173
199
  };
174
200
  }
@@ -244,63 +270,79 @@ export async function handleChat(config, requestSessionId, userMessage) {
244
270
  let finalStatus = 'ok';
245
271
 
246
272
  // Handoff loop
247
- while (true) {
248
- const run = await runAgentLoop(client, config, session, tools, toolDefs, prepareMessages);
249
- allToolCalls.push(...run.runToolCalls);
250
-
251
- if (run.status !== 'checkpoint_reached') {
252
- finalResponse = run.response;
253
- finalLogSummary = run.logSummary;
254
- finalStatus = run.status;
273
+ try {
274
+ while (true) {
275
+ const run = await runAgentLoop(client, config, session, tools, toolDefs, prepareMessages);
276
+ allToolCalls.push(...run.runToolCalls);
277
+
278
+ if (run.status !== 'checkpoint_reached') {
279
+ finalResponse = run.response;
280
+ finalLogSummary = run.logSummary;
281
+ finalStatus = run.status;
282
+
283
+ const logEntry = {
284
+ iteration: run.iteration,
285
+ model: config.selectedModel,
286
+ userInput: userMessage,
287
+ toolCalls: allToolCalls,
288
+ response: finalResponse,
289
+ logSummary: finalLogSummary,
290
+ status: finalStatus,
291
+ };
292
+ if (run.errorDetail) logEntry.errorDetail = run.errorDetail;
293
+ if (run.contextInfo) logEntry.contextInfo = run.contextInfo;
294
+ if (run.rawResponse) logEntry.rawResponse = run.rawResponse;
295
+ appendLog(sessionId, logEntry);
296
+ break;
297
+ }
255
298
 
256
- const logEntry = {
299
+ // Checkpoint reached — log this run
300
+ appendLog(sessionId, {
257
301
  iteration: run.iteration,
258
302
  model: config.selectedModel,
259
303
  userInput: userMessage,
260
- toolCalls: allToolCalls,
261
- response: finalResponse,
262
- logSummary: finalLogSummary,
263
- status: finalStatus,
264
- };
265
- if (run.errorDetail) logEntry.errorDetail = run.errorDetail;
266
- if (run.contextInfo) logEntry.contextInfo = run.contextInfo;
267
- if (run.rawResponse) logEntry.rawResponse = run.rawResponse;
268
- appendLog(sessionId, logEntry);
269
- break;
270
- }
271
-
272
- // Checkpoint reached — log this run
273
- appendLog(sessionId, {
274
- iteration: run.iteration,
275
- model: config.selectedModel,
276
- userInput: userMessage,
277
- toolCalls: run.runToolCalls,
278
- response: run.response,
279
- logSummary: run.logSummary,
280
- status: 'checkpoint_reached',
281
- });
304
+ toolCalls: run.runToolCalls,
305
+ response: run.response,
306
+ logSummary: run.logSummary,
307
+ status: 'checkpoint_reached',
308
+ });
282
309
 
283
- // Check handoff limit
284
- session.metadata.handoffCount++;
285
- if (session.metadata.handoffCount > config.maxHandoffs) {
286
- finalResponse = run.response;
287
- finalLogSummary = run.logSummary;
288
- finalStatus = 'intervention_required';
310
+ // Check handoff limit
311
+ session.metadata.handoffCount++;
312
+ if (session.metadata.handoffCount > config.maxHandoffs) {
313
+ finalResponse = run.response;
314
+ finalLogSummary = run.logSummary;
315
+ finalStatus = 'intervention_required';
316
+
317
+ appendLog(sessionId, {
318
+ iteration: 0,
319
+ model: config.selectedModel,
320
+ userInput: userMessage,
321
+ toolCalls: [],
322
+ response: finalResponse,
323
+ logSummary: 'Max handoffs exceeded. Human intervention required.',
324
+ status: 'intervention_required',
325
+ });
326
+ break;
327
+ }
289
328
 
290
- appendLog(sessionId, {
291
- iteration: 0,
292
- model: config.selectedModel,
293
- userInput: userMessage,
294
- toolCalls: [],
295
- response: finalResponse,
296
- logSummary: 'Max handoffs exceeded. Human intervention required.',
297
- status: 'intervention_required',
298
- });
299
- break;
329
+ // Resume with checkpoint.remaining as new prompt
330
+ session.messages.push({ role: 'user', content: run.checkpoint.remaining });
300
331
  }
301
-
302
- // Resume with checkpoint.remaining as new prompt
303
- session.messages.push({ role: 'user', content: run.checkpoint.remaining });
332
+ } catch (e) {
333
+ const errorLog = {
334
+ iteration: 0,
335
+ model: config.selectedModel,
336
+ userInput: userMessage,
337
+ toolCalls: allToolCalls,
338
+ response: `An unexpected server error occurred: ${e.message}`,
339
+ logSummary: `Critical error: ${e.message}`,
340
+ status: 'error',
341
+ errorDetail: { message: e.message, stack: e.stack },
342
+ };
343
+ appendLog(sessionId, errorLog);
344
+ // Re-throw to let app.js handle the HTTP response
345
+ throw e;
304
346
  }
305
347
 
306
348
  saveSession(sessionId, session);