@siftd/connect-agent 0.2.0 → 0.2.3
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/agent.js +120 -26
- package/dist/api.d.ts +1 -0
- package/dist/cli.js +3 -1
- package/dist/config.d.ts +12 -0
- package/dist/config.js +25 -4
- package/dist/core/system-indexer.d.ts +65 -0
- package/dist/core/system-indexer.js +354 -0
- package/dist/genesis/index.d.ts +56 -0
- package/dist/genesis/index.js +71 -0
- package/dist/genesis/system-knowledge.json +62 -0
- package/dist/genesis/tool-patterns.json +88 -0
- package/dist/heartbeat.d.ts +32 -0
- package/dist/heartbeat.js +166 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/orchestrator.d.ts +39 -2
- package/dist/orchestrator.js +547 -78
- package/dist/tools/bash.d.ts +18 -0
- package/dist/tools/bash.js +85 -0
- package/dist/tools/index.d.ts +8 -0
- package/dist/tools/index.js +7 -0
- package/dist/tools/web.d.ts +38 -0
- package/dist/tools/web.js +284 -0
- package/dist/tools/worker.d.ts +36 -0
- package/dist/tools/worker.js +149 -0
- package/dist/websocket.d.ts +73 -0
- package/dist/websocket.js +243 -0
- package/dist/workers/manager.d.ts +62 -0
- package/dist/workers/manager.js +270 -0
- package/dist/workers/types.d.ts +31 -0
- package/dist/workers/types.js +10 -0
- package/package.json +5 -3
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Runner Heartbeat Module
|
|
3
|
+
*
|
|
4
|
+
* Sends periodic heartbeats to the Connect server to maintain presence.
|
|
5
|
+
* This is what makes a runner "connected" - NOT the pairing token.
|
|
6
|
+
*
|
|
7
|
+
* Both local and VM runners use this same module.
|
|
8
|
+
*/
|
|
9
|
+
import { hostname } from 'os';
|
|
10
|
+
import { createHash } from 'crypto';
|
|
11
|
+
import { getServerUrl, getAgentToken, getUserId, isCloudMode } from './config.js';
|
|
12
|
+
const HEARTBEAT_INTERVAL = 10000; // 10 seconds
|
|
13
|
+
const VERSION = '0.2.3'; // Should match package.json
|
|
14
|
+
const state = {
|
|
15
|
+
intervalId: null,
|
|
16
|
+
runnerId: null,
|
|
17
|
+
isRunning: false,
|
|
18
|
+
lastSuccess: null,
|
|
19
|
+
consecutiveFailures: 0,
|
|
20
|
+
};
|
|
21
|
+
/**
|
|
22
|
+
* Generate a stable runner ID based on machine characteristics
|
|
23
|
+
* Format: local:<hash> or vm:<deploymentId>
|
|
24
|
+
*/
|
|
25
|
+
function generateRunnerId(runnerType) {
|
|
26
|
+
if (runnerType === 'vm') {
|
|
27
|
+
// For VM, use deployment ID from env or generate from container ID
|
|
28
|
+
const deploymentId = process.env.RAILWAY_DEPLOYMENT_ID
|
|
29
|
+
|| process.env.FLY_ALLOC_ID
|
|
30
|
+
|| process.env.CONTAINER_ID
|
|
31
|
+
|| `vm-${createHash('sha256').update(hostname() + process.pid).digest('hex').substring(0, 8)}`;
|
|
32
|
+
return `vm:${deploymentId}`;
|
|
33
|
+
}
|
|
34
|
+
// For local, create a stable hash from machine characteristics
|
|
35
|
+
const machineId = createHash('sha256')
|
|
36
|
+
.update(hostname())
|
|
37
|
+
.update(process.env.USER || 'unknown')
|
|
38
|
+
.update(process.env.HOME || '/tmp')
|
|
39
|
+
.digest('hex')
|
|
40
|
+
.substring(0, 12);
|
|
41
|
+
return `local:${machineId}`;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Get the capabilities this runner supports
|
|
45
|
+
*/
|
|
46
|
+
function getCapabilities(customCapabilities) {
|
|
47
|
+
const capabilities = new Set();
|
|
48
|
+
// Base capabilities
|
|
49
|
+
capabilities.add('claude-cli');
|
|
50
|
+
capabilities.add('bash');
|
|
51
|
+
capabilities.add('filesystem');
|
|
52
|
+
// Check for common tools
|
|
53
|
+
if (process.env.ANTHROPIC_API_KEY) {
|
|
54
|
+
capabilities.add('orchestrator');
|
|
55
|
+
}
|
|
56
|
+
// Cloud mode has different capabilities
|
|
57
|
+
if (isCloudMode()) {
|
|
58
|
+
capabilities.add('cloud-persistent');
|
|
59
|
+
}
|
|
60
|
+
else {
|
|
61
|
+
capabilities.add('local-storage');
|
|
62
|
+
}
|
|
63
|
+
// Add custom capabilities
|
|
64
|
+
if (customCapabilities) {
|
|
65
|
+
customCapabilities.forEach(cap => capabilities.add(cap));
|
|
66
|
+
}
|
|
67
|
+
return Array.from(capabilities);
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Send a single heartbeat to the server
|
|
71
|
+
*/
|
|
72
|
+
async function sendHeartbeat(config) {
|
|
73
|
+
const serverUrl = getServerUrl();
|
|
74
|
+
const agentToken = getAgentToken();
|
|
75
|
+
const userId = getUserId();
|
|
76
|
+
if (!agentToken || !userId) {
|
|
77
|
+
console.error('[HEARTBEAT] No agent token or userId configured');
|
|
78
|
+
return false;
|
|
79
|
+
}
|
|
80
|
+
if (!state.runnerId) {
|
|
81
|
+
state.runnerId = generateRunnerId(config.runnerType);
|
|
82
|
+
}
|
|
83
|
+
const payload = {
|
|
84
|
+
userId,
|
|
85
|
+
runnerId: state.runnerId,
|
|
86
|
+
runnerType: config.runnerType,
|
|
87
|
+
capabilities: getCapabilities(config.capabilities),
|
|
88
|
+
version: VERSION,
|
|
89
|
+
hostname: hostname(),
|
|
90
|
+
setActive: state.consecutiveFailures === 0 && !state.lastSuccess, // Set active on first successful heartbeat
|
|
91
|
+
};
|
|
92
|
+
try {
|
|
93
|
+
const response = await fetch(`${serverUrl}/api/agent/heartbeat`, {
|
|
94
|
+
method: 'POST',
|
|
95
|
+
headers: {
|
|
96
|
+
'Content-Type': 'application/json',
|
|
97
|
+
'Authorization': `Bearer ${agentToken}`,
|
|
98
|
+
},
|
|
99
|
+
body: JSON.stringify(payload),
|
|
100
|
+
});
|
|
101
|
+
if (!response.ok) {
|
|
102
|
+
const error = await response.json().catch(() => ({ error: 'Unknown error' }));
|
|
103
|
+
throw new Error(error.error || `HTTP ${response.status}`);
|
|
104
|
+
}
|
|
105
|
+
// Success
|
|
106
|
+
state.lastSuccess = new Date();
|
|
107
|
+
state.consecutiveFailures = 0;
|
|
108
|
+
config.onSuccess?.();
|
|
109
|
+
return true;
|
|
110
|
+
}
|
|
111
|
+
catch (error) {
|
|
112
|
+
state.consecutiveFailures++;
|
|
113
|
+
const err = error instanceof Error ? error : new Error(String(error));
|
|
114
|
+
// Only log every 3rd failure to avoid spam
|
|
115
|
+
if (state.consecutiveFailures % 3 === 1) {
|
|
116
|
+
console.error(`[HEARTBEAT] Failed (${state.consecutiveFailures}x): ${err.message}`);
|
|
117
|
+
}
|
|
118
|
+
config.onError?.(err);
|
|
119
|
+
return false;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* Start the heartbeat loop
|
|
124
|
+
*/
|
|
125
|
+
export function startHeartbeat(config) {
|
|
126
|
+
if (state.isRunning) {
|
|
127
|
+
console.log('[HEARTBEAT] Already running');
|
|
128
|
+
return;
|
|
129
|
+
}
|
|
130
|
+
state.runnerId = generateRunnerId(config.runnerType);
|
|
131
|
+
state.isRunning = true;
|
|
132
|
+
state.consecutiveFailures = 0;
|
|
133
|
+
console.log(`[HEARTBEAT] Starting (${config.runnerType} runner: ${state.runnerId})`);
|
|
134
|
+
// Send initial heartbeat immediately
|
|
135
|
+
sendHeartbeat(config).then(success => {
|
|
136
|
+
if (success) {
|
|
137
|
+
console.log('[HEARTBEAT] Initial heartbeat sent successfully');
|
|
138
|
+
}
|
|
139
|
+
});
|
|
140
|
+
// Then send every HEARTBEAT_INTERVAL
|
|
141
|
+
state.intervalId = setInterval(() => {
|
|
142
|
+
sendHeartbeat(config);
|
|
143
|
+
}, HEARTBEAT_INTERVAL);
|
|
144
|
+
}
|
|
145
|
+
/**
|
|
146
|
+
* Stop the heartbeat loop
|
|
147
|
+
*/
|
|
148
|
+
export function stopHeartbeat() {
|
|
149
|
+
if (state.intervalId) {
|
|
150
|
+
clearInterval(state.intervalId);
|
|
151
|
+
state.intervalId = null;
|
|
152
|
+
}
|
|
153
|
+
state.isRunning = false;
|
|
154
|
+
console.log('[HEARTBEAT] Stopped');
|
|
155
|
+
}
|
|
156
|
+
/**
|
|
157
|
+
* Get current heartbeat state (for diagnostics)
|
|
158
|
+
*/
|
|
159
|
+
export function getHeartbeatState() {
|
|
160
|
+
return {
|
|
161
|
+
isRunning: state.isRunning,
|
|
162
|
+
runnerId: state.runnerId,
|
|
163
|
+
lastSuccess: state.lastSuccess,
|
|
164
|
+
consecutiveFailures: state.consecutiveFailures,
|
|
165
|
+
};
|
|
166
|
+
}
|
package/dist/index.d.ts
CHANGED
package/dist/index.js
CHANGED
package/dist/orchestrator.d.ts
CHANGED
|
@@ -12,10 +12,17 @@ export declare class MasterOrchestrator {
|
|
|
12
12
|
private maxTokens;
|
|
13
13
|
private memory;
|
|
14
14
|
private scheduler;
|
|
15
|
+
private indexer;
|
|
15
16
|
private jobs;
|
|
16
17
|
private jobCounter;
|
|
17
18
|
private userId;
|
|
18
19
|
private workspaceDir;
|
|
20
|
+
private claudePath;
|
|
21
|
+
private initialized;
|
|
22
|
+
private bashTool;
|
|
23
|
+
private webTools;
|
|
24
|
+
private workerTools;
|
|
25
|
+
private verboseMode;
|
|
19
26
|
constructor(options: {
|
|
20
27
|
apiKey: string;
|
|
21
28
|
userId: string;
|
|
@@ -24,10 +31,27 @@ export declare class MasterOrchestrator {
|
|
|
24
31
|
maxTokens?: number;
|
|
25
32
|
voyageApiKey?: string;
|
|
26
33
|
});
|
|
34
|
+
/**
|
|
35
|
+
* Initialize the orchestrator - indexes filesystem on first call
|
|
36
|
+
*/
|
|
37
|
+
initialize(): Promise<void>;
|
|
38
|
+
/**
|
|
39
|
+
* Find the claude binary path
|
|
40
|
+
*/
|
|
41
|
+
private findClaudeBinary;
|
|
42
|
+
/**
|
|
43
|
+
* Handle slash commands
|
|
44
|
+
*/
|
|
45
|
+
private handleSlashCommand;
|
|
46
|
+
/**
|
|
47
|
+
* Check if verbose mode is enabled
|
|
48
|
+
*/
|
|
49
|
+
isVerbose(): boolean;
|
|
27
50
|
/**
|
|
28
51
|
* Process a user message
|
|
52
|
+
* @param apiKey Optional per-request API key (overrides default)
|
|
29
53
|
*/
|
|
30
|
-
processMessage(message: string, conversationHistory?: MessageParam[], sendMessage?: MessageSender): Promise<string>;
|
|
54
|
+
processMessage(message: string, conversationHistory?: MessageParam[], sendMessage?: MessageSender, apiKey?: string): Promise<string>;
|
|
31
55
|
/**
|
|
32
56
|
* Get relevant memory context for a message
|
|
33
57
|
*/
|
|
@@ -38,6 +62,7 @@ export declare class MasterOrchestrator {
|
|
|
38
62
|
private autoRemember;
|
|
39
63
|
/**
|
|
40
64
|
* Run the agentic loop
|
|
65
|
+
* @param apiKey Optional per-request API key (creates temporary client)
|
|
41
66
|
*/
|
|
42
67
|
private runAgentLoop;
|
|
43
68
|
/**
|
|
@@ -49,7 +74,7 @@ export declare class MasterOrchestrator {
|
|
|
49
74
|
*/
|
|
50
75
|
private processToolCalls;
|
|
51
76
|
/**
|
|
52
|
-
* Delegate task to Claude Code CLI worker
|
|
77
|
+
* Delegate task to Claude Code CLI worker with retry logic
|
|
53
78
|
*/
|
|
54
79
|
private delegateToWorker;
|
|
55
80
|
/**
|
|
@@ -72,6 +97,18 @@ export declare class MasterOrchestrator {
|
|
|
72
97
|
* Execute memory stats tool
|
|
73
98
|
*/
|
|
74
99
|
private executeMemoryStats;
|
|
100
|
+
/**
|
|
101
|
+
* Open a URL in the user's default browser
|
|
102
|
+
*/
|
|
103
|
+
private executeOpenBrowser;
|
|
104
|
+
/**
|
|
105
|
+
* Start a persistent HTTP server
|
|
106
|
+
*/
|
|
107
|
+
private executeStartServer;
|
|
108
|
+
/**
|
|
109
|
+
* Stop a running server on a port
|
|
110
|
+
*/
|
|
111
|
+
private executeStopServer;
|
|
75
112
|
/**
|
|
76
113
|
* Format tool preview for user
|
|
77
114
|
*/
|