@northflare/runner 0.0.13 → 0.0.16
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/README.md +8 -5
- package/bin/northflare-runner +44 -16
- package/dist/components/claude-sdk-manager.d.ts +3 -3
- package/dist/components/claude-sdk-manager.d.ts.map +1 -1
- package/dist/components/claude-sdk-manager.js +80 -111
- package/dist/components/claude-sdk-manager.js.map +1 -1
- package/dist/components/codex-sdk-manager.d.ts +15 -6
- package/dist/components/codex-sdk-manager.d.ts.map +1 -1
- package/dist/components/codex-sdk-manager.js +128 -97
- package/dist/components/codex-sdk-manager.js.map +1 -1
- package/dist/components/enhanced-repository-manager.d.ts +2 -2
- package/dist/components/enhanced-repository-manager.d.ts.map +1 -1
- package/dist/components/enhanced-repository-manager.js +68 -75
- package/dist/components/enhanced-repository-manager.js.map +1 -1
- package/dist/components/message-handler-sse.d.ts +1 -1
- package/dist/components/message-handler-sse.d.ts.map +1 -1
- package/dist/components/message-handler-sse.js +205 -97
- package/dist/components/message-handler-sse.js.map +1 -1
- package/dist/components/{claude-manager.d.ts → northflare-agent-sdk-manager.d.ts} +17 -14
- package/dist/components/northflare-agent-sdk-manager.d.ts.map +1 -0
- package/dist/components/northflare-agent-sdk-manager.js +1456 -0
- package/dist/components/northflare-agent-sdk-manager.js.map +1 -0
- package/dist/components/repository-manager.d.ts +2 -2
- package/dist/components/repository-manager.d.ts.map +1 -1
- package/dist/components/repository-manager.js +34 -74
- package/dist/components/repository-manager.js.map +1 -1
- package/dist/index.d.ts +3 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +115 -79
- package/dist/index.js.map +1 -1
- package/dist/runner-sse.d.ts +22 -5
- package/dist/runner-sse.d.ts.map +1 -1
- package/dist/runner-sse.js +95 -74
- package/dist/runner-sse.js.map +1 -1
- package/dist/services/RunnerAPIClient.d.ts +1 -1
- package/dist/services/RunnerAPIClient.d.ts.map +1 -1
- package/dist/services/RunnerAPIClient.js +3 -7
- package/dist/services/RunnerAPIClient.js.map +1 -1
- package/dist/services/SSEClient.js +5 -9
- package/dist/services/SSEClient.js.map +1 -1
- package/dist/types/claude.d.ts +16 -2
- package/dist/types/claude.d.ts.map +1 -1
- package/dist/types/claude.js +1 -2
- package/dist/types/claude.js.map +1 -1
- package/dist/types/index.d.ts +5 -3
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/index.js +3 -19
- package/dist/types/index.js.map +1 -1
- package/dist/types/messages.js +1 -2
- package/dist/types/messages.js.map +1 -1
- package/dist/types/runner-interface.d.ts +8 -4
- package/dist/types/runner-interface.d.ts.map +1 -1
- package/dist/types/runner-interface.js +1 -2
- package/dist/types/runner-interface.js.map +1 -1
- package/dist/utils/StateManager.js +12 -19
- package/dist/utils/StateManager.js.map +1 -1
- package/dist/utils/config.d.ts +1 -1
- package/dist/utils/config.d.ts.map +1 -1
- package/dist/utils/config.js +19 -26
- package/dist/utils/config.js.map +1 -1
- package/dist/utils/console.js +3 -6
- package/dist/utils/console.js.map +1 -1
- package/dist/utils/debug.js +1 -4
- package/dist/utils/debug.js.map +1 -1
- package/dist/utils/expand-env.js +1 -4
- package/dist/utils/expand-env.js.map +1 -1
- package/dist/utils/inactivity-timeout.d.ts +19 -0
- package/dist/utils/inactivity-timeout.d.ts.map +1 -0
- package/dist/utils/inactivity-timeout.js +72 -0
- package/dist/utils/inactivity-timeout.js.map +1 -0
- package/dist/utils/logger.d.ts.map +1 -1
- package/dist/utils/logger.js +24 -35
- package/dist/utils/logger.js.map +1 -1
- package/dist/utils/model.d.ts +3 -1
- package/dist/utils/model.d.ts.map +1 -1
- package/dist/utils/model.js +18 -4
- package/dist/utils/model.js.map +1 -1
- package/dist/utils/status-line.d.ts +1 -0
- package/dist/utils/status-line.d.ts.map +1 -1
- package/dist/utils/status-line.js +25 -18
- package/dist/utils/status-line.js.map +1 -1
- package/dist/utils/tool-response-sanitizer.js +6 -10
- package/dist/utils/tool-response-sanitizer.js.map +1 -1
- package/lib/codex-sdk/dist/index.d.ts +1 -1
- package/lib/codex-sdk/dist/samples/basic_streaming.d.ts +3 -0
- package/lib/codex-sdk/dist/samples/basic_streaming.d.ts.map +1 -0
- package/lib/codex-sdk/dist/samples/basic_streaming.js +81 -0
- package/lib/codex-sdk/dist/samples/basic_streaming.js.map +1 -0
- package/lib/codex-sdk/dist/samples/helpers.d.ts +2 -0
- package/lib/codex-sdk/dist/samples/helpers.d.ts.map +1 -0
- package/lib/codex-sdk/dist/samples/helpers.js +6 -0
- package/lib/codex-sdk/dist/samples/helpers.js.map +1 -0
- package/lib/codex-sdk/dist/samples/structured_output.d.ts +3 -0
- package/lib/codex-sdk/dist/samples/structured_output.d.ts.map +1 -0
- package/lib/codex-sdk/dist/samples/structured_output.js +17 -0
- package/lib/codex-sdk/dist/samples/structured_output.js.map +1 -0
- package/lib/codex-sdk/dist/samples/structured_output_zod.d.ts +3 -0
- package/lib/codex-sdk/dist/samples/structured_output_zod.d.ts.map +1 -0
- package/lib/codex-sdk/dist/samples/structured_output_zod.js +16 -0
- package/lib/codex-sdk/dist/samples/structured_output_zod.js.map +1 -0
- package/lib/codex-sdk/dist/tsup.config.d.ts +3 -0
- package/lib/codex-sdk/dist/tsup.config.js +12 -0
- package/package.json +9 -4
- package/scripts/verify-openrouter-agent.ts +163 -0
- package/dist/collections/runner-messages.d.ts +0 -52
- package/dist/collections/runner-messages.d.ts.map +0 -1
- package/dist/collections/runner-messages.js +0 -161
- package/dist/collections/runner-messages.js.map +0 -1
- package/dist/components/claude-manager.d.ts.map +0 -1
- package/dist/components/claude-manager.js +0 -783
- package/dist/components/claude-manager.js.map +0 -1
- package/dist/components/message-handler.d.ts +0 -35
- package/dist/components/message-handler.d.ts.map +0 -1
- package/dist/components/message-handler.js +0 -689
- package/dist/components/message-handler.js.map +0 -1
- package/dist/runner.d.ts +0 -51
- package/dist/runner.d.ts.map +0 -1
- package/dist/runner.js +0 -530
- package/dist/runner.js.map +0 -1
|
@@ -1,689 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
/**
|
|
3
|
-
* MessageHandler - Processes incoming JSONRPC messages from the orchestrator via ElectricSQL collections
|
|
4
|
-
*/
|
|
5
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.MessageHandler = void 0;
|
|
7
|
-
const runner_messages_1 = require("../collections/runner-messages");
|
|
8
|
-
const status_line_1 = require("../utils/status-line");
|
|
9
|
-
const console_1 = require("../utils/console");
|
|
10
|
-
const logger_1 = require("../utils/logger");
|
|
11
|
-
const logger = (0, logger_1.createLogger)("MessageHandler");
|
|
12
|
-
class MessageHandler {
|
|
13
|
-
messagesCollection;
|
|
14
|
-
methodHandlers;
|
|
15
|
-
runner;
|
|
16
|
-
processingSubscription;
|
|
17
|
-
processedMessages = new Set();
|
|
18
|
-
constructor(runner) {
|
|
19
|
-
this.runner = runner;
|
|
20
|
-
this.methodHandlers = new Map();
|
|
21
|
-
// Don't initialize collection here - wait until after registration
|
|
22
|
-
this.registerHandlers();
|
|
23
|
-
}
|
|
24
|
-
// Initialize the message collection after registration
|
|
25
|
-
initializeCollection() {
|
|
26
|
-
console_1.console.log("MessageHandler: Initializing message collection");
|
|
27
|
-
if (process.env["DEBUG"] === "true") {
|
|
28
|
-
logger.debug("Initializing message collection", {
|
|
29
|
-
runnerId: this.runner.config_.runnerId,
|
|
30
|
-
runnerUid: this.runner.getRunnerUid(),
|
|
31
|
-
lastProcessedAt: this.runner.getLastProcessedAt()?.toISOString() || "null",
|
|
32
|
-
electricUrl: this.runner.config_.electricUrl
|
|
33
|
-
});
|
|
34
|
-
}
|
|
35
|
-
// Stop existing collection if one exists
|
|
36
|
-
if (this.messagesCollection) {
|
|
37
|
-
this.messagesCollection.stop();
|
|
38
|
-
}
|
|
39
|
-
// Create the collection with initial lastProcessedAt for ElectricSQL filtering
|
|
40
|
-
// We still filter in JavaScript too since lastProcessedAt changes during runtime
|
|
41
|
-
this.messagesCollection = (0, runner_messages_1.createRunnerMessagesCollection)(this.runner.config_, this.runner.getLastProcessedAt() // Initial filter + accurate logging
|
|
42
|
-
);
|
|
43
|
-
}
|
|
44
|
-
async startProcessing() {
|
|
45
|
-
console_1.console.log("MessageHandler: Starting message processing...");
|
|
46
|
-
if (!this.messagesCollection) {
|
|
47
|
-
// Initialize collection if not already done
|
|
48
|
-
this.initializeCollection();
|
|
49
|
-
}
|
|
50
|
-
if (process.env["DEBUG"] === "true") {
|
|
51
|
-
logger.debug("Starting message processing with reactive subscriptions", {
|
|
52
|
-
runnerUid: this.runner.getRunnerUid(),
|
|
53
|
-
isActiveRunner: this.runner.getIsActiveRunner(),
|
|
54
|
-
lastProcessedAt: this.runner.getLastProcessedAt()?.toISOString() || "null"
|
|
55
|
-
});
|
|
56
|
-
}
|
|
57
|
-
// Preload the collection to start sync immediately
|
|
58
|
-
if (this.messagesCollection?.preload) {
|
|
59
|
-
if (process.env["DEBUG"] === "true") {
|
|
60
|
-
logger.debug("Calling preload() to initiate collection sync");
|
|
61
|
-
}
|
|
62
|
-
await this.messagesCollection.preload();
|
|
63
|
-
}
|
|
64
|
-
// Process any existing messages immediately
|
|
65
|
-
this.processUnprocessedMessages();
|
|
66
|
-
// Subscribe to collection changes for reactive updates
|
|
67
|
-
if (this.messagesCollection) {
|
|
68
|
-
this.processingSubscription = this.messagesCollection.subscribe(() => {
|
|
69
|
-
if (process.env["DEBUG"] === "true") {
|
|
70
|
-
logger.debug("Collection subscription fired - new data available");
|
|
71
|
-
}
|
|
72
|
-
this.processUnprocessedMessages();
|
|
73
|
-
});
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
processUnprocessedMessages() {
|
|
77
|
-
if (!this.messagesCollection) {
|
|
78
|
-
return;
|
|
79
|
-
}
|
|
80
|
-
const messages = Array.from(this.messagesCollection.state?.values() || []);
|
|
81
|
-
// Always log collection state in debug mode
|
|
82
|
-
if (process.env["DEBUG"] === "true") {
|
|
83
|
-
logger.debug("Collection state check", {
|
|
84
|
-
hasState: !!this.messagesCollection.state,
|
|
85
|
-
totalMessages: messages.length,
|
|
86
|
-
collectionSize: this.messagesCollection.state?.size || 0,
|
|
87
|
-
runnerId: this.runner.config_.runnerId,
|
|
88
|
-
isActiveRunner: this.runner.getIsActiveRunner()
|
|
89
|
-
});
|
|
90
|
-
// Log ALL messages in the collection
|
|
91
|
-
if (messages.length > 0) {
|
|
92
|
-
messages.forEach((msg, index) => {
|
|
93
|
-
logger.debug(`Message ${index + 1}/${messages.length} in collection`, {
|
|
94
|
-
id: msg.id,
|
|
95
|
-
method: msg.payload?.method,
|
|
96
|
-
direction: msg.direction,
|
|
97
|
-
createdAt: msg.createdAt,
|
|
98
|
-
taskId: msg.taskId,
|
|
99
|
-
workspaceId: msg.workspaceId,
|
|
100
|
-
params: msg.payload?.params
|
|
101
|
-
});
|
|
102
|
-
});
|
|
103
|
-
}
|
|
104
|
-
}
|
|
105
|
-
const unprocessed = messages
|
|
106
|
-
.filter((msg) => msg.direction === "to_runner" && !this.processedMessages.has(msg.id))
|
|
107
|
-
.sort((a, b) => new Date(a.createdAt).getTime() - new Date(b.createdAt).getTime());
|
|
108
|
-
if (process.env["DEBUG"] === "true" && unprocessed.length > 0) {
|
|
109
|
-
logger.debug("Processing unprocessed messages", {
|
|
110
|
-
totalMessages: messages.length,
|
|
111
|
-
unprocessedCount: unprocessed.length,
|
|
112
|
-
messageIds: unprocessed.map(m => m.id)
|
|
113
|
-
});
|
|
114
|
-
}
|
|
115
|
-
unprocessed.forEach((msg) => this.processMessage(msg));
|
|
116
|
-
}
|
|
117
|
-
async stopProcessing() {
|
|
118
|
-
console_1.console.log("MessageHandler: Stopping message processing...");
|
|
119
|
-
// Unsubscribe from collection updates
|
|
120
|
-
if (this.processingSubscription) {
|
|
121
|
-
this.processingSubscription();
|
|
122
|
-
this.processingSubscription = undefined;
|
|
123
|
-
}
|
|
124
|
-
// Clear processed messages tracking
|
|
125
|
-
this.processedMessages.clear();
|
|
126
|
-
}
|
|
127
|
-
async processMessage(message) {
|
|
128
|
-
if (process.env["DEBUG"] === "true") {
|
|
129
|
-
logger.debug("processMessage called", {
|
|
130
|
-
messageId: message.id,
|
|
131
|
-
method: message.payload?.method,
|
|
132
|
-
direction: message.direction,
|
|
133
|
-
createdAt: message.createdAt
|
|
134
|
-
});
|
|
135
|
-
}
|
|
136
|
-
// Check if we should process this message based on ownership
|
|
137
|
-
if (!this.shouldProcessMessage(message)) {
|
|
138
|
-
return;
|
|
139
|
-
}
|
|
140
|
-
const { method, params } = message.payload;
|
|
141
|
-
if (!method) {
|
|
142
|
-
await this.sendError(message, "Missing method in message payload");
|
|
143
|
-
return;
|
|
144
|
-
}
|
|
145
|
-
const handler = this.methodHandlers.get(method);
|
|
146
|
-
if (!handler) {
|
|
147
|
-
await this.sendError(message, `Unknown method: ${method}`);
|
|
148
|
-
return;
|
|
149
|
-
}
|
|
150
|
-
if (process.env["DEBUG"] === "true") {
|
|
151
|
-
logger.debug("Processing message", {
|
|
152
|
-
messageId: message.id,
|
|
153
|
-
method: method,
|
|
154
|
-
taskId: message.taskId,
|
|
155
|
-
isActionMessage: this.isActionMessage(message)
|
|
156
|
-
});
|
|
157
|
-
}
|
|
158
|
-
try {
|
|
159
|
-
await handler(params, message);
|
|
160
|
-
await this.markProcessed(message.id);
|
|
161
|
-
// Acknowledge ALL messages to update lastProcessedAt
|
|
162
|
-
// This ensures the server knows which messages have been processed
|
|
163
|
-
await this.acknowledgeMessage(message);
|
|
164
|
-
if (process.env["DEBUG"] === "true") {
|
|
165
|
-
logger.debug("Message acknowledged", {
|
|
166
|
-
messageId: message.id,
|
|
167
|
-
method: method,
|
|
168
|
-
timestamp: message.createdAt,
|
|
169
|
-
wasActionMessage: this.isActionMessage(message)
|
|
170
|
-
});
|
|
171
|
-
}
|
|
172
|
-
}
|
|
173
|
-
catch (error) {
|
|
174
|
-
if (process.env["DEBUG"] === "true") {
|
|
175
|
-
logger.debug("Message processing error", {
|
|
176
|
-
messageId: message.id,
|
|
177
|
-
method: method,
|
|
178
|
-
error: error instanceof Error ? error.message : String(error)
|
|
179
|
-
});
|
|
180
|
-
}
|
|
181
|
-
await this.handleError(message, error);
|
|
182
|
-
}
|
|
183
|
-
}
|
|
184
|
-
shouldProcessMessage(message) {
|
|
185
|
-
const decision = (() => {
|
|
186
|
-
// Always process our own responses going to orchestrator
|
|
187
|
-
if (message.direction === 'to_orchestrator') {
|
|
188
|
-
return { shouldProcess: true, reason: "own response to orchestrator" };
|
|
189
|
-
}
|
|
190
|
-
// Filter by lastProcessedAt first (before checking active status)
|
|
191
|
-
const lastProcessedAt = this.runner.getLastProcessedAt();
|
|
192
|
-
if (lastProcessedAt && message.createdAt) {
|
|
193
|
-
const messageTime = new Date(message.createdAt);
|
|
194
|
-
if (messageTime <= lastProcessedAt) {
|
|
195
|
-
return { shouldProcess: false, reason: "message before lastProcessedAt" };
|
|
196
|
-
}
|
|
197
|
-
}
|
|
198
|
-
// Always process UID change messages (after time check)
|
|
199
|
-
if (message.payload?.method === 'runner.uid.changed') {
|
|
200
|
-
return { shouldProcess: true, reason: "UID change message" };
|
|
201
|
-
}
|
|
202
|
-
// If we're not the active runner
|
|
203
|
-
if (!this.runner.getIsActiveRunner()) {
|
|
204
|
-
// Only process if it's for a pre-handoff conversation by conversationId
|
|
205
|
-
const cid = message.conversationId || message.payload?.params?.conversationId;
|
|
206
|
-
if (cid && this.runner.getPreHandoffConversations().has(cid)) {
|
|
207
|
-
return { shouldProcess: true, reason: "pre-handoff conversation (by conversationId)" };
|
|
208
|
-
}
|
|
209
|
-
return { shouldProcess: false, reason: "not active runner" };
|
|
210
|
-
}
|
|
211
|
-
// We're active and message is after lastProcessedAt
|
|
212
|
-
return { shouldProcess: true, reason: "active runner, message after watermark" };
|
|
213
|
-
})();
|
|
214
|
-
if (process.env["DEBUG"] === "true") {
|
|
215
|
-
logger.debug("Message processing decision", {
|
|
216
|
-
messageId: message.id,
|
|
217
|
-
method: message.payload?.method,
|
|
218
|
-
shouldProcess: decision.shouldProcess,
|
|
219
|
-
reason: decision.reason,
|
|
220
|
-
runnerUid: this.runner.getRunnerUid(),
|
|
221
|
-
isActiveRunner: this.runner.getIsActiveRunner(),
|
|
222
|
-
lastProcessedAt: this.runner.getLastProcessedAt()?.toISOString() || "null",
|
|
223
|
-
messageCreatedAt: message.createdAt
|
|
224
|
-
});
|
|
225
|
-
}
|
|
226
|
-
return decision.shouldProcess;
|
|
227
|
-
}
|
|
228
|
-
isActionMessage(message) {
|
|
229
|
-
const actionMethods = [
|
|
230
|
-
'conversation.start',
|
|
231
|
-
'conversation.stop',
|
|
232
|
-
'conversation.resume',
|
|
233
|
-
'conversation.config',
|
|
234
|
-
'message.user'
|
|
235
|
-
];
|
|
236
|
-
return actionMethods.includes(message.payload?.method || '');
|
|
237
|
-
}
|
|
238
|
-
async acknowledgeMessage(message) {
|
|
239
|
-
const runnerId = this.runner.getRunnerId();
|
|
240
|
-
console_1.console.log(`[MessageHandler] Sending message.acknowledge:`, {
|
|
241
|
-
runnerId,
|
|
242
|
-
messageTimestamp: message.createdAt,
|
|
243
|
-
messageId: message.id,
|
|
244
|
-
method: message.payload?.method
|
|
245
|
-
});
|
|
246
|
-
await this.runner.notify('message.acknowledge', {
|
|
247
|
-
runnerId,
|
|
248
|
-
messageTimestamp: message.createdAt
|
|
249
|
-
});
|
|
250
|
-
console_1.console.log(`[MessageHandler] ✅ message.acknowledge sent successfully`);
|
|
251
|
-
}
|
|
252
|
-
async markProcessed(messageId) {
|
|
253
|
-
// Track processed messages internally
|
|
254
|
-
this.processedMessages.add(messageId);
|
|
255
|
-
// Note: We no longer update a processedAt field in the database
|
|
256
|
-
// Messages are tracked as processed only in memory during the runner session
|
|
257
|
-
}
|
|
258
|
-
async sendError(message, errorMessage) {
|
|
259
|
-
// Send error report with conversation object info if available
|
|
260
|
-
const conversationObjectType = message.conversationObjectType || (message.taskId ? "task" : undefined);
|
|
261
|
-
const conversationObjectId = message.conversationObjectId || message.taskId;
|
|
262
|
-
if (!conversationObjectId) {
|
|
263
|
-
console_1.console.error(`[MessageHandler] Cannot send error report - no conversationObjectId available. Error: ${errorMessage}`);
|
|
264
|
-
if (process.env["DEBUG"] === "true") {
|
|
265
|
-
logger.debug("Error without conversationObjectId", {
|
|
266
|
-
messageId: message.id,
|
|
267
|
-
method: message.payload?.method,
|
|
268
|
-
error: errorMessage,
|
|
269
|
-
runnerId: message.runnerId
|
|
270
|
-
});
|
|
271
|
-
}
|
|
272
|
-
return;
|
|
273
|
-
}
|
|
274
|
-
await this.runner.notify("error.report", {
|
|
275
|
-
conversationObjectType,
|
|
276
|
-
conversationObjectId,
|
|
277
|
-
messageId: message.id,
|
|
278
|
-
errorType: "method_error",
|
|
279
|
-
message: errorMessage,
|
|
280
|
-
details: {
|
|
281
|
-
originalMessage: message,
|
|
282
|
-
timestamp: new Date(),
|
|
283
|
-
},
|
|
284
|
-
});
|
|
285
|
-
}
|
|
286
|
-
async handleError(message, error) {
|
|
287
|
-
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
288
|
-
const errorStack = error instanceof Error ? error.stack : undefined;
|
|
289
|
-
// Send error report with conversation object info if available
|
|
290
|
-
const conversationObjectType = message.conversationObjectType || (message.taskId ? "task" : undefined);
|
|
291
|
-
const conversationObjectId = message.conversationObjectId || message.taskId;
|
|
292
|
-
if (!conversationObjectId) {
|
|
293
|
-
console_1.console.error(`[MessageHandler] Cannot send error report - no conversationObjectId available. Processing error: ${errorMessage}`);
|
|
294
|
-
if (process.env["DEBUG"] === "true") {
|
|
295
|
-
logger.debug("Processing error without conversationObjectId", {
|
|
296
|
-
messageId: message.id,
|
|
297
|
-
method: message.payload?.method,
|
|
298
|
-
error: errorMessage,
|
|
299
|
-
stack: errorStack,
|
|
300
|
-
runnerId: message.runnerId
|
|
301
|
-
});
|
|
302
|
-
}
|
|
303
|
-
return;
|
|
304
|
-
}
|
|
305
|
-
await this.runner.notify("error.report", {
|
|
306
|
-
conversationObjectType,
|
|
307
|
-
conversationObjectId,
|
|
308
|
-
messageId: message.id,
|
|
309
|
-
errorType: "processing_error",
|
|
310
|
-
message: errorMessage,
|
|
311
|
-
details: {
|
|
312
|
-
stack: errorStack,
|
|
313
|
-
originalMessage: message,
|
|
314
|
-
timestamp: new Date(),
|
|
315
|
-
},
|
|
316
|
-
});
|
|
317
|
-
}
|
|
318
|
-
registerHandlers() {
|
|
319
|
-
console_1.console.log("MessageHandler: Registering handlers...");
|
|
320
|
-
this.methodHandlers = new Map([
|
|
321
|
-
["conversation.start", this.handleConversationStart.bind(this)],
|
|
322
|
-
["conversation.stop", this.handleConversationStop.bind(this)],
|
|
323
|
-
["conversation.resume", this.handleConversationResume.bind(this)],
|
|
324
|
-
["conversation.config", this.handleConversationConfig.bind(this)],
|
|
325
|
-
["message.user", this.handleUserMessage.bind(this)],
|
|
326
|
-
["runner.uid.changed", this.handleUidChanged.bind(this)],
|
|
327
|
-
["git.operation", this.handleGitOperation.bind(this)],
|
|
328
|
-
["git.cleanup", this.handleGitCleanup.bind(this)],
|
|
329
|
-
]);
|
|
330
|
-
}
|
|
331
|
-
async handleConversationStart(params, message) {
|
|
332
|
-
const { conversationObjectType = message.conversationObjectType || "task", conversationObjectId = message.conversationObjectId || params.conversation?.objectId, config, initialMessages, conversation } = params;
|
|
333
|
-
// Validate required parameters
|
|
334
|
-
if (!config) {
|
|
335
|
-
throw new Error("Missing required parameter: config");
|
|
336
|
-
}
|
|
337
|
-
// Require a conversation object; if missing, try to fetch via conversationId on the message
|
|
338
|
-
let conversationData = conversation;
|
|
339
|
-
if (!conversationData) {
|
|
340
|
-
const cid = params.conversationId || message.conversationId;
|
|
341
|
-
if (!cid) {
|
|
342
|
-
throw new Error("Missing required conversation information: conversation object or conversationId");
|
|
343
|
-
}
|
|
344
|
-
conversationData = await this.runner.fetchConversationDetails(cid);
|
|
345
|
-
if (!conversationData) {
|
|
346
|
-
throw new Error(`Conversation ${cid} not found`);
|
|
347
|
-
}
|
|
348
|
-
}
|
|
349
|
-
const finalObjectType = conversationObjectType || conversationData.objectType;
|
|
350
|
-
const finalObjectId = conversationObjectId || conversationData.objectId;
|
|
351
|
-
if (!finalObjectId) {
|
|
352
|
-
throw new Error("Missing conversationObjectId");
|
|
353
|
-
}
|
|
354
|
-
// Debug log the config
|
|
355
|
-
console_1.console.log(`[MessageHandler] conversation.start config:`, {
|
|
356
|
-
conversationObjectId,
|
|
357
|
-
hasConfig: !!config,
|
|
358
|
-
hasRepository: !!config?.repository,
|
|
359
|
-
repositoryType: config?.repository?.type,
|
|
360
|
-
repositoryUrl: config?.repository?.url,
|
|
361
|
-
workspaceId: config?.workspaceId,
|
|
362
|
-
fullConfig: JSON.stringify(config, null, 2)
|
|
363
|
-
});
|
|
364
|
-
// Start the conversation with the provided/loaded conversation details
|
|
365
|
-
await this.runner.claudeManager_.startConversation(finalObjectType, finalObjectId, config, initialMessages || [], conversationData);
|
|
366
|
-
// Update status line
|
|
367
|
-
status_line_1.statusLineManager.updateActiveCount(this.runner.activeConversations_.size);
|
|
368
|
-
}
|
|
369
|
-
async handleConversationStop(params, message) {
|
|
370
|
-
// Require conversationId (present at message level); do not fall back to agentSessionId/taskId
|
|
371
|
-
const { conversationId = message.conversationId } = params;
|
|
372
|
-
console_1.console.log(`[MessageHandler] handleConversationStop called with:`, {
|
|
373
|
-
conversationId,
|
|
374
|
-
messageConversationId: message.conversationId,
|
|
375
|
-
agentSessionId: params?.agentSessionId,
|
|
376
|
-
taskId: params?.taskId,
|
|
377
|
-
params: JSON.stringify(params),
|
|
378
|
-
activeConversations: this.runner.activeConversations_.size,
|
|
379
|
-
conversationIds: Array.from(this.runner.activeConversations_.keys())
|
|
380
|
-
});
|
|
381
|
-
// Lookup strictly by conversationId
|
|
382
|
-
let context;
|
|
383
|
-
let targetConversationId;
|
|
384
|
-
if (conversationId) {
|
|
385
|
-
context = this.runner.getConversationContext(conversationId);
|
|
386
|
-
targetConversationId = conversationId;
|
|
387
|
-
}
|
|
388
|
-
console_1.console.log(`[MessageHandler] handleConversationStop lookup result:`, {
|
|
389
|
-
contextFound: !!context,
|
|
390
|
-
targetConversationId,
|
|
391
|
-
contextTaskId: context?.taskId,
|
|
392
|
-
contextAgentSessionId: context?.agentSessionId
|
|
393
|
-
});
|
|
394
|
-
// Check if we have any identifier to work with
|
|
395
|
-
if (!conversationId) {
|
|
396
|
-
throw new Error("Missing required parameter: conversationId");
|
|
397
|
-
}
|
|
398
|
-
if (context && targetConversationId) {
|
|
399
|
-
context.status = "stopping";
|
|
400
|
-
await this.runner.claudeManager_.stopConversation(context.agentSessionId, context);
|
|
401
|
-
context.status = "stopped";
|
|
402
|
-
this.runner.activeConversations_.delete(targetConversationId);
|
|
403
|
-
// Update status line
|
|
404
|
-
status_line_1.statusLineManager.updateActiveCount(this.runner.activeConversations_.size);
|
|
405
|
-
}
|
|
406
|
-
else {
|
|
407
|
-
// No conversation found - this is expected as conversations may have already ended
|
|
408
|
-
// or been cleaned up. Just log it and update status line.
|
|
409
|
-
console_1.console.log(`Conversation stop requested for ${conversationId} - conversation not found or already cleaned up`);
|
|
410
|
-
// If we have a targetConversationId, ensure it's removed from tracking
|
|
411
|
-
if (targetConversationId) {
|
|
412
|
-
this.runner.activeConversations_.delete(targetConversationId);
|
|
413
|
-
}
|
|
414
|
-
status_line_1.statusLineManager.updateActiveCount(this.runner.activeConversations_.size);
|
|
415
|
-
}
|
|
416
|
-
}
|
|
417
|
-
async handleConversationResume(params, message) {
|
|
418
|
-
const { conversationId = message.conversationId, conversation: resumeConversation, config, message: resumeMessage } = params;
|
|
419
|
-
const cid = params.conversationId || conversationId;
|
|
420
|
-
if (!cid) {
|
|
421
|
-
throw new Error("Missing required parameter: conversationId");
|
|
422
|
-
}
|
|
423
|
-
// Load conversation details if not provided
|
|
424
|
-
const conversationData = resumeConversation || (await this.runner.fetchConversationDetails(cid));
|
|
425
|
-
if (!conversationData) {
|
|
426
|
-
throw new Error(`Conversation ${cid} not found`);
|
|
427
|
-
}
|
|
428
|
-
const agentSessionId = conversationData.agentSessionId;
|
|
429
|
-
if (!agentSessionId) {
|
|
430
|
-
throw new Error("Cannot resume conversation without agentSessionId");
|
|
431
|
-
}
|
|
432
|
-
await this.runner.claudeManager_.resumeConversation(conversationData.objectType, conversationData.objectId, agentSessionId, config, conversationData, resumeMessage);
|
|
433
|
-
}
|
|
434
|
-
async handleConversationConfig(params, message) {
|
|
435
|
-
const { conversationId, model, permissionMode, config } = params;
|
|
436
|
-
console_1.console.log(`[MessageHandler] handleConversationConfig called with:`, {
|
|
437
|
-
conversationId,
|
|
438
|
-
model,
|
|
439
|
-
permissionMode,
|
|
440
|
-
hasConfig: !!config
|
|
441
|
-
});
|
|
442
|
-
// Find the active conversation by conversationId only
|
|
443
|
-
let context;
|
|
444
|
-
if (conversationId) {
|
|
445
|
-
context = this.runner.getConversationContext(conversationId);
|
|
446
|
-
}
|
|
447
|
-
if (!context) {
|
|
448
|
-
throw new Error(`No active conversation found for conversationId: ${conversationId}`);
|
|
449
|
-
}
|
|
450
|
-
// Validate required parameters
|
|
451
|
-
if (!model && !permissionMode) {
|
|
452
|
-
throw new Error("At least one of model or permissionMode must be provided");
|
|
453
|
-
}
|
|
454
|
-
// Update the config with new values
|
|
455
|
-
const newConfig = {
|
|
456
|
-
...context.config,
|
|
457
|
-
...(model && { model }),
|
|
458
|
-
...(permissionMode && { permissionMode }),
|
|
459
|
-
...config // Allow full config overrides if provided
|
|
460
|
-
};
|
|
461
|
-
console_1.console.log(`[MessageHandler] Stopping conversation ${context.conversationId} to apply new config`);
|
|
462
|
-
// Stop the current conversation
|
|
463
|
-
await this.runner.claudeManager_.stopConversation(context.agentSessionId, context);
|
|
464
|
-
// Remove from active conversations
|
|
465
|
-
this.runner.activeConversations_.delete(context.conversationId);
|
|
466
|
-
console_1.console.log(`[MessageHandler] Resuming conversation ${context.conversationId} with new config`);
|
|
467
|
-
// Resume with new config
|
|
468
|
-
await this.runner.claudeManager_.resumeConversation(context.conversationObjectType, context.conversationObjectId, context.agentSessionId, newConfig, {
|
|
469
|
-
id: context.conversationId,
|
|
470
|
-
objectType: context.conversationObjectType,
|
|
471
|
-
objectId: context.conversationObjectId,
|
|
472
|
-
model: newConfig.model,
|
|
473
|
-
globalInstructions: context.globalInstructions,
|
|
474
|
-
workspaceInstructions: context.workspaceInstructions,
|
|
475
|
-
permissionsMode: newConfig.permissionMode,
|
|
476
|
-
agentSessionId: context.agentSessionId
|
|
477
|
-
}, "<system-instructions>Configuration updated. Please continue with the new settings.</system-instructions>");
|
|
478
|
-
// Update status line
|
|
479
|
-
status_line_1.statusLineManager.updateActiveCount(this.runner.activeConversations_.size);
|
|
480
|
-
console_1.console.log(`[MessageHandler] Conversation ${context.conversationId} config updated successfully`);
|
|
481
|
-
}
|
|
482
|
-
async handleUserMessage(params, message) {
|
|
483
|
-
const { conversationId, content, config, conversationObjectType = message.conversationObjectType || "task", conversationObjectId = message.conversationObjectId } = params;
|
|
484
|
-
// Validate required parameters
|
|
485
|
-
if (!conversationId) {
|
|
486
|
-
throw new Error("Missing required parameter: conversationId");
|
|
487
|
-
}
|
|
488
|
-
if (!content) {
|
|
489
|
-
throw new Error("Missing required parameter: content");
|
|
490
|
-
}
|
|
491
|
-
await this.runner.claudeManager_.sendUserMessage(conversationId, content, config, conversationObjectType, conversationObjectId);
|
|
492
|
-
}
|
|
493
|
-
async handleUidChanged(params, _message) {
|
|
494
|
-
const { runnerUid, lastProcessedAt } = params;
|
|
495
|
-
console_1.console.log(`MessageHandler: Handling UID change notification - new UID: ${runnerUid}, lastProcessedAt: ${lastProcessedAt}`);
|
|
496
|
-
if (process.env["DEBUG"] === "true") {
|
|
497
|
-
logger.debug("UID change notification received", {
|
|
498
|
-
newUid: runnerUid,
|
|
499
|
-
currentUid: this.runner.getRunnerUid(),
|
|
500
|
-
newLastProcessedAt: lastProcessedAt,
|
|
501
|
-
currentLastProcessedAt: this.runner.getLastProcessedAt()?.toISOString() || "null",
|
|
502
|
-
wasActiveRunner: this.runner.getIsActiveRunner(),
|
|
503
|
-
activeConversations: this.runner.activeConversations_.size
|
|
504
|
-
});
|
|
505
|
-
}
|
|
506
|
-
// Check if this is an old UID change that we should ignore
|
|
507
|
-
const currentLastProcessedAt = this.runner.getLastProcessedAt();
|
|
508
|
-
if (currentLastProcessedAt && lastProcessedAt) {
|
|
509
|
-
const newTime = new Date(lastProcessedAt);
|
|
510
|
-
if (newTime < currentLastProcessedAt) {
|
|
511
|
-
console_1.console.log(`MessageHandler: Ignoring old UID change (${lastProcessedAt} < ${currentLastProcessedAt.toISOString()})`);
|
|
512
|
-
if (process.env["DEBUG"] === "true") {
|
|
513
|
-
logger.debug("Ignoring old UID change", {
|
|
514
|
-
newUid: runnerUid,
|
|
515
|
-
newLastProcessedAt: lastProcessedAt,
|
|
516
|
-
currentLastProcessedAt: currentLastProcessedAt.toISOString()
|
|
517
|
-
});
|
|
518
|
-
}
|
|
519
|
-
return;
|
|
520
|
-
}
|
|
521
|
-
}
|
|
522
|
-
if (runnerUid === this.runner.getRunnerUid()) {
|
|
523
|
-
// This is our UID - we're the active runner
|
|
524
|
-
console_1.console.log("MessageHandler: We are now the active runner");
|
|
525
|
-
this.runner.setIsActiveRunner(true);
|
|
526
|
-
this.runner.setLastProcessedAt(lastProcessedAt ? new Date(lastProcessedAt) : null);
|
|
527
|
-
if (process.env["DEBUG"] === "true") {
|
|
528
|
-
logger.debug("Runner activated as primary", {
|
|
529
|
-
runnerUid: runnerUid,
|
|
530
|
-
lastProcessedAt: lastProcessedAt,
|
|
531
|
-
electricUrl: this.runner.config_.electricUrl
|
|
532
|
-
});
|
|
533
|
-
}
|
|
534
|
-
// No need to reinitialize collection - just continue processing
|
|
535
|
-
// The collection is already initialized and will receive new messages
|
|
536
|
-
// Emit activation notification - wrap in try/catch to handle failures gracefully
|
|
537
|
-
try {
|
|
538
|
-
await this.runner.notify("runner.activate", {
|
|
539
|
-
runnerId: this.runner.getRunnerId(),
|
|
540
|
-
runnerUid: runnerUid
|
|
541
|
-
});
|
|
542
|
-
}
|
|
543
|
-
catch (error) {
|
|
544
|
-
console_1.console.error("Failed to send activation notification:", error);
|
|
545
|
-
if (process.env["DEBUG"] === "true") {
|
|
546
|
-
logger.debug("Activation notification failed", {
|
|
547
|
-
error: error instanceof Error ? error.message : String(error)
|
|
548
|
-
});
|
|
549
|
-
}
|
|
550
|
-
}
|
|
551
|
-
// Start processing messages from the lastProcessedAt point
|
|
552
|
-
console_1.console.log(`MessageHandler: Will process messages after ${lastProcessedAt || 'beginning'}`);
|
|
553
|
-
}
|
|
554
|
-
else {
|
|
555
|
-
// Different UID - we're being replaced
|
|
556
|
-
console_1.console.log(`MessageHandler: We are being replaced by runner with UID ${runnerUid}`);
|
|
557
|
-
this.runner.setIsActiveRunner(false);
|
|
558
|
-
// Remember which conversations were active before handoff (by conversationId)
|
|
559
|
-
for (const [conversationId, context] of this.runner.activeConversations_) {
|
|
560
|
-
if (context.status === 'active') {
|
|
561
|
-
this.runner.getPreHandoffConversations().add(conversationId);
|
|
562
|
-
}
|
|
563
|
-
}
|
|
564
|
-
if (process.env["DEBUG"] === "true") {
|
|
565
|
-
logger.debug("Runner deactivated - being replaced", {
|
|
566
|
-
newRunnerUid: runnerUid,
|
|
567
|
-
ourUid: this.runner.getRunnerUid(),
|
|
568
|
-
preHandoffConversations: Array.from(this.runner.getPreHandoffConversations()),
|
|
569
|
-
activeConversationsCount: this.runner.getPreHandoffConversations().size
|
|
570
|
-
});
|
|
571
|
-
}
|
|
572
|
-
console_1.console.log(`MessageHandler: Will complete ${this.runner.getPreHandoffConversations().size} active conversations`);
|
|
573
|
-
// Emit deactivation notification - wrap in try/catch to handle failures gracefully
|
|
574
|
-
try {
|
|
575
|
-
await this.runner.notify("runner.deactivate", {
|
|
576
|
-
runnerId: this.runner.getRunnerId(),
|
|
577
|
-
runnerUid: this.runner.getRunnerUid(),
|
|
578
|
-
activeConversations: this.runner.getPreHandoffConversations().size
|
|
579
|
-
});
|
|
580
|
-
}
|
|
581
|
-
catch (error) {
|
|
582
|
-
console_1.console.error("Failed to send deactivation notification:", error);
|
|
583
|
-
if (process.env["DEBUG"] === "true") {
|
|
584
|
-
logger.debug("Deactivation notification failed", {
|
|
585
|
-
error: error instanceof Error ? error.message : String(error)
|
|
586
|
-
});
|
|
587
|
-
}
|
|
588
|
-
}
|
|
589
|
-
}
|
|
590
|
-
}
|
|
591
|
-
async handleGitOperation(params, message) {
|
|
592
|
-
const { taskId, operation, params: opParams } = params;
|
|
593
|
-
if (!taskId || !operation) {
|
|
594
|
-
throw new Error("Missing required parameters: taskId and operation");
|
|
595
|
-
}
|
|
596
|
-
console_1.console.log(`MessageHandler: Handling Git operation ${operation} for task ${taskId}`);
|
|
597
|
-
const repoManager = this.runner.repositoryManager_;
|
|
598
|
-
try {
|
|
599
|
-
switch (operation) {
|
|
600
|
-
case "stage":
|
|
601
|
-
await repoManager.stageAll(taskId);
|
|
602
|
-
await this.sendGitStateUpdate(taskId);
|
|
603
|
-
break;
|
|
604
|
-
case "commit":
|
|
605
|
-
if (!opParams?.message) {
|
|
606
|
-
throw new Error("Commit message is required");
|
|
607
|
-
}
|
|
608
|
-
const commitHash = await repoManager.commit(taskId, opParams.message, opParams.author);
|
|
609
|
-
await this.recordGitOperation(taskId, "commit", "succeeded", { commitHash });
|
|
610
|
-
await this.sendGitStateUpdate(taskId);
|
|
611
|
-
break;
|
|
612
|
-
case "push":
|
|
613
|
-
// TODO: Implement push operation
|
|
614
|
-
console_1.console.log("Push operation not yet implemented");
|
|
615
|
-
break;
|
|
616
|
-
case "rebase":
|
|
617
|
-
if (!opParams?.targetBranch) {
|
|
618
|
-
throw new Error("Target branch is required for rebase");
|
|
619
|
-
}
|
|
620
|
-
const rebaseResult = await repoManager.rebaseTask(taskId, opParams.targetBranch);
|
|
621
|
-
await this.recordGitOperation(taskId, "rebase", rebaseResult.success ? "succeeded" : "failed", rebaseResult);
|
|
622
|
-
await this.sendGitStateUpdate(taskId);
|
|
623
|
-
break;
|
|
624
|
-
case "merge":
|
|
625
|
-
if (!opParams?.targetBranch) {
|
|
626
|
-
throw new Error("Target branch is required for merge");
|
|
627
|
-
}
|
|
628
|
-
const mergeResult = await repoManager.mergeTask(taskId, opParams.targetBranch, opParams.mode);
|
|
629
|
-
await this.recordGitOperation(taskId, "merge", mergeResult.success ? "succeeded" : "failed", mergeResult);
|
|
630
|
-
await this.sendGitStateUpdate(taskId);
|
|
631
|
-
break;
|
|
632
|
-
default:
|
|
633
|
-
throw new Error(`Unknown Git operation: ${operation}`);
|
|
634
|
-
}
|
|
635
|
-
}
|
|
636
|
-
catch (error) {
|
|
637
|
-
console_1.console.error(`Git operation ${operation} failed for task ${taskId}:`, error);
|
|
638
|
-
await this.recordGitOperation(taskId, operation, "failed", { error: error instanceof Error ? error.message : String(error) });
|
|
639
|
-
throw error;
|
|
640
|
-
}
|
|
641
|
-
}
|
|
642
|
-
async handleGitCleanup(params, message) {
|
|
643
|
-
const { taskId, preserveBranch = false } = params;
|
|
644
|
-
if (!taskId) {
|
|
645
|
-
throw new Error("Missing required parameter: taskId");
|
|
646
|
-
}
|
|
647
|
-
console_1.console.log(`MessageHandler: Cleaning up Git worktree for task ${taskId}`);
|
|
648
|
-
const repoManager = this.runner.repositoryManager_;
|
|
649
|
-
try {
|
|
650
|
-
await repoManager.removeTaskWorktree(taskId, { preserveBranch });
|
|
651
|
-
console_1.console.log(`Successfully cleaned up worktree for task ${taskId}`);
|
|
652
|
-
}
|
|
653
|
-
catch (error) {
|
|
654
|
-
console_1.console.error(`Failed to clean up worktree for task ${taskId}:`, error);
|
|
655
|
-
throw error;
|
|
656
|
-
}
|
|
657
|
-
}
|
|
658
|
-
async sendGitStateUpdate(taskId) {
|
|
659
|
-
const repoManager = this.runner.repositoryManager_;
|
|
660
|
-
const gitState = await repoManager.getTaskState(taskId);
|
|
661
|
-
if (!gitState) {
|
|
662
|
-
console_1.console.error(`No Git state found for task ${taskId}`);
|
|
663
|
-
return;
|
|
664
|
-
}
|
|
665
|
-
// Send state update to orchestrator
|
|
666
|
-
await this.runner.notify("git.state.update", {
|
|
667
|
-
taskId,
|
|
668
|
-
state: {
|
|
669
|
-
branch: gitState.branch,
|
|
670
|
-
commit: gitState.lastCommit || "",
|
|
671
|
-
isDirty: false, // TODO: Check actual dirty state
|
|
672
|
-
ahead: 0, // TODO: Calculate ahead/behind
|
|
673
|
-
behind: 0,
|
|
674
|
-
},
|
|
675
|
-
});
|
|
676
|
-
}
|
|
677
|
-
async recordGitOperation(taskId, operation, status, details) {
|
|
678
|
-
// Send operation record to orchestrator
|
|
679
|
-
await this.runner.notify("git.operation.record", {
|
|
680
|
-
taskId,
|
|
681
|
-
operation,
|
|
682
|
-
status,
|
|
683
|
-
details,
|
|
684
|
-
timestamp: new Date(),
|
|
685
|
-
});
|
|
686
|
-
}
|
|
687
|
-
}
|
|
688
|
-
exports.MessageHandler = MessageHandler;
|
|
689
|
-
//# sourceMappingURL=message-handler.js.map
|