@siftd/connect-agent 0.2.57 → 0.2.58
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/orchestrator.d.ts +6 -0
- package/dist/orchestrator.js +151 -0
- package/package.json +1 -1
package/dist/orchestrator.d.ts
CHANGED
|
@@ -76,6 +76,7 @@ export declare class MasterOrchestrator {
|
|
|
76
76
|
private currentFileScope;
|
|
77
77
|
private forceTeamWorkingDir;
|
|
78
78
|
private recentFileWrites;
|
|
79
|
+
private recentWorkerActivity;
|
|
79
80
|
private bashTool;
|
|
80
81
|
private webTools;
|
|
81
82
|
private workerTools;
|
|
@@ -214,6 +215,11 @@ export declare class MasterOrchestrator {
|
|
|
214
215
|
private toFilesVirtualPath;
|
|
215
216
|
private finalizeResponse;
|
|
216
217
|
private getFileScopeSystemNote;
|
|
218
|
+
private recordWorkerActivity;
|
|
219
|
+
private formatRelativeTime;
|
|
220
|
+
private getRecentWorkerSummary;
|
|
221
|
+
private isStatusInquiry;
|
|
222
|
+
private buildStatusReply;
|
|
217
223
|
/**
|
|
218
224
|
* Check if verbose mode is enabled
|
|
219
225
|
*/
|
package/dist/orchestrator.js
CHANGED
|
@@ -259,6 +259,7 @@ export class MasterOrchestrator {
|
|
|
259
259
|
currentFileScope = 'personal';
|
|
260
260
|
forceTeamWorkingDir = false;
|
|
261
261
|
recentFileWrites = [];
|
|
262
|
+
recentWorkerActivity = [];
|
|
262
263
|
// New tools from whatsapp-claude
|
|
263
264
|
bashTool;
|
|
264
265
|
webTools;
|
|
@@ -992,6 +993,98 @@ export class MasterOrchestrator {
|
|
|
992
993
|
return null;
|
|
993
994
|
return `TEAM FILES DIRECTORY:\n- ${teamDir}\nUse this path for files meant to be shared with the team.`;
|
|
994
995
|
}
|
|
996
|
+
recordWorkerActivity(event) {
|
|
997
|
+
const normalized = {
|
|
998
|
+
...event,
|
|
999
|
+
task: event.task.slice(0, 140),
|
|
1000
|
+
note: event.note?.slice(0, 200)
|
|
1001
|
+
};
|
|
1002
|
+
this.recentWorkerActivity = [normalized, ...this.recentWorkerActivity].slice(0, 12);
|
|
1003
|
+
}
|
|
1004
|
+
formatRelativeTime(timestamp) {
|
|
1005
|
+
const deltaMs = Date.now() - timestamp;
|
|
1006
|
+
if (deltaMs < 1000)
|
|
1007
|
+
return 'just now';
|
|
1008
|
+
const seconds = Math.floor(deltaMs / 1000);
|
|
1009
|
+
if (seconds < 60)
|
|
1010
|
+
return `${seconds}s ago`;
|
|
1011
|
+
const minutes = Math.floor(seconds / 60);
|
|
1012
|
+
if (minutes < 60)
|
|
1013
|
+
return `${minutes}m ago`;
|
|
1014
|
+
const hours = Math.floor(minutes / 60);
|
|
1015
|
+
if (hours < 24)
|
|
1016
|
+
return `${hours}h ago`;
|
|
1017
|
+
const days = Math.floor(hours / 24);
|
|
1018
|
+
return `${days}d ago`;
|
|
1019
|
+
}
|
|
1020
|
+
getRecentWorkerSummary(limit = 4) {
|
|
1021
|
+
if (this.recentWorkerActivity.length === 0)
|
|
1022
|
+
return null;
|
|
1023
|
+
const seen = new Set();
|
|
1024
|
+
const lines = [];
|
|
1025
|
+
for (const event of this.recentWorkerActivity) {
|
|
1026
|
+
if (seen.has(event.id))
|
|
1027
|
+
continue;
|
|
1028
|
+
seen.add(event.id);
|
|
1029
|
+
const when = this.formatRelativeTime(event.endedAt ?? event.startedAt);
|
|
1030
|
+
const note = event.note ? ` — ${event.note}` : '';
|
|
1031
|
+
lines.push(`- ${event.task} (${event.status}, ${when})${note}`);
|
|
1032
|
+
if (lines.length >= limit)
|
|
1033
|
+
break;
|
|
1034
|
+
}
|
|
1035
|
+
return lines.length > 0 ? lines.join('\n') : null;
|
|
1036
|
+
}
|
|
1037
|
+
isStatusInquiry(message) {
|
|
1038
|
+
const lower = message.toLowerCase();
|
|
1039
|
+
if (!lower)
|
|
1040
|
+
return false;
|
|
1041
|
+
const patterns = [
|
|
1042
|
+
/\b(status|progress|queue|queued|pending)\b/,
|
|
1043
|
+
/\bwhat (are|were) you (doing|working on)\b/,
|
|
1044
|
+
/\bwhat happened\b/,
|
|
1045
|
+
/\bstuck\b/,
|
|
1046
|
+
/\btaking (so long|forever|too long)\b/,
|
|
1047
|
+
/\bwhy (is|are) (this|it) (taking|hung|stuck)\b/,
|
|
1048
|
+
];
|
|
1049
|
+
return patterns.some((pattern) => pattern.test(lower));
|
|
1050
|
+
}
|
|
1051
|
+
buildStatusReply() {
|
|
1052
|
+
const queueStatus = this.taskQueue.getStatus();
|
|
1053
|
+
const runningWorkers = this.getWorkerStatus().filter((worker) => worker.status === 'running');
|
|
1054
|
+
const recentWorkers = this.getRecentWorkerSummary(4);
|
|
1055
|
+
const recentTasks = this.taskQueue.getRecentTasks(3)
|
|
1056
|
+
.filter((task) => task.status !== 'pending')
|
|
1057
|
+
.map((task) => `- ${task.content.slice(0, 80)} (${task.status})`);
|
|
1058
|
+
const lines = [];
|
|
1059
|
+
if (runningWorkers.length > 0) {
|
|
1060
|
+
lines.push(`Active workers: ${runningWorkers.length}`);
|
|
1061
|
+
for (const worker of runningWorkers.slice(0, 3)) {
|
|
1062
|
+
lines.push(`- ${worker.task} (${worker.progress}% · ${worker.elapsed}s)`);
|
|
1063
|
+
}
|
|
1064
|
+
}
|
|
1065
|
+
else {
|
|
1066
|
+
lines.push('Active workers: none');
|
|
1067
|
+
}
|
|
1068
|
+
if (queueStatus.isProcessing || queueStatus.pendingCount > 0) {
|
|
1069
|
+
const current = queueStatus.currentTask?.content;
|
|
1070
|
+
lines.push(`Task queue: ${queueStatus.pendingCount} pending${queueStatus.isProcessing ? ' · processing' : ''}`);
|
|
1071
|
+
if (current) {
|
|
1072
|
+
lines.push(`- Current: ${current.slice(0, 100)}`);
|
|
1073
|
+
}
|
|
1074
|
+
}
|
|
1075
|
+
else {
|
|
1076
|
+
lines.push('Task queue: empty');
|
|
1077
|
+
}
|
|
1078
|
+
if (recentWorkers) {
|
|
1079
|
+
lines.push('Recent worker activity:');
|
|
1080
|
+
lines.push(recentWorkers);
|
|
1081
|
+
}
|
|
1082
|
+
if (recentTasks.length > 0) {
|
|
1083
|
+
lines.push('Recent task results:');
|
|
1084
|
+
lines.push(recentTasks.join('\n'));
|
|
1085
|
+
}
|
|
1086
|
+
return lines.join('\n');
|
|
1087
|
+
}
|
|
995
1088
|
/**
|
|
996
1089
|
* Check if verbose mode is enabled
|
|
997
1090
|
*/
|
|
@@ -1010,6 +1103,9 @@ export class MasterOrchestrator {
|
|
|
1010
1103
|
return slashResponse;
|
|
1011
1104
|
}
|
|
1012
1105
|
this.updateFileScope(cleanMessage);
|
|
1106
|
+
if (this.isStatusInquiry(cleanMessage)) {
|
|
1107
|
+
return this.buildStatusReply();
|
|
1108
|
+
}
|
|
1013
1109
|
const wantsTodoOrCal = this.hasTodoMutation(cleanMessage) || this.hasCalendarMutation(cleanMessage);
|
|
1014
1110
|
if (wantsTodoOrCal) {
|
|
1015
1111
|
this.attachmentContext = this.extractAttachmentContext(message);
|
|
@@ -1066,6 +1162,10 @@ ${hubContextStr}
|
|
|
1066
1162
|
if (fileScopeNote) {
|
|
1067
1163
|
systemWithContext += `\n\n${fileScopeNote}`;
|
|
1068
1164
|
}
|
|
1165
|
+
const recentWorkerSummary = this.getRecentWorkerSummary();
|
|
1166
|
+
if (recentWorkerSummary) {
|
|
1167
|
+
systemWithContext += `\n\nRECENT WORKER ACTIVITY (for accurate status updates):\n${recentWorkerSummary}`;
|
|
1168
|
+
}
|
|
1069
1169
|
// Add user message
|
|
1070
1170
|
const messages = [
|
|
1071
1171
|
...conversationHistory,
|
|
@@ -2336,6 +2436,17 @@ Unlike lia_plan (internal only), this creates a VISIBLE todo list that appears i
|
|
|
2336
2436
|
priority: input.priority,
|
|
2337
2437
|
workingDirectory: input.working_directory || fileScope.workingDir
|
|
2338
2438
|
});
|
|
2439
|
+
if (result.success && result.output) {
|
|
2440
|
+
const match = result.output.match(/Job ID:\s*(\S+)/i);
|
|
2441
|
+
if (match) {
|
|
2442
|
+
this.recordWorkerActivity({
|
|
2443
|
+
id: match[1],
|
|
2444
|
+
task: normalizedTask.slice(0, 200),
|
|
2445
|
+
status: 'running',
|
|
2446
|
+
startedAt: Date.now(),
|
|
2447
|
+
});
|
|
2448
|
+
}
|
|
2449
|
+
}
|
|
2339
2450
|
break;
|
|
2340
2451
|
}
|
|
2341
2452
|
case 'check_worker':
|
|
@@ -2349,6 +2460,16 @@ Unlike lia_plan (internal only), this creates a VISIBLE todo list that appears i
|
|
|
2349
2460
|
break;
|
|
2350
2461
|
case 'cancel_worker':
|
|
2351
2462
|
result = await this.workerTools.cancelWorker(input.job_id);
|
|
2463
|
+
if (result.success) {
|
|
2464
|
+
this.recordWorkerActivity({
|
|
2465
|
+
id: String(input.job_id || 'unknown'),
|
|
2466
|
+
task: 'Worker cancelled',
|
|
2467
|
+
status: 'cancelled',
|
|
2468
|
+
startedAt: Date.now(),
|
|
2469
|
+
endedAt: Date.now(),
|
|
2470
|
+
note: 'Cancelled by request'
|
|
2471
|
+
});
|
|
2472
|
+
}
|
|
2352
2473
|
break;
|
|
2353
2474
|
// Legacy delegate tool
|
|
2354
2475
|
case 'delegate_to_worker': {
|
|
@@ -2509,6 +2630,12 @@ Unlike lia_plan (internal only), this creates a VISIBLE todo list that appears i
|
|
|
2509
2630
|
estimatedTime,
|
|
2510
2631
|
workingDir: cwd
|
|
2511
2632
|
};
|
|
2633
|
+
this.recordWorkerActivity({
|
|
2634
|
+
id,
|
|
2635
|
+
task: job.task,
|
|
2636
|
+
status: 'running',
|
|
2637
|
+
startedAt: job.startTime
|
|
2638
|
+
});
|
|
2512
2639
|
// Escape single quotes in prompt for shell safety
|
|
2513
2640
|
const escapedPrompt = prompt.replace(/'/g, "'\\''");
|
|
2514
2641
|
const budget = resolveClaudeBudgetUsd();
|
|
@@ -2549,6 +2676,14 @@ Unlike lia_plan (internal only), this creates a VISIBLE todo list that appears i
|
|
|
2549
2676
|
job.endTime = Date.now();
|
|
2550
2677
|
child.kill('SIGTERM');
|
|
2551
2678
|
console.log(`[ORCHESTRATOR] Worker ${id} timed out`);
|
|
2679
|
+
this.recordWorkerActivity({
|
|
2680
|
+
id,
|
|
2681
|
+
task: job.task,
|
|
2682
|
+
status: 'timeout',
|
|
2683
|
+
startedAt: job.startTime,
|
|
2684
|
+
endedAt: job.endTime,
|
|
2685
|
+
note: 'Timed out after 5 minutes'
|
|
2686
|
+
});
|
|
2552
2687
|
if (this.workerResultCallback) {
|
|
2553
2688
|
this.workerResultCallback(id, `Worker timed out. Partial output: ${job.output.slice(-1000) || 'none'}`);
|
|
2554
2689
|
}
|
|
@@ -2586,6 +2721,14 @@ Unlike lia_plan (internal only), this creates a VISIBLE todo list that appears i
|
|
|
2586
2721
|
const status = code === 0 ? 'completed' : 'failed';
|
|
2587
2722
|
const filesCreated = assets.map(a => a.name);
|
|
2588
2723
|
logWorker(id, job.task, status, duration, filesCreated.length > 0 ? filesCreated : undefined);
|
|
2724
|
+
this.recordWorkerActivity({
|
|
2725
|
+
id,
|
|
2726
|
+
task: job.task,
|
|
2727
|
+
status,
|
|
2728
|
+
startedAt: job.startTime,
|
|
2729
|
+
endedAt: job.endTime,
|
|
2730
|
+
note: code === 0 ? undefined : `Exit code ${code ?? 'unknown'}`
|
|
2731
|
+
});
|
|
2589
2732
|
if (assets.length > 0) {
|
|
2590
2733
|
console.log(`[ORCHESTRATOR] Worker ${id} created ${assets.length} files: ${assets.map(a => a.name).join(', ')}`);
|
|
2591
2734
|
// Store in memory for gallery queries
|
|
@@ -2613,6 +2756,14 @@ Unlike lia_plan (internal only), this creates a VISIBLE todo list that appears i
|
|
|
2613
2756
|
job.status = 'failed';
|
|
2614
2757
|
job.endTime = Date.now();
|
|
2615
2758
|
console.error(`[ORCHESTRATOR] Worker ${id} error:`, err.message);
|
|
2759
|
+
this.recordWorkerActivity({
|
|
2760
|
+
id,
|
|
2761
|
+
task: job.task,
|
|
2762
|
+
status: 'failed',
|
|
2763
|
+
startedAt: job.startTime,
|
|
2764
|
+
endedAt: job.endTime,
|
|
2765
|
+
note: err.message
|
|
2766
|
+
});
|
|
2616
2767
|
if (this.workerResultCallback) {
|
|
2617
2768
|
this.workerResultCallback(id, `Worker error: ${err.message}`);
|
|
2618
2769
|
}
|