@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,17 +1,14 @@
|
|
|
1
|
-
"use strict";
|
|
2
1
|
/**
|
|
3
2
|
* MessageHandler - Processes incoming JSONRPC messages from SSE events
|
|
4
3
|
*/
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
const
|
|
12
|
-
|
|
13
|
-
const logger = (0, logger_1.createLogger)("MessageHandler");
|
|
14
|
-
class MessageHandler {
|
|
4
|
+
import { SSEClient } from '../services/SSEClient.js';
|
|
5
|
+
import { RunnerAPIClient } from '../services/RunnerAPIClient.js';
|
|
6
|
+
import { statusLineManager } from '../utils/status-line.js';
|
|
7
|
+
import { console } from '../utils/console.js';
|
|
8
|
+
import { createLogger } from '../utils/logger.js';
|
|
9
|
+
import { isRunnerDebugEnabled } from '../utils/debug.js';
|
|
10
|
+
const logger = createLogger("MessageHandler");
|
|
11
|
+
export class MessageHandler {
|
|
15
12
|
methodHandlers;
|
|
16
13
|
runner;
|
|
17
14
|
processedMessages = new Set();
|
|
@@ -21,11 +18,11 @@ class MessageHandler {
|
|
|
21
18
|
constructor(runner) {
|
|
22
19
|
this.runner = runner;
|
|
23
20
|
this.methodHandlers = new Map();
|
|
24
|
-
this.apiClient = new
|
|
21
|
+
this.apiClient = new RunnerAPIClient(runner.config_);
|
|
25
22
|
this.registerHandlers();
|
|
26
23
|
}
|
|
27
24
|
async startProcessing() {
|
|
28
|
-
|
|
25
|
+
console.log("MessageHandler: Starting message processing with SSE...");
|
|
29
26
|
if (this.isProcessing) {
|
|
30
27
|
logger.warn("Message processing already started");
|
|
31
28
|
return;
|
|
@@ -42,7 +39,7 @@ class MessageHandler {
|
|
|
42
39
|
await this.connectSSE();
|
|
43
40
|
}
|
|
44
41
|
async stopProcessing() {
|
|
45
|
-
|
|
42
|
+
console.log("MessageHandler: Stopping message processing...");
|
|
46
43
|
this.isProcessing = false;
|
|
47
44
|
// Stop SSE client
|
|
48
45
|
if (this.sseClient) {
|
|
@@ -61,21 +58,21 @@ class MessageHandler {
|
|
|
61
58
|
logger.debug("No lastProcessedAt timestamp, skipping catch-up");
|
|
62
59
|
return;
|
|
63
60
|
}
|
|
64
|
-
|
|
61
|
+
console.log(`MessageHandler: Catching up on messages since ${lastProcessedAt.toISOString()}`);
|
|
65
62
|
try {
|
|
66
63
|
const messages = await this.apiClient.fetchMissedMessages({
|
|
67
64
|
since: lastProcessedAt,
|
|
68
65
|
limit: 1000,
|
|
69
66
|
});
|
|
70
67
|
if (messages.length > 0) {
|
|
71
|
-
|
|
68
|
+
console.log(`MessageHandler: Processing ${messages.length} missed messages`);
|
|
72
69
|
// Process messages in order
|
|
73
70
|
for (const message of messages) {
|
|
74
71
|
await this.processMessage(message);
|
|
75
72
|
}
|
|
76
73
|
}
|
|
77
74
|
else {
|
|
78
|
-
|
|
75
|
+
console.log("MessageHandler: No missed messages to process");
|
|
79
76
|
}
|
|
80
77
|
}
|
|
81
78
|
catch (error) {
|
|
@@ -95,8 +92,8 @@ class MessageHandler {
|
|
|
95
92
|
if (!token) {
|
|
96
93
|
throw new Error("Missing NORTHFLARE_RUNNER_TOKEN");
|
|
97
94
|
}
|
|
98
|
-
|
|
99
|
-
this.sseClient = new
|
|
95
|
+
console.log("MessageHandler: Connecting to SSE endpoint...");
|
|
96
|
+
this.sseClient = new SSEClient({
|
|
100
97
|
url: `${this.runner.config_.orchestratorUrl}/api/runner-events`,
|
|
101
98
|
runnerId,
|
|
102
99
|
token,
|
|
@@ -105,10 +102,10 @@ class MessageHandler {
|
|
|
105
102
|
logger.error("SSE connection error:", error);
|
|
106
103
|
},
|
|
107
104
|
onConnect: () => {
|
|
108
|
-
|
|
105
|
+
console.log("MessageHandler: SSE connection established");
|
|
109
106
|
},
|
|
110
107
|
onDisconnect: () => {
|
|
111
|
-
|
|
108
|
+
console.log("MessageHandler: SSE connection closed");
|
|
112
109
|
},
|
|
113
110
|
reconnectInterval: 1000,
|
|
114
111
|
maxReconnectInterval: 30000,
|
|
@@ -124,7 +121,7 @@ class MessageHandler {
|
|
|
124
121
|
async handleSSEEvent(event) {
|
|
125
122
|
if (event.type === "runner.message") {
|
|
126
123
|
const message = event.data;
|
|
127
|
-
if (
|
|
124
|
+
if (isRunnerDebugEnabled()) {
|
|
128
125
|
logger.debug("Received SSE event", {
|
|
129
126
|
eventId: event.id,
|
|
130
127
|
type: event.type,
|
|
@@ -152,7 +149,7 @@ class MessageHandler {
|
|
|
152
149
|
}
|
|
153
150
|
}
|
|
154
151
|
async processMessage(message) {
|
|
155
|
-
if (
|
|
152
|
+
if (isRunnerDebugEnabled()) {
|
|
156
153
|
logger.debug("processMessage called", {
|
|
157
154
|
messageId: message.id,
|
|
158
155
|
method: message.payload?.method,
|
|
@@ -178,7 +175,7 @@ class MessageHandler {
|
|
|
178
175
|
await this.sendError(message, `Unknown method: ${method}`);
|
|
179
176
|
return;
|
|
180
177
|
}
|
|
181
|
-
if (
|
|
178
|
+
if (isRunnerDebugEnabled()) {
|
|
182
179
|
logger.debug("Processing message", {
|
|
183
180
|
messageId: message.id,
|
|
184
181
|
method: method,
|
|
@@ -191,7 +188,7 @@ class MessageHandler {
|
|
|
191
188
|
await this.markProcessed(message);
|
|
192
189
|
// Acknowledge ALL messages to update lastProcessedAt
|
|
193
190
|
await this.acknowledgeMessage(message);
|
|
194
|
-
if (
|
|
191
|
+
if (isRunnerDebugEnabled()) {
|
|
195
192
|
logger.debug("Message acknowledged", {
|
|
196
193
|
messageId: message.id,
|
|
197
194
|
method: method,
|
|
@@ -201,7 +198,7 @@ class MessageHandler {
|
|
|
201
198
|
}
|
|
202
199
|
}
|
|
203
200
|
catch (error) {
|
|
204
|
-
if (
|
|
201
|
+
if (isRunnerDebugEnabled()) {
|
|
205
202
|
logger.debug("Message processing error", {
|
|
206
203
|
messageId: message.id,
|
|
207
204
|
method: method,
|
|
@@ -251,7 +248,7 @@ class MessageHandler {
|
|
|
251
248
|
reason: "active runner, message after watermark",
|
|
252
249
|
};
|
|
253
250
|
})();
|
|
254
|
-
if (
|
|
251
|
+
if (isRunnerDebugEnabled()) {
|
|
255
252
|
logger.debug("Message processing decision", {
|
|
256
253
|
messageId: message.id,
|
|
257
254
|
method: message.payload?.method,
|
|
@@ -277,7 +274,7 @@ class MessageHandler {
|
|
|
277
274
|
}
|
|
278
275
|
async acknowledgeMessage(message) {
|
|
279
276
|
const runnerId = this.runner.getRunnerId();
|
|
280
|
-
|
|
277
|
+
console.log(`[MessageHandler] Sending message.acknowledge:`, {
|
|
281
278
|
runnerId,
|
|
282
279
|
messageTimestamp: message.createdAt,
|
|
283
280
|
messageId: message.id,
|
|
@@ -287,7 +284,7 @@ class MessageHandler {
|
|
|
287
284
|
await this.apiClient.acknowledgeMessage(message.createdAt);
|
|
288
285
|
// Update local lastProcessedAt
|
|
289
286
|
await this.runner.updateLastProcessedAt(new Date(message.createdAt));
|
|
290
|
-
|
|
287
|
+
console.log(`[MessageHandler] ✅ message.acknowledge sent successfully`);
|
|
291
288
|
}
|
|
292
289
|
catch (error) {
|
|
293
290
|
logger.error("Failed to acknowledge message:", error);
|
|
@@ -303,8 +300,8 @@ class MessageHandler {
|
|
|
303
300
|
const conversationObjectType = message.conversationObjectType || (message.taskId ? "Task" : undefined);
|
|
304
301
|
const conversationObjectId = message.conversationObjectId || message.taskId;
|
|
305
302
|
if (!conversationObjectId) {
|
|
306
|
-
|
|
307
|
-
if (
|
|
303
|
+
console.error(`[MessageHandler] Cannot send error report - no conversationObjectId available. Error: ${errorMessage}`);
|
|
304
|
+
if (isRunnerDebugEnabled()) {
|
|
308
305
|
logger.debug("Error without conversationObjectId", {
|
|
309
306
|
messageId: message.id,
|
|
310
307
|
method: message.payload?.method,
|
|
@@ -333,8 +330,8 @@ class MessageHandler {
|
|
|
333
330
|
const conversationObjectType = message.conversationObjectType || (message.taskId ? "Task" : undefined);
|
|
334
331
|
const conversationObjectId = message.conversationObjectId || message.taskId;
|
|
335
332
|
if (!conversationObjectId) {
|
|
336
|
-
|
|
337
|
-
if (
|
|
333
|
+
console.error(`[MessageHandler] Cannot send error report - no conversationObjectId available. Processing error: ${errorMessage}`);
|
|
334
|
+
if (isRunnerDebugEnabled()) {
|
|
338
335
|
logger.debug("Processing error without conversationObjectId", {
|
|
339
336
|
messageId: message.id,
|
|
340
337
|
method: message.payload?.method,
|
|
@@ -359,7 +356,7 @@ class MessageHandler {
|
|
|
359
356
|
});
|
|
360
357
|
}
|
|
361
358
|
registerHandlers() {
|
|
362
|
-
|
|
359
|
+
console.log("MessageHandler: Registering handlers...");
|
|
363
360
|
this.methodHandlers = new Map([
|
|
364
361
|
["conversation.start", this.handleConversationStart.bind(this)],
|
|
365
362
|
["conversation.stop", this.handleConversationStop.bind(this)],
|
|
@@ -391,7 +388,7 @@ class MessageHandler {
|
|
|
391
388
|
throw new Error("Missing conversationObjectId");
|
|
392
389
|
}
|
|
393
390
|
// Debug log the config
|
|
394
|
-
|
|
391
|
+
console.log(`[MessageHandler] conversation.start config:`, {
|
|
395
392
|
conversationObjectId,
|
|
396
393
|
hasConfig: !!config,
|
|
397
394
|
hasRepository: !!config?.repository,
|
|
@@ -401,7 +398,7 @@ class MessageHandler {
|
|
|
401
398
|
fullConfig: JSON.stringify(config, null, 2),
|
|
402
399
|
});
|
|
403
400
|
// Debug log workspace instructions received
|
|
404
|
-
|
|
401
|
+
console.log(`[MessageHandler] Received conversation with workspaceInstructions:`, {
|
|
405
402
|
conversationId: conversationData.id,
|
|
406
403
|
hasWorkspaceInstructions: !!conversationData.workspaceInstructions,
|
|
407
404
|
workspaceInstructionsLength: conversationData.workspaceInstructions?.length ?? 0,
|
|
@@ -409,17 +406,34 @@ class MessageHandler {
|
|
|
409
406
|
hasGlobalInstructions: !!conversationData.globalInstructions,
|
|
410
407
|
globalInstructionsLength: conversationData.globalInstructions?.length ?? 0,
|
|
411
408
|
});
|
|
409
|
+
// Check if conversation is already active (prevent duplicate starts on catch-up)
|
|
410
|
+
const conversationId = conversationData.id;
|
|
411
|
+
if (this.runner.activeConversations_.has(conversationId)) {
|
|
412
|
+
console.log(`[MessageHandler] Conversation ${conversationId} already active, skipping duplicate start`);
|
|
413
|
+
return;
|
|
414
|
+
}
|
|
415
|
+
// Check if this conversation was recently completed (prevent restart on catch-up)
|
|
416
|
+
if (this.runner.wasConversationCompleted(conversationId)) {
|
|
417
|
+
console.log(`[MessageHandler] Conversation ${conversationId} was already completed, skipping restart`);
|
|
418
|
+
return;
|
|
419
|
+
}
|
|
412
420
|
const provider = this.resolveAgentProvider(conversationData, config);
|
|
413
421
|
const manager = this.getManagerForProvider(provider);
|
|
414
422
|
// Start the conversation with the provided/loaded conversation details
|
|
415
|
-
|
|
423
|
+
// For CodexManager (openai) we pass the provider to distinguish
|
|
424
|
+
if (provider === "openai") {
|
|
425
|
+
await manager.startConversation(finalObjectType, finalObjectId, config, initialMessages || [], conversationData, provider);
|
|
426
|
+
}
|
|
427
|
+
else {
|
|
428
|
+
await manager.startConversation(finalObjectType, finalObjectId, config, initialMessages || [], conversationData, provider);
|
|
429
|
+
}
|
|
416
430
|
// Update status line
|
|
417
|
-
|
|
431
|
+
statusLineManager.updateActiveCount(this.runner.activeConversations_.size);
|
|
418
432
|
}
|
|
419
433
|
async handleConversationStop(params, message) {
|
|
420
434
|
// Require conversationId (present at message level); do not fall back to agentSessionId/taskId
|
|
421
435
|
const { conversationId = message.conversationId, reason } = params;
|
|
422
|
-
|
|
436
|
+
console.log(`[MessageHandler] handleConversationStop called with:`, {
|
|
423
437
|
conversationId,
|
|
424
438
|
messageConversationId: message.conversationId,
|
|
425
439
|
agentSessionId: params?.agentSessionId,
|
|
@@ -435,7 +449,7 @@ class MessageHandler {
|
|
|
435
449
|
context = this.runner.getConversationContext(conversationId);
|
|
436
450
|
targetConversationId = conversationId;
|
|
437
451
|
}
|
|
438
|
-
|
|
452
|
+
console.log(`[MessageHandler] handleConversationStop lookup result:`, {
|
|
439
453
|
contextFound: !!context,
|
|
440
454
|
targetConversationId,
|
|
441
455
|
contextTaskId: context?.taskId,
|
|
@@ -454,17 +468,17 @@ class MessageHandler {
|
|
|
454
468
|
context.status = "stopped";
|
|
455
469
|
this.runner.activeConversations_.delete(targetConversationId);
|
|
456
470
|
// Update status line
|
|
457
|
-
|
|
471
|
+
statusLineManager.updateActiveCount(this.runner.activeConversations_.size);
|
|
458
472
|
}
|
|
459
473
|
else {
|
|
460
474
|
// No conversation found - this is expected as conversations may have already ended
|
|
461
475
|
// or been cleaned up. Just log it and update status line.
|
|
462
|
-
|
|
476
|
+
console.log(`Conversation stop requested for ${conversationId} - conversation not found or already cleaned up`);
|
|
463
477
|
// If we have a targetConversationId, ensure it's removed from tracking
|
|
464
478
|
if (targetConversationId) {
|
|
465
479
|
this.runner.activeConversations_.delete(targetConversationId);
|
|
466
480
|
}
|
|
467
|
-
|
|
481
|
+
statusLineManager.updateActiveCount(this.runner.activeConversations_.size);
|
|
468
482
|
}
|
|
469
483
|
}
|
|
470
484
|
async handleConversationResume(params, message) {
|
|
@@ -484,11 +498,17 @@ class MessageHandler {
|
|
|
484
498
|
}
|
|
485
499
|
const provider = this.resolveAgentProvider(conversationData, config);
|
|
486
500
|
const manager = this.getManagerForProvider(provider);
|
|
487
|
-
|
|
501
|
+
// For CodexManager (openai) we pass the provider to distinguish
|
|
502
|
+
if (provider === "openai") {
|
|
503
|
+
await manager.resumeConversation(conversationData.objectType, conversationData.objectId, agentSessionId, config, conversationData, resumeMessage, provider);
|
|
504
|
+
}
|
|
505
|
+
else {
|
|
506
|
+
await manager.resumeConversation(conversationData.objectType, conversationData.objectId, agentSessionId, config, conversationData, resumeMessage, provider);
|
|
507
|
+
}
|
|
488
508
|
}
|
|
489
509
|
async handleConversationConfig(params, message) {
|
|
490
510
|
const { conversationId, model, permissionsMode, config } = params;
|
|
491
|
-
|
|
511
|
+
console.log(`[MessageHandler] handleConversationConfig called with:`, {
|
|
492
512
|
conversationId,
|
|
493
513
|
model,
|
|
494
514
|
permissionsMode,
|
|
@@ -513,28 +533,44 @@ class MessageHandler {
|
|
|
513
533
|
...(permissionsMode && { permissionsMode }),
|
|
514
534
|
...config, // Allow full config overrides if provided
|
|
515
535
|
};
|
|
516
|
-
|
|
536
|
+
console.log(`[MessageHandler] Stopping conversation ${context.conversationId} to apply new config`);
|
|
517
537
|
// Stop the current conversation
|
|
518
538
|
const manager = this.getManagerForConversationContext(context);
|
|
519
539
|
await manager.stopConversation(context.agentSessionId, context, false // Not a runner shutdown, just updating config
|
|
520
540
|
);
|
|
521
541
|
// Remove from active conversations
|
|
522
542
|
this.runner.activeConversations_.delete(context.conversationId);
|
|
523
|
-
|
|
543
|
+
console.log(`[MessageHandler] Resuming conversation ${context.conversationId} with new config`);
|
|
524
544
|
// Resume with new config
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
545
|
+
// For CodexManager (openai) we pass the provider to distinguish
|
|
546
|
+
const contextProvider = context.provider?.toLowerCase();
|
|
547
|
+
if (contextProvider === "openai") {
|
|
548
|
+
await manager.resumeConversation(context.conversationObjectType, context.conversationObjectId, context.agentSessionId, newConfig, {
|
|
549
|
+
id: context.conversationId,
|
|
550
|
+
objectType: context.conversationObjectType,
|
|
551
|
+
objectId: context.conversationObjectId,
|
|
552
|
+
model: newConfig.model,
|
|
553
|
+
globalInstructions: context.globalInstructions,
|
|
554
|
+
workspaceInstructions: context.workspaceInstructions,
|
|
555
|
+
permissionsMode: newConfig.permissionsMode,
|
|
556
|
+
agentSessionId: context.agentSessionId,
|
|
557
|
+
}, "<system-instructions>Configuration updated. Please continue with the new settings.</system-instructions>", contextProvider);
|
|
558
|
+
}
|
|
559
|
+
else {
|
|
560
|
+
await manager.resumeConversation(context.conversationObjectType, context.conversationObjectId, context.agentSessionId, newConfig, {
|
|
561
|
+
id: context.conversationId,
|
|
562
|
+
objectType: context.conversationObjectType,
|
|
563
|
+
objectId: context.conversationObjectId,
|
|
564
|
+
model: newConfig.model,
|
|
565
|
+
globalInstructions: context.globalInstructions,
|
|
566
|
+
workspaceInstructions: context.workspaceInstructions,
|
|
567
|
+
permissionsMode: newConfig.permissionsMode,
|
|
568
|
+
agentSessionId: context.agentSessionId,
|
|
569
|
+
}, "<system-instructions>Configuration updated. Please continue with the new settings.</system-instructions>");
|
|
570
|
+
}
|
|
535
571
|
// Update status line
|
|
536
|
-
|
|
537
|
-
|
|
572
|
+
statusLineManager.updateActiveCount(this.runner.activeConversations_.size);
|
|
573
|
+
console.log(`[MessageHandler] Conversation ${context.conversationId} config updated successfully`);
|
|
538
574
|
}
|
|
539
575
|
async handleUserMessage(params, message) {
|
|
540
576
|
const { conversationId, content, config, conversationObjectType = message.conversationObjectType || "Task", conversationObjectId = message.conversationObjectId, conversation, agentSessionId, } = params;
|
|
@@ -546,15 +582,22 @@ class MessageHandler {
|
|
|
546
582
|
throw new Error("Missing required parameter: content");
|
|
547
583
|
}
|
|
548
584
|
const existingContext = this.runner.getConversationContext(conversationId);
|
|
549
|
-
const
|
|
550
|
-
?
|
|
551
|
-
: this.
|
|
552
|
-
|
|
585
|
+
const provider = existingContext
|
|
586
|
+
? existingContext.provider
|
|
587
|
+
: this.resolveAgentProvider(conversation, config);
|
|
588
|
+
const manager = this.getManagerForProvider(provider);
|
|
589
|
+
// For CodexManager (openai), pass the provider
|
|
590
|
+
if (provider === "openai") {
|
|
591
|
+
await manager.sendUserMessage(conversationId, content, config, conversationObjectType, conversationObjectId, conversation, agentSessionId, provider);
|
|
592
|
+
}
|
|
593
|
+
else {
|
|
594
|
+
await manager.sendUserMessage(conversationId, content, config, conversationObjectType, conversationObjectId, conversation, agentSessionId);
|
|
595
|
+
}
|
|
553
596
|
}
|
|
554
597
|
async handleUidChanged(params, _message) {
|
|
555
598
|
const { runnerUid, lastProcessedAt } = params;
|
|
556
|
-
|
|
557
|
-
if (
|
|
599
|
+
console.log(`MessageHandler: Handling UID change notification - new UID: ${runnerUid}, lastProcessedAt: ${lastProcessedAt}`);
|
|
600
|
+
if (isRunnerDebugEnabled()) {
|
|
558
601
|
logger.debug("UID change notification received", {
|
|
559
602
|
newUid: runnerUid,
|
|
560
603
|
currentUid: this.runner.getRunnerUid(),
|
|
@@ -568,10 +611,10 @@ class MessageHandler {
|
|
|
568
611
|
// This ensures we activate even if we received the message during catch-up
|
|
569
612
|
if (runnerUid === this.runner.getRunnerUid()) {
|
|
570
613
|
// This is our UID - we're the active runner
|
|
571
|
-
|
|
614
|
+
console.log("MessageHandler: We are now the active runner");
|
|
572
615
|
this.runner.setIsActiveRunner(true);
|
|
573
616
|
await this.runner.updateLastProcessedAt(lastProcessedAt ? new Date(lastProcessedAt) : null);
|
|
574
|
-
if (
|
|
617
|
+
if (isRunnerDebugEnabled()) {
|
|
575
618
|
logger.debug("Runner activated as primary", {
|
|
576
619
|
runnerUid: runnerUid,
|
|
577
620
|
lastProcessedAt: lastProcessedAt,
|
|
@@ -586,15 +629,15 @@ class MessageHandler {
|
|
|
586
629
|
});
|
|
587
630
|
}
|
|
588
631
|
catch (error) {
|
|
589
|
-
|
|
590
|
-
if (
|
|
632
|
+
console.error("Failed to send activation notification:", error);
|
|
633
|
+
if (isRunnerDebugEnabled()) {
|
|
591
634
|
logger.debug("Activation notification failed", {
|
|
592
635
|
error: error instanceof Error ? error.message : String(error),
|
|
593
636
|
});
|
|
594
637
|
}
|
|
595
638
|
}
|
|
596
639
|
// Start processing messages from the lastProcessedAt point
|
|
597
|
-
|
|
640
|
+
console.log(`MessageHandler: Will process messages after ${lastProcessedAt || "beginning"}`);
|
|
598
641
|
}
|
|
599
642
|
else {
|
|
600
643
|
// Different UID - check if this is an old UID change that we should ignore
|
|
@@ -602,8 +645,8 @@ class MessageHandler {
|
|
|
602
645
|
if (currentLastProcessedAt && lastProcessedAt) {
|
|
603
646
|
const newTime = new Date(lastProcessedAt);
|
|
604
647
|
if (newTime < currentLastProcessedAt) {
|
|
605
|
-
|
|
606
|
-
if (
|
|
648
|
+
console.log(`MessageHandler: Ignoring old UID change (${lastProcessedAt} < ${currentLastProcessedAt.toISOString()})`);
|
|
649
|
+
if (isRunnerDebugEnabled()) {
|
|
607
650
|
logger.debug("Ignoring old UID change", {
|
|
608
651
|
newUid: runnerUid,
|
|
609
652
|
newLastProcessedAt: lastProcessedAt,
|
|
@@ -614,7 +657,7 @@ class MessageHandler {
|
|
|
614
657
|
}
|
|
615
658
|
}
|
|
616
659
|
// Different UID - we're being replaced
|
|
617
|
-
|
|
660
|
+
console.log(`MessageHandler: We are being replaced by runner with UID ${runnerUid}`);
|
|
618
661
|
this.runner.setIsActiveRunner(false);
|
|
619
662
|
// Remember which conversations were active before handoff (by conversationId)
|
|
620
663
|
for (const [conversationId, context] of this.runner
|
|
@@ -623,7 +666,7 @@ class MessageHandler {
|
|
|
623
666
|
this.runner.getPreHandoffConversations().add(conversationId);
|
|
624
667
|
}
|
|
625
668
|
}
|
|
626
|
-
if (
|
|
669
|
+
if (isRunnerDebugEnabled()) {
|
|
627
670
|
logger.debug("Runner deactivated - being replaced", {
|
|
628
671
|
newRunnerUid: runnerUid,
|
|
629
672
|
ourUid: this.runner.getRunnerUid(),
|
|
@@ -631,7 +674,7 @@ class MessageHandler {
|
|
|
631
674
|
activeConversationsCount: this.runner.getPreHandoffConversations().size,
|
|
632
675
|
});
|
|
633
676
|
}
|
|
634
|
-
|
|
677
|
+
console.log(`MessageHandler: Will complete ${this.runner.getPreHandoffConversations().size} active conversations`);
|
|
635
678
|
// Emit deactivation notification - wrap in try/catch to handle failures gracefully
|
|
636
679
|
try {
|
|
637
680
|
await this.runner.notify("runner.deactivate", {
|
|
@@ -641,8 +684,8 @@ class MessageHandler {
|
|
|
641
684
|
});
|
|
642
685
|
}
|
|
643
686
|
catch (error) {
|
|
644
|
-
|
|
645
|
-
if (
|
|
687
|
+
console.error("Failed to send deactivation notification:", error);
|
|
688
|
+
if (isRunnerDebugEnabled()) {
|
|
646
689
|
logger.debug("Deactivation notification failed", {
|
|
647
690
|
error: error instanceof Error ? error.message : String(error),
|
|
648
691
|
});
|
|
@@ -655,7 +698,7 @@ class MessageHandler {
|
|
|
655
698
|
if (!taskId || !operation) {
|
|
656
699
|
throw new Error("Missing required parameters: taskId and operation");
|
|
657
700
|
}
|
|
658
|
-
|
|
701
|
+
console.log(`MessageHandler: Handling Git operation ${operation} for task ${taskId}`);
|
|
659
702
|
const repoManager = this.runner.repositoryManager_;
|
|
660
703
|
try {
|
|
661
704
|
switch (operation) {
|
|
@@ -675,7 +718,7 @@ class MessageHandler {
|
|
|
675
718
|
break;
|
|
676
719
|
case "push":
|
|
677
720
|
// TODO: Implement push operation
|
|
678
|
-
|
|
721
|
+
console.log("Push operation not yet implemented");
|
|
679
722
|
break;
|
|
680
723
|
case "rebase":
|
|
681
724
|
if (!opParams?.targetBranch) {
|
|
@@ -698,7 +741,7 @@ class MessageHandler {
|
|
|
698
741
|
}
|
|
699
742
|
}
|
|
700
743
|
catch (error) {
|
|
701
|
-
|
|
744
|
+
console.error(`Git operation ${operation} failed for task ${taskId}:`, error);
|
|
702
745
|
await this.recordGitOperation(taskId, operation, "failed", {
|
|
703
746
|
error: error instanceof Error ? error.message : String(error),
|
|
704
747
|
});
|
|
@@ -710,14 +753,14 @@ class MessageHandler {
|
|
|
710
753
|
if (!taskId) {
|
|
711
754
|
throw new Error("Missing required parameter: taskId");
|
|
712
755
|
}
|
|
713
|
-
|
|
756
|
+
console.log(`MessageHandler: Cleaning up Git worktree for task ${taskId}`);
|
|
714
757
|
const repoManager = this.runner.repositoryManager_;
|
|
715
758
|
try {
|
|
716
759
|
await repoManager.removeTaskWorktree(taskId, { preserveBranch });
|
|
717
|
-
|
|
760
|
+
console.log(`Successfully cleaned up worktree for task ${taskId}`);
|
|
718
761
|
}
|
|
719
762
|
catch (error) {
|
|
720
|
-
|
|
763
|
+
console.error(`Failed to clean up worktree for task ${taskId}:`, error);
|
|
721
764
|
throw error;
|
|
722
765
|
}
|
|
723
766
|
}
|
|
@@ -725,7 +768,7 @@ class MessageHandler {
|
|
|
725
768
|
const repoManager = this.runner.repositoryManager_;
|
|
726
769
|
const gitState = await repoManager.getTaskState(taskId);
|
|
727
770
|
if (!gitState) {
|
|
728
|
-
|
|
771
|
+
console.error(`No Git state found for task ${taskId}`);
|
|
729
772
|
return;
|
|
730
773
|
}
|
|
731
774
|
// Send state update to orchestrator
|
|
@@ -751,39 +794,104 @@ class MessageHandler {
|
|
|
751
794
|
});
|
|
752
795
|
}
|
|
753
796
|
resolveAgentProvider(conversation, config) {
|
|
797
|
+
const model = conversation?.model ||
|
|
798
|
+
config?.model ||
|
|
799
|
+
config?.defaultModel ||
|
|
800
|
+
"";
|
|
801
|
+
const normalizedModel = model.toLowerCase();
|
|
802
|
+
// First check if model has explicit provider prefix
|
|
803
|
+
if (normalizedModel.startsWith("openrouter:") || normalizedModel.startsWith("openrouter/")) {
|
|
804
|
+
return "openrouter";
|
|
805
|
+
}
|
|
806
|
+
if (normalizedModel.startsWith("groq:") || normalizedModel.startsWith("groq/")) {
|
|
807
|
+
return "groq";
|
|
808
|
+
}
|
|
809
|
+
if (normalizedModel.startsWith("openai:") || normalizedModel.startsWith("openai/")) {
|
|
810
|
+
return "openai";
|
|
811
|
+
}
|
|
812
|
+
if (normalizedModel.startsWith("claude:") || normalizedModel.startsWith("claude/")) {
|
|
813
|
+
return "claude";
|
|
814
|
+
}
|
|
815
|
+
// Respect explicit provider, but let model-based OpenRouter routing win first
|
|
754
816
|
const explicitProvider = conversation?.providerType ||
|
|
755
817
|
conversation?.agentProviderType ||
|
|
756
818
|
config?.providerType ||
|
|
757
819
|
config?.agentProviderType;
|
|
758
820
|
if (typeof explicitProvider === "string") {
|
|
759
821
|
const normalized = explicitProvider.toLowerCase();
|
|
822
|
+
if (normalized === "openrouter")
|
|
823
|
+
return "openrouter";
|
|
824
|
+
if (normalized === "groq")
|
|
825
|
+
return "groq";
|
|
760
826
|
if (normalized === "openai")
|
|
761
827
|
return "openai";
|
|
762
828
|
if (normalized === "claude")
|
|
763
829
|
return "claude";
|
|
764
830
|
}
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
""
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
831
|
+
// Check for known Claude models (direct access, not via OpenRouter)
|
|
832
|
+
const looksLikeClaude = normalizedModel.includes("claude") ||
|
|
833
|
+
normalizedModel.includes("opus") ||
|
|
834
|
+
normalizedModel.includes("sonnet") ||
|
|
835
|
+
normalizedModel.includes("haiku");
|
|
836
|
+
// Define specific OpenAI/Codex models that should use the OpenAI provider
|
|
837
|
+
// These are models directly from OpenAI/Codex, not via OpenRouter
|
|
838
|
+
const directOpenAIModels = [
|
|
839
|
+
"gpt-3.5-turbo",
|
|
840
|
+
"gpt-4",
|
|
841
|
+
"gpt-4-turbo",
|
|
842
|
+
"gpt-4o",
|
|
843
|
+
"gpt-4o-mini",
|
|
844
|
+
"gpt-5.1",
|
|
845
|
+
"gpt-5.1-codex",
|
|
846
|
+
"gpt-5.1-codex-max",
|
|
847
|
+
"gpt-5.1-codex-mini",
|
|
848
|
+
"o1",
|
|
849
|
+
"o1-preview",
|
|
850
|
+
"o1-mini",
|
|
851
|
+
"codex"
|
|
852
|
+
];
|
|
853
|
+
// Check if it's a direct OpenAI model (exact match or starts with the model name followed by :)
|
|
854
|
+
const isDirectOpenAIModel = directOpenAIModels.some(directModel => {
|
|
855
|
+
// Check for exact match or model with reasoning effort suffix (e.g., "gpt-5.1:high")
|
|
856
|
+
return normalizedModel === directModel ||
|
|
857
|
+
normalizedModel.startsWith(directModel + ":") ||
|
|
858
|
+
normalizedModel.startsWith(directModel + "-") ||
|
|
859
|
+
(directModel.startsWith("o") && /^o\d/.test(normalizedModel));
|
|
860
|
+
});
|
|
861
|
+
if (looksLikeClaude)
|
|
862
|
+
return "claude";
|
|
863
|
+
if (isDirectOpenAIModel)
|
|
864
|
+
return "openai";
|
|
865
|
+
// If it doesn't match known Claude or direct OpenAI models, treat as OpenRouter
|
|
866
|
+
// This includes any remaining unknown models
|
|
867
|
+
if (model && model.length > 0) {
|
|
868
|
+
return "openrouter";
|
|
869
|
+
}
|
|
870
|
+
return "claude";
|
|
775
871
|
}
|
|
776
872
|
getManagerForProvider(provider) {
|
|
777
|
-
|
|
873
|
+
const normalized = provider?.toLowerCase();
|
|
874
|
+
if (normalized === "openrouter" || normalized === "groq") {
|
|
875
|
+
// OpenRouter now handled by Northflare Agent manager
|
|
876
|
+
return this.runner.northflareAgentManager_;
|
|
877
|
+
}
|
|
878
|
+
if (normalized === "openai") {
|
|
778
879
|
return this.runner.codexManager_;
|
|
779
880
|
}
|
|
780
881
|
return this.runner.claudeManager_;
|
|
781
882
|
}
|
|
782
883
|
getManagerForConversationContext(context) {
|
|
783
|
-
|
|
884
|
+
const provider = context.provider?.toLowerCase();
|
|
885
|
+
const model = (context.model || "").toLowerCase();
|
|
886
|
+
// Route any OpenRouter-style model strings to the Northflare Agent, even if the
|
|
887
|
+
// provider was previously tagged as openai/codex.
|
|
888
|
+
const looksLikeOpenRouter = model.startsWith("openrouter:");
|
|
889
|
+
if (provider === "openrouter" || provider === "groq" || looksLikeOpenRouter) {
|
|
890
|
+
return this.runner.northflareAgentManager_;
|
|
891
|
+
}
|
|
892
|
+
return provider === "openai"
|
|
784
893
|
? this.runner.codexManager_
|
|
785
894
|
: this.runner.claudeManager_;
|
|
786
895
|
}
|
|
787
896
|
}
|
|
788
|
-
exports.MessageHandler = MessageHandler;
|
|
789
897
|
//# sourceMappingURL=message-handler-sse.js.map
|