@markus-global/cli 0.4.18 → 0.4.20
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/dist/commands/start.d.ts.map +1 -1
- package/dist/commands/start.js +243 -81
- package/dist/commands/start.js.map +1 -1
- package/dist/commands/system.d.ts.map +1 -1
- package/dist/commands/system.js +22 -7
- package/dist/commands/system.js.map +1 -1
- package/dist/index.js +107 -93
- package/dist/index.js.map +1 -1
- package/dist/markus.mjs +4937 -2117
- package/dist/paths.js +4 -4
- package/dist/paths.js.map +1 -1
- package/dist/web-ui/assets/index-Bm8JwOPl.js +66 -0
- package/dist/web-ui/assets/index-CRfXZ2wF.css +1 -0
- package/dist/web-ui/index.html +2 -2
- package/package.json +1 -1
- package/templates/roles/developer/HEARTBEAT.md +4 -4
- package/templates/roles/operations/HEARTBEAT.md +4 -4
- package/templates/roles/org-manager/HEARTBEAT.md +4 -4
- package/templates/roles/product-manager/HEARTBEAT.md +4 -4
- package/templates/roles/reviewer/HEARTBEAT.md +4 -4
- package/templates/roles/secretary/HEARTBEAT.md +3 -3
- package/templates/roles/skill-architect/ROLE.md +1 -1
- package/templates/skills/chrome-devtools/SKILL.md +33 -14
- package/templates/skills/self-evolution/SKILL.md +128 -150
- package/templates/skills/self-evolution/skill.json +1 -1
- package/templates/skills/skill-building/SKILL.md +1 -1
- package/dist/web-ui/assets/index-BWQnbwYf.css +0 -1
- package/dist/web-ui/assets/index-DKzBhzes.js +0 -63
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"start.d.ts","sourceRoot":"","sources":["../../src/commands/start.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"start.d.ts","sourceRoot":"","sources":["../../src/commands/start.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAwDzC,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,OAAO,QAqBpD"}
|
package/dist/commands/start.js
CHANGED
|
@@ -2,9 +2,9 @@ import { resolve, join, dirname } from 'node:path';
|
|
|
2
2
|
import { existsSync } from 'node:fs';
|
|
3
3
|
import { homedir } from 'node:os';
|
|
4
4
|
import { allTemplateDirs, resolveTemplatesDir, resolveWebUiDir } from '../paths.js';
|
|
5
|
-
import { loadConfig, getDefaultConfigPath, createLogger, closeRuntimeLogger, } from '@markus/shared';
|
|
5
|
+
import { loadConfig, getDefaultConfigPath, createLogger, closeRuntimeLogger, checkForUpdate, TRIAGE_MAX_TOKENS, TRIAGE_TEMPERATURE, TRIAGE_ALLOWED_TOOLS, } from '@markus/shared';
|
|
6
6
|
import { AgentManager, LLMRouter, LLMLogger, RoleLoader, createDefaultSkillRegistry, ExternalAgentGateway, } from '@markus/core';
|
|
7
|
-
import { OrganizationService, TaskService, APIServer, HITLService, BillingService, AuditService, ProjectService, RequirementService, KnowledgeService, FileKnowledgeStore, DeliverableService, ReportService, TrustService, ScheduledTaskRunner, initStorage, searchRegistries, installSkill, } from '@markus/org-manager';
|
|
7
|
+
import { OrganizationService, TaskService, APIServer, HITLService, BillingService, AuditService, ProjectService, RequirementService, KnowledgeService, FileKnowledgeStore, DeliverableService, ReportService, TrustService, ArchiveService, ScheduledTaskRunner, initStorage, searchRegistries, installSkill, } from '@markus/org-manager';
|
|
8
8
|
import { MessageRouter, FeishuAdapter, WebUIAdapter } from '@markus/comms';
|
|
9
9
|
import { initStartupLogger, startupLog, startupBlank, startupSection, closeStartupLogger, getStartupLogFile } from '../utils/logger.js';
|
|
10
10
|
import { openBrowser } from '../utils/browser.js';
|
|
@@ -177,6 +177,15 @@ async function createServices(config) {
|
|
|
177
177
|
if (config.agent?.maxToolIterations) {
|
|
178
178
|
agentManager.maxToolIterations = config.agent.maxToolIterations;
|
|
179
179
|
}
|
|
180
|
+
if (config.browser?.bringToFront !== undefined) {
|
|
181
|
+
agentManager.setBrowserBringToFront(config.browser.bringToFront);
|
|
182
|
+
}
|
|
183
|
+
if (config.browser?.autoCloseTabs !== undefined) {
|
|
184
|
+
agentManager.setBrowserAutoCloseTabs(config.browser.autoCloseTabs);
|
|
185
|
+
}
|
|
186
|
+
if (config.browser?.remoteDebuggingPort) {
|
|
187
|
+
agentManager.setBrowserRemoteDebuggingPort(config.browser.remoteDebuggingPort);
|
|
188
|
+
}
|
|
180
189
|
taskService.setAgentManager(agentManager);
|
|
181
190
|
const orgService = new OrganizationService(agentManager, roleLoader, storage ?? undefined);
|
|
182
191
|
taskService.setOrgService(orgService);
|
|
@@ -306,6 +315,9 @@ async function startServer(config, values) {
|
|
|
306
315
|
if (storage?.notificationRepo) {
|
|
307
316
|
hitlService.setNotificationRepo(storage.notificationRepo);
|
|
308
317
|
}
|
|
318
|
+
if (storage?.approvalRepo) {
|
|
319
|
+
hitlService.setApprovalRepo(storage.approvalRepo);
|
|
320
|
+
}
|
|
309
321
|
if (storage?.projectRepo) {
|
|
310
322
|
projectService.setProjectRepo(storage.projectRepo);
|
|
311
323
|
}
|
|
@@ -340,6 +352,10 @@ async function startServer(config, values) {
|
|
|
340
352
|
// Wire ProjectService into TaskService (workspace management is handled by agents)
|
|
341
353
|
taskService.setProjectService(projectService);
|
|
342
354
|
taskService.setRequirementService(requirementService);
|
|
355
|
+
// Auto-archive: archive terminal tasks and requirements after configured thresholds
|
|
356
|
+
const archiveService = new ArchiveService(taskService, projectService);
|
|
357
|
+
archiveService.setRequirementService(requirementService);
|
|
358
|
+
archiveService.start();
|
|
343
359
|
// Expose LLM router to API server so settings can read/write it at runtime
|
|
344
360
|
apiServer.setLLMRouter(llmRouter);
|
|
345
361
|
apiServer.setConfigPath(values['config'] ?? getDefaultConfigPath());
|
|
@@ -372,6 +388,16 @@ async function startServer(config, values) {
|
|
|
372
388
|
if (hubClient) {
|
|
373
389
|
agentManager.setHubClient(hubClient);
|
|
374
390
|
}
|
|
391
|
+
// Wire team/agent update callbacks for manager tools
|
|
392
|
+
agentManager.setTeamUpdater(async (teamId, data) => {
|
|
393
|
+
const team = await orgService.updateTeam(teamId, data);
|
|
394
|
+
return { id: teamId, name: team.name, description: team.description };
|
|
395
|
+
});
|
|
396
|
+
if (storage) {
|
|
397
|
+
agentManager.setAgentConfigPersister(async (agentId, data) => {
|
|
398
|
+
await storage.agentRepo.updateConfig(agentId, data);
|
|
399
|
+
});
|
|
400
|
+
}
|
|
375
401
|
// Wire skill search/install callbacks so agents can discover and install remote skills
|
|
376
402
|
agentManager.setSkillSearcher(async (query) => searchRegistries(query));
|
|
377
403
|
agentManager.setSkillInstaller(async (request) => {
|
|
@@ -388,50 +414,20 @@ async function startServer(config, values) {
|
|
|
388
414
|
}, skillRegistry);
|
|
389
415
|
return { installed: result.installed, name: result.name, method: result.method };
|
|
390
416
|
});
|
|
391
|
-
// Wire
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
const sessions = await storage.chatSessionRepo.getSessionsByAgent(agentId);
|
|
404
|
-
if (sessions.length > 0) {
|
|
405
|
-
sessionId = sessions[0].id;
|
|
406
|
-
}
|
|
407
|
-
else {
|
|
408
|
-
const newSess = await storage.chatSessionRepo.createSession(agentId);
|
|
409
|
-
sessionId = newSess.id;
|
|
410
|
-
}
|
|
411
|
-
}
|
|
412
|
-
const msg = await storage.chatSessionRepo.appendMessage(sessionId, agentId, 'assistant', message);
|
|
413
|
-
ws.broadcastProactiveMessage(agentId, agent.config.name, sessionId, msg.id, message);
|
|
414
|
-
return { sessionId, messageId: msg.id };
|
|
415
|
-
});
|
|
416
|
-
agentManager.setChatSessionsFetcher(agentId, async () => {
|
|
417
|
-
const sessions = await storage.chatSessionRepo.getSessionsByAgent(agentId);
|
|
418
|
-
return sessions.slice(0, 5).map((s) => ({
|
|
419
|
-
id: s.id,
|
|
420
|
-
title: s.title,
|
|
421
|
-
lastMessageAt: s.lastMessageAt ?? s.createdAt ?? new Date().toISOString(),
|
|
422
|
-
lastMessagePreview: s.lastMessagePreview,
|
|
423
|
-
}));
|
|
424
|
-
});
|
|
425
|
-
}
|
|
426
|
-
catch { /* agent not found */ }
|
|
427
|
-
};
|
|
428
|
-
for (const info of agentManager.listAgents())
|
|
429
|
-
wireAgentChatIntegration(info.id);
|
|
430
|
-
agentManager.getEventBus().on('agent:created', (evt) => {
|
|
431
|
-
const { agentId } = evt;
|
|
432
|
-
wireAgentChatIntegration(agentId);
|
|
417
|
+
// Wire user approval requester through HITL service
|
|
418
|
+
agentManager.setUserApprovalRequester(async (opts) => {
|
|
419
|
+
return hitlService.requestApprovalAndWait({
|
|
420
|
+
agentId: opts.agentId,
|
|
421
|
+
agentName: opts.agentName,
|
|
422
|
+
type: 'custom',
|
|
423
|
+
title: opts.title,
|
|
424
|
+
description: opts.description,
|
|
425
|
+
targetUserId: 'default',
|
|
426
|
+
options: opts.options,
|
|
427
|
+
allowFreeform: opts.allowFreeform,
|
|
428
|
+
details: { priority: opts.priority, taskId: opts.relatedTaskId },
|
|
433
429
|
});
|
|
434
|
-
}
|
|
430
|
+
});
|
|
435
431
|
// Wire user notifier through HITL service
|
|
436
432
|
agentManager.setUserNotifier((opts) => {
|
|
437
433
|
hitlService.notify({
|
|
@@ -447,6 +443,13 @@ async function startServer(config, values) {
|
|
|
447
443
|
});
|
|
448
444
|
// Ensure every agent has a main session on startup, then persist activity logs to it
|
|
449
445
|
if (storage?.chatSessionRepo) {
|
|
446
|
+
// Migrate legacy assistant messages that lack segments metadata
|
|
447
|
+
try {
|
|
448
|
+
storage.chatSessionRepo.migrateLegacyMessages();
|
|
449
|
+
}
|
|
450
|
+
catch (e) {
|
|
451
|
+
log.warn('Legacy chat message migration failed', { error: String(e) });
|
|
452
|
+
}
|
|
450
453
|
for (const info of agentManager.listAgents()) {
|
|
451
454
|
try {
|
|
452
455
|
storage.chatSessionRepo.getOrCreateMainSession(info.id);
|
|
@@ -457,15 +460,77 @@ async function startServer(config, values) {
|
|
|
457
460
|
agentManager.getEventBus().on('agent:activity-log', async (evt) => {
|
|
458
461
|
const { agentId, message, metadata } = evt;
|
|
459
462
|
try {
|
|
460
|
-
const mainSession =
|
|
461
|
-
const msg =
|
|
463
|
+
const mainSession = storage.chatSessionRepo.getOrCreateMainSession(agentId);
|
|
464
|
+
const msg = storage.chatSessionRepo.appendMessage(mainSession.id, agentId, 'assistant', message, 0, metadata);
|
|
465
|
+
storage.chatSessionRepo.updateLastMessage(mainSession.id);
|
|
462
466
|
const agent = agentManager.getAgent(agentId);
|
|
463
|
-
ws.broadcastProactiveMessage(agentId, agent.config.name, mainSession.id, msg.id, message
|
|
467
|
+
ws.broadcastProactiveMessage(agentId, agent.config.name, mainSession.id, msg.id, message, {
|
|
468
|
+
...metadata,
|
|
469
|
+
isMainSession: true,
|
|
470
|
+
});
|
|
464
471
|
}
|
|
465
472
|
catch (e) {
|
|
466
473
|
log.warn('Failed to persist activity log', { agentId, error: String(e) });
|
|
467
474
|
}
|
|
468
475
|
});
|
|
476
|
+
// notify_user: persist as regular chat message + WS broadcast + notification bell
|
|
477
|
+
agentManager.getEventBus().on('agent:notify-user', async (evt) => {
|
|
478
|
+
const { agentId, title, body, priority, taskId, requirementId } = evt;
|
|
479
|
+
try {
|
|
480
|
+
const mainSession = storage.chatSessionRepo.getOrCreateMainSession(agentId);
|
|
481
|
+
const agent = agentManager.getAgent(agentId);
|
|
482
|
+
const formattedMsg = `**${title}**\n\n${body}`;
|
|
483
|
+
const msg = storage.chatSessionRepo.appendMessage(mainSession.id, agentId, 'assistant', formattedMsg, 0, {});
|
|
484
|
+
storage.chatSessionRepo.updateLastMessage(mainSession.id);
|
|
485
|
+
ws.broadcastProactiveMessage(agentId, agent.config.name, mainSession.id, msg.id, formattedMsg, {
|
|
486
|
+
isMainSession: true,
|
|
487
|
+
});
|
|
488
|
+
const hasTask = !!taskId;
|
|
489
|
+
hitlService.notify({
|
|
490
|
+
targetUserId: 'default',
|
|
491
|
+
type: 'agent_report',
|
|
492
|
+
title, body, priority,
|
|
493
|
+
actionType: hasTask ? 'navigate' : 'open_chat',
|
|
494
|
+
actionTarget: hasTask
|
|
495
|
+
? JSON.stringify({ path: `/work?openTask=${taskId}` })
|
|
496
|
+
: JSON.stringify({ agentId, sessionId: mainSession.id }),
|
|
497
|
+
metadata: { agentId, agentName: agent.config.name, taskId, requirementId, sessionId: mainSession.id },
|
|
498
|
+
});
|
|
499
|
+
}
|
|
500
|
+
catch (e) {
|
|
501
|
+
log.warn('Failed to handle notify-user event', { agentId, error: String(e) });
|
|
502
|
+
}
|
|
503
|
+
});
|
|
504
|
+
// escalation: persist as regular chat message + WS broadcast + notification + audit
|
|
505
|
+
agentManager.getEventBus().on('agent:escalation', async (evt) => {
|
|
506
|
+
const { agentId, reason } = evt;
|
|
507
|
+
try {
|
|
508
|
+
const mainSession = storage.chatSessionRepo.getOrCreateMainSession(agentId);
|
|
509
|
+
const agent = agentManager.getAgent(agentId);
|
|
510
|
+
const formattedMsg = `**I need help**\n\n${reason}`;
|
|
511
|
+
const msg = storage.chatSessionRepo.appendMessage(mainSession.id, agentId, 'assistant', formattedMsg, 0, {});
|
|
512
|
+
storage.chatSessionRepo.updateLastMessage(mainSession.id);
|
|
513
|
+
ws.broadcastProactiveMessage(agentId, agent.config.name, mainSession.id, msg.id, formattedMsg, {
|
|
514
|
+
isMainSession: true,
|
|
515
|
+
});
|
|
516
|
+
hitlService.notify({
|
|
517
|
+
targetUserId: 'default',
|
|
518
|
+
type: 'system',
|
|
519
|
+
title: 'Agent needs help',
|
|
520
|
+
body: reason,
|
|
521
|
+
priority: 'high',
|
|
522
|
+
actionType: 'open_chat',
|
|
523
|
+
actionTarget: JSON.stringify({ agentId, sessionId: mainSession.id }),
|
|
524
|
+
metadata: { agentId, sessionId: mainSession.id },
|
|
525
|
+
});
|
|
526
|
+
auditService.record({
|
|
527
|
+
orgId: 'default', agentId, type: 'error', action: 'escalation', detail: reason, success: false,
|
|
528
|
+
});
|
|
529
|
+
}
|
|
530
|
+
catch (e) {
|
|
531
|
+
log.warn('Failed to handle escalation event', { agentId, error: String(e) });
|
|
532
|
+
}
|
|
533
|
+
});
|
|
469
534
|
// Also create main session for newly created agents
|
|
470
535
|
agentManager.getEventBus().on('agent:created', (evt) => {
|
|
471
536
|
const { agentId } = evt;
|
|
@@ -475,17 +540,7 @@ async function startServer(config, values) {
|
|
|
475
540
|
catch { /* skip */ }
|
|
476
541
|
});
|
|
477
542
|
}
|
|
478
|
-
//
|
|
479
|
-
// Tasks retain their execution history in DB (task_logs + comments),
|
|
480
|
-
// so the agent receives full previous context on resume.
|
|
481
|
-
setTimeout(async () => {
|
|
482
|
-
try {
|
|
483
|
-
await taskService.resumeInProgressTasks();
|
|
484
|
-
}
|
|
485
|
-
catch (err) {
|
|
486
|
-
log.warn('Failed to auto-resume in_progress tasks', { error: String(err) });
|
|
487
|
-
}
|
|
488
|
-
}, 3000);
|
|
543
|
+
// Task resume is triggered after agents finish starting (see below).
|
|
489
544
|
// Wire External Agent Gateway for OpenClaw integration
|
|
490
545
|
const gatewaySecret = config.security?.gatewaySecret ?? process.env['GATEWAY_SECRET'] ?? 'markus-gateway-default-secret-change-me';
|
|
491
546
|
const gateway = new ExternalAgentGateway({ signingSecret: gatewaySecret });
|
|
@@ -577,23 +632,10 @@ async function startServer(config, values) {
|
|
|
577
632
|
deliverableService.setWSBroadcaster(apiServer.getWSBroadcaster());
|
|
578
633
|
const scheduledTaskRunner = new ScheduledTaskRunner(taskService);
|
|
579
634
|
scheduledTaskRunner.start();
|
|
635
|
+
// Escalation callback kept for agent-internal state management; actual notification/DB/WS/audit
|
|
636
|
+
// logic is handled by the 'agent:escalation' event handler registered above.
|
|
580
637
|
agentManager.setEscalationHandler((agentId, reason) => {
|
|
581
638
|
log.warn('Agent escalation', { agentId, reason });
|
|
582
|
-
hitlService.notify({
|
|
583
|
-
targetUserId: 'default',
|
|
584
|
-
type: 'system',
|
|
585
|
-
title: 'Agent needs help',
|
|
586
|
-
body: reason,
|
|
587
|
-
priority: 'high',
|
|
588
|
-
});
|
|
589
|
-
auditService.record({
|
|
590
|
-
orgId: 'default',
|
|
591
|
-
agentId,
|
|
592
|
-
type: 'error',
|
|
593
|
-
action: 'escalation',
|
|
594
|
-
detail: reason,
|
|
595
|
-
success: false,
|
|
596
|
-
});
|
|
597
639
|
});
|
|
598
640
|
agentManager.setApprovalHandler(async (agentId, request) => {
|
|
599
641
|
const agents = agentManager.listAgents();
|
|
@@ -611,7 +653,6 @@ async function startServer(config, values) {
|
|
|
611
653
|
description: request.reason,
|
|
612
654
|
details: { ...request.toolArgs, toolName: request.toolName, agentId, taskId: request.taskId },
|
|
613
655
|
targetUserId: 'default',
|
|
614
|
-
expiresInMs: 5 * 60 * 1000, // 5 minutes
|
|
615
656
|
});
|
|
616
657
|
auditService.record({
|
|
617
658
|
orgId: 'default',
|
|
@@ -725,6 +766,24 @@ async function startServer(config, values) {
|
|
|
725
766
|
}
|
|
726
767
|
},
|
|
727
768
|
});
|
|
769
|
+
// Wire recall_activity tool to query execution history from SQLite
|
|
770
|
+
agentManager.setRecallCallbacks({
|
|
771
|
+
listActivities: (agentId, opts) => {
|
|
772
|
+
const results = actRepo.queryActivities(agentId, {
|
|
773
|
+
type: opts.type,
|
|
774
|
+
limit: opts.limit,
|
|
775
|
+
});
|
|
776
|
+
if (opts.taskId)
|
|
777
|
+
return results.filter((a) => a.taskId === opts.taskId);
|
|
778
|
+
return results;
|
|
779
|
+
},
|
|
780
|
+
getActivityLogs: (activityId) => {
|
|
781
|
+
return actRepo.getActivityLogs(activityId);
|
|
782
|
+
},
|
|
783
|
+
searchActivities: (agentId, query, opts) => {
|
|
784
|
+
return actRepo.searchActivities(agentId, query, opts);
|
|
785
|
+
},
|
|
786
|
+
});
|
|
728
787
|
}
|
|
729
788
|
// Wire mailbox + decision persistence to SQLite
|
|
730
789
|
if (storage?.mailboxRepo && storage?.decisionRepo) {
|
|
@@ -737,11 +796,12 @@ async function startServer(config, values) {
|
|
|
737
796
|
mailbox.setPersistence({
|
|
738
797
|
save: (item) => {
|
|
739
798
|
try {
|
|
799
|
+
const { responsePromise, ...persistableMetadata } = (item.metadata ?? {});
|
|
740
800
|
mbRepo.save({
|
|
741
801
|
id: item.id, agentId: item.agentId, sourceType: item.sourceType,
|
|
742
802
|
priority: item.priority, status: item.status,
|
|
743
803
|
payload: item.payload,
|
|
744
|
-
metadata:
|
|
804
|
+
metadata: persistableMetadata,
|
|
745
805
|
queuedAt: item.queuedAt,
|
|
746
806
|
});
|
|
747
807
|
}
|
|
@@ -758,10 +818,46 @@ async function startServer(config, values) {
|
|
|
758
818
|
}
|
|
759
819
|
},
|
|
760
820
|
markStaleProcessingAsDropped: (aid) => mbRepo.markStaleProcessingAsDropped(aid),
|
|
821
|
+
loadQueued: (aid) => {
|
|
822
|
+
const rows = mbRepo.getByAgent(aid, { status: 'queued' });
|
|
823
|
+
return rows.map((r) => ({
|
|
824
|
+
id: r.id,
|
|
825
|
+
agentId: r.agentId,
|
|
826
|
+
sourceType: r.sourceType,
|
|
827
|
+
priority: r.priority,
|
|
828
|
+
status: r.status,
|
|
829
|
+
payload: r.payload,
|
|
830
|
+
metadata: r.metadata,
|
|
831
|
+
queuedAt: r.queuedAt,
|
|
832
|
+
startedAt: r.startedAt ?? undefined,
|
|
833
|
+
completedAt: r.completedAt ?? undefined,
|
|
834
|
+
deferredUntil: r.deferredUntil ?? undefined,
|
|
835
|
+
mergedInto: r.mergedInto ?? undefined,
|
|
836
|
+
retryCount: r.retryCount ?? 0,
|
|
837
|
+
}));
|
|
838
|
+
},
|
|
839
|
+
loadDeferred: (aid) => {
|
|
840
|
+
const rows = mbRepo.getByAgent(aid, { status: 'deferred' });
|
|
841
|
+
return rows.map((r) => ({
|
|
842
|
+
id: r.id,
|
|
843
|
+
agentId: r.agentId,
|
|
844
|
+
sourceType: r.sourceType,
|
|
845
|
+
priority: r.priority,
|
|
846
|
+
status: r.status,
|
|
847
|
+
payload: r.payload,
|
|
848
|
+
metadata: r.metadata,
|
|
849
|
+
queuedAt: r.queuedAt,
|
|
850
|
+
startedAt: r.startedAt ?? undefined,
|
|
851
|
+
completedAt: r.completedAt ?? undefined,
|
|
852
|
+
deferredUntil: r.deferredUntil ?? undefined,
|
|
853
|
+
mergedInto: r.mergedInto ?? undefined,
|
|
854
|
+
retryCount: r.retryCount ?? 0,
|
|
855
|
+
}));
|
|
856
|
+
},
|
|
761
857
|
});
|
|
762
|
-
const dropped = mailbox.recoverStaleItems();
|
|
763
|
-
if (dropped > 0)
|
|
764
|
-
log.info('
|
|
858
|
+
const { dropped, restored, expired, merged } = mailbox.recoverStaleItems();
|
|
859
|
+
if (dropped > 0 || restored > 0 || expired > 0 || merged > 0)
|
|
860
|
+
log.info('Mailbox recovery on startup', { agentId, dropped, restored, expired, merged });
|
|
765
861
|
agent.getAttentionController().setDecisionPersistence({
|
|
766
862
|
save: (decision) => {
|
|
767
863
|
try {
|
|
@@ -779,6 +875,52 @@ async function startServer(config, values) {
|
|
|
779
875
|
}
|
|
780
876
|
},
|
|
781
877
|
});
|
|
878
|
+
// Wire TriageJudge — uses the agent's configured LLM provider
|
|
879
|
+
const triageProvider = agent.config.llmConfig?.modelMode === 'custom'
|
|
880
|
+
? agent.config.llmConfig.primary : undefined;
|
|
881
|
+
agent.getAttentionController().setTriageJudge(async (prompt) => {
|
|
882
|
+
const response = await llmRouter.chat({
|
|
883
|
+
messages: [
|
|
884
|
+
{ role: 'system', content: 'You are a mailbox triage assistant. Output ONLY a single JSON object — no explanation, no markdown fences, no <think> tags. Start your response with {' },
|
|
885
|
+
{ role: 'user', content: prompt },
|
|
886
|
+
],
|
|
887
|
+
temperature: TRIAGE_TEMPERATURE,
|
|
888
|
+
maxTokens: TRIAGE_MAX_TOKENS,
|
|
889
|
+
}, triageProvider);
|
|
890
|
+
return response.content;
|
|
891
|
+
});
|
|
892
|
+
// Wire triage chat function (for mini tool loop during triage)
|
|
893
|
+
agent.getAttentionController().setTriageChatFn(async (messages, tools) => {
|
|
894
|
+
const llmTools = tools?.map(t => ({
|
|
895
|
+
name: t.name,
|
|
896
|
+
description: t.description,
|
|
897
|
+
inputSchema: t.inputSchema,
|
|
898
|
+
}));
|
|
899
|
+
const response = await llmRouter.chat({
|
|
900
|
+
messages: messages,
|
|
901
|
+
tools: llmTools,
|
|
902
|
+
temperature: TRIAGE_TEMPERATURE,
|
|
903
|
+
maxTokens: TRIAGE_MAX_TOKENS,
|
|
904
|
+
}, triageProvider);
|
|
905
|
+
return { content: response.content, toolCalls: response.toolCalls };
|
|
906
|
+
});
|
|
907
|
+
// Wire read-only triage tools from the agent's tool set
|
|
908
|
+
const triageToolMap = new Map();
|
|
909
|
+
const agentTools = agent.getTools();
|
|
910
|
+
for (const toolName of TRIAGE_ALLOWED_TOOLS) {
|
|
911
|
+
const handler = agentTools.get(toolName);
|
|
912
|
+
if (handler) {
|
|
913
|
+
triageToolMap.set(toolName, {
|
|
914
|
+
name: handler.name,
|
|
915
|
+
description: handler.description,
|
|
916
|
+
inputSchema: handler.inputSchema,
|
|
917
|
+
execute: handler.execute.bind(handler),
|
|
918
|
+
});
|
|
919
|
+
}
|
|
920
|
+
}
|
|
921
|
+
if (triageToolMap.size > 0) {
|
|
922
|
+
agent.getAttentionController().setTriageTools(triageToolMap);
|
|
923
|
+
}
|
|
782
924
|
}
|
|
783
925
|
catch { /* agent not found */ }
|
|
784
926
|
};
|
|
@@ -850,6 +992,10 @@ async function startServer(config, values) {
|
|
|
850
992
|
const ws = apiServer.getWSBroadcaster();
|
|
851
993
|
ws.broadcast({ type: 'agent:focus', payload: event, timestamp: new Date().toISOString() });
|
|
852
994
|
});
|
|
995
|
+
eventBus.on('attention:triage', (event) => {
|
|
996
|
+
const ws = apiServer.getWSBroadcaster();
|
|
997
|
+
ws.broadcast({ type: 'agent:triage', payload: event, timestamp: new Date().toISOString() });
|
|
998
|
+
});
|
|
853
999
|
// Wire agent lifecycle events to WS broadcast
|
|
854
1000
|
eventBus.on('agent:removed', (event) => {
|
|
855
1001
|
const { agentId } = event;
|
|
@@ -992,12 +1138,28 @@ async function startServer(config, values) {
|
|
|
992
1138
|
else {
|
|
993
1139
|
progress.finish(uiUrl);
|
|
994
1140
|
}
|
|
995
|
-
//
|
|
996
|
-
|
|
1141
|
+
// Non-blocking update check — runs after startup, never blocks or throws
|
|
1142
|
+
checkForUpdate().then(info => {
|
|
1143
|
+
if (info.updateAvailable) {
|
|
1144
|
+
console.log(`\n \x1b[33m⬆ New version available: v${info.latestVersion} (current: v${info.currentVersion})\x1b[0m`);
|
|
1145
|
+
console.log(` Run \x1b[1mnpm i -g @markus-global/cli\x1b[0m to upgrade\n`);
|
|
1146
|
+
}
|
|
1147
|
+
}).catch(() => { });
|
|
1148
|
+
// Start restored agents in background (server is already accepting requests),
|
|
1149
|
+
// then auto-resume in_progress tasks once all agents are ready.
|
|
1150
|
+
orgService.startRestoredAgentsInBackground().then(async () => {
|
|
1151
|
+
try {
|
|
1152
|
+
await taskService.resumeInProgressTasks();
|
|
1153
|
+
}
|
|
1154
|
+
catch (err) {
|
|
1155
|
+
log.warn('Failed to auto-resume in_progress tasks', { error: String(err) });
|
|
1156
|
+
}
|
|
1157
|
+
});
|
|
997
1158
|
process.on('SIGINT', () => {
|
|
998
1159
|
console.error('\nShutting down...');
|
|
999
1160
|
closeStartupLogger();
|
|
1000
1161
|
closeRuntimeLogger();
|
|
1162
|
+
archiveService.stop();
|
|
1001
1163
|
scheduledTaskRunner.stop();
|
|
1002
1164
|
apiServer.stop();
|
|
1003
1165
|
agentManager.shutdown()
|