@northflare/runner 0.0.8 → 0.0.10
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/components/claude-sdk-manager.d.ts +1 -1
- package/dist/components/claude-sdk-manager.d.ts.map +1 -1
- package/dist/components/claude-sdk-manager.js +30 -16
- package/dist/components/claude-sdk-manager.js.map +1 -1
- package/dist/components/codex-sdk-manager.d.ts +60 -0
- package/dist/components/codex-sdk-manager.d.ts.map +1 -0
- package/dist/components/codex-sdk-manager.js +988 -0
- package/dist/components/codex-sdk-manager.js.map +1 -0
- package/dist/components/message-handler-sse.d.ts +3 -0
- package/dist/components/message-handler-sse.d.ts.map +1 -1
- package/dist/components/message-handler-sse.js +66 -21
- package/dist/components/message-handler-sse.js.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -2
- package/dist/index.js.map +1 -1
- package/dist/runner-sse.d.ts +4 -0
- package/dist/runner-sse.d.ts.map +1 -1
- package/dist/runner-sse.js +63 -20
- package/dist/runner-sse.js.map +1 -1
- package/dist/runner.js +3 -3
- package/dist/types/claude.d.ts +11 -1
- package/dist/types/claude.d.ts.map +1 -1
- package/dist/types/index.d.ts +1 -0
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/runner-interface.d.ts +2 -0
- package/dist/types/runner-interface.d.ts.map +1 -1
- package/dist/utils/config.d.ts.map +1 -1
- package/dist/utils/config.js +1 -0
- package/dist/utils/config.js.map +1 -1
- package/dist/utils/console.d.ts.map +1 -1
- package/dist/utils/console.js +2 -1
- package/dist/utils/console.js.map +1 -1
- package/dist/utils/debug.d.ts +2 -0
- package/dist/utils/debug.d.ts.map +1 -0
- package/dist/utils/debug.js +19 -0
- package/dist/utils/debug.js.map +1 -0
- package/dist/utils/logger.d.ts.map +1 -1
- package/dist/utils/logger.js +6 -4
- package/dist/utils/logger.js.map +1 -1
- package/dist/utils/model.d.ts +6 -0
- package/dist/utils/model.d.ts.map +1 -0
- package/dist/utils/model.js +23 -0
- package/dist/utils/model.js.map +1 -0
- package/dist/utils/status-line.d.ts +0 -8
- package/dist/utils/status-line.d.ts.map +1 -1
- package/dist/utils/status-line.js +9 -8
- package/dist/utils/status-line.js.map +1 -1
- package/dist/utils/tool-response-sanitizer.d.ts +9 -0
- package/dist/utils/tool-response-sanitizer.d.ts.map +1 -0
- package/dist/utils/tool-response-sanitizer.js +122 -0
- package/dist/utils/tool-response-sanitizer.js.map +1 -0
- package/exceptions.log +2 -0
- package/lib/codex-sdk/.prettierignore +3 -0
- package/lib/codex-sdk/.prettierrc +5 -0
- package/lib/codex-sdk/README.md +133 -0
- package/lib/codex-sdk/dist/index.d.ts +260 -0
- package/lib/codex-sdk/dist/index.js +426 -0
- package/lib/codex-sdk/eslint.config.js +21 -0
- package/lib/codex-sdk/jest.config.cjs +31 -0
- package/lib/codex-sdk/package.json +65 -0
- package/lib/codex-sdk/samples/basic_streaming.ts +90 -0
- package/lib/codex-sdk/samples/helpers.ts +8 -0
- package/lib/codex-sdk/samples/structured_output.ts +22 -0
- package/lib/codex-sdk/samples/structured_output_zod.ts +19 -0
- package/lib/codex-sdk/src/codex.ts +38 -0
- package/lib/codex-sdk/src/codexOptions.ts +10 -0
- package/lib/codex-sdk/src/events.ts +80 -0
- package/lib/codex-sdk/src/exec.ts +336 -0
- package/lib/codex-sdk/src/index.ts +39 -0
- package/lib/codex-sdk/src/items.ts +127 -0
- package/lib/codex-sdk/src/outputSchemaFile.ts +40 -0
- package/lib/codex-sdk/src/thread.ts +155 -0
- package/lib/codex-sdk/src/threadOptions.ts +18 -0
- package/lib/codex-sdk/src/turnOptions.ts +6 -0
- package/lib/codex-sdk/tests/abort.test.ts +165 -0
- package/lib/codex-sdk/tests/codexExecSpy.ts +37 -0
- package/lib/codex-sdk/tests/responsesProxy.ts +225 -0
- package/lib/codex-sdk/tests/run.test.ts +687 -0
- package/lib/codex-sdk/tests/runStreamed.test.ts +211 -0
- package/lib/codex-sdk/tsconfig.json +24 -0
- package/lib/codex-sdk/tsup.config.ts +12 -0
- package/package.json +3 -1
- package/rejections.log +5 -0
- package/src/components/claude-sdk-manager.ts +38 -17
- package/src/components/codex-sdk-manager.ts +1349 -0
- package/src/components/message-handler-sse.ts +94 -22
- package/src/index.ts +4 -2
- package/src/runner-sse.ts +75 -20
- package/src/types/claude.ts +12 -1
- package/src/types/index.ts +1 -0
- package/src/types/runner-interface.ts +3 -1
- package/src/utils/config.ts +1 -0
- package/src/utils/console.ts +4 -2
- package/src/utils/debug.ts +18 -0
- package/src/utils/logger.ts +8 -5
- package/src/utils/model.ts +29 -0
- package/src/utils/status-line.ts +9 -8
- package/src/utils/tool-response-sanitizer.ts +160 -0
- package/tests/tool-response-sanitizer.test.ts +63 -0
- package/src/utils/codex-sdk.js +0 -448
- package/src/utils/sdk-demo.js +0 -34
|
@@ -3,12 +3,18 @@
|
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
5
|
import { IRunnerApp } from "../types/runner-interface";
|
|
6
|
-
import {
|
|
6
|
+
import {
|
|
7
|
+
RunnerMessage,
|
|
8
|
+
MethodHandler,
|
|
9
|
+
ConversationContext,
|
|
10
|
+
ConversationConfig,
|
|
11
|
+
} from "../types";
|
|
7
12
|
import { SSEClient, SSEEvent } from "../services/SSEClient";
|
|
8
13
|
import { RunnerAPIClient } from "../services/RunnerAPIClient";
|
|
9
14
|
import { statusLineManager } from "../utils/status-line";
|
|
10
15
|
import { console } from "../utils/console";
|
|
11
16
|
import { createLogger } from "../utils/logger";
|
|
17
|
+
import { isRunnerDebugEnabled } from "../utils/debug";
|
|
12
18
|
|
|
13
19
|
const logger = createLogger("MessageHandler");
|
|
14
20
|
|
|
@@ -151,7 +157,7 @@ export class MessageHandler {
|
|
|
151
157
|
if (event.type === "runner.message") {
|
|
152
158
|
const message = event.data as RunnerMessage;
|
|
153
159
|
|
|
154
|
-
if (
|
|
160
|
+
if (isRunnerDebugEnabled()) {
|
|
155
161
|
logger.debug("Received SSE event", {
|
|
156
162
|
eventId: event.id,
|
|
157
163
|
type: event.type,
|
|
@@ -178,7 +184,7 @@ export class MessageHandler {
|
|
|
178
184
|
}
|
|
179
185
|
|
|
180
186
|
private async processMessage(message: RunnerMessage): Promise<void> {
|
|
181
|
-
if (
|
|
187
|
+
if (isRunnerDebugEnabled()) {
|
|
182
188
|
logger.debug("processMessage called", {
|
|
183
189
|
messageId: message.id,
|
|
184
190
|
method: message.payload?.method,
|
|
@@ -211,7 +217,7 @@ export class MessageHandler {
|
|
|
211
217
|
return;
|
|
212
218
|
}
|
|
213
219
|
|
|
214
|
-
if (
|
|
220
|
+
if (isRunnerDebugEnabled()) {
|
|
215
221
|
logger.debug("Processing message", {
|
|
216
222
|
messageId: message.id,
|
|
217
223
|
method: method,
|
|
@@ -227,7 +233,7 @@ export class MessageHandler {
|
|
|
227
233
|
// Acknowledge ALL messages to update lastProcessedAt
|
|
228
234
|
await this.acknowledgeMessage(message);
|
|
229
235
|
|
|
230
|
-
if (
|
|
236
|
+
if (isRunnerDebugEnabled()) {
|
|
231
237
|
logger.debug("Message acknowledged", {
|
|
232
238
|
messageId: message.id,
|
|
233
239
|
method: method,
|
|
@@ -236,7 +242,7 @@ export class MessageHandler {
|
|
|
236
242
|
});
|
|
237
243
|
}
|
|
238
244
|
} catch (error) {
|
|
239
|
-
if (
|
|
245
|
+
if (isRunnerDebugEnabled()) {
|
|
240
246
|
logger.debug("Message processing error", {
|
|
241
247
|
messageId: message.id,
|
|
242
248
|
method: method,
|
|
@@ -293,7 +299,7 @@ export class MessageHandler {
|
|
|
293
299
|
};
|
|
294
300
|
})();
|
|
295
301
|
|
|
296
|
-
if (
|
|
302
|
+
if (isRunnerDebugEnabled()) {
|
|
297
303
|
logger.debug("Message processing decision", {
|
|
298
304
|
messageId: message.id,
|
|
299
305
|
method: message.payload?.method,
|
|
@@ -361,7 +367,7 @@ export class MessageHandler {
|
|
|
361
367
|
console.error(
|
|
362
368
|
`[MessageHandler] Cannot send error report - no conversationObjectId available. Error: ${errorMessage}`
|
|
363
369
|
);
|
|
364
|
-
if (
|
|
370
|
+
if (isRunnerDebugEnabled()) {
|
|
365
371
|
logger.debug("Error without conversationObjectId", {
|
|
366
372
|
messageId: message.id,
|
|
367
373
|
method: message.payload?.method,
|
|
@@ -398,7 +404,7 @@ export class MessageHandler {
|
|
|
398
404
|
console.error(
|
|
399
405
|
`[MessageHandler] Cannot send error report - no conversationObjectId available. Processing error: ${errorMessage}`
|
|
400
406
|
);
|
|
401
|
-
if (
|
|
407
|
+
if (isRunnerDebugEnabled()) {
|
|
402
408
|
logger.debug("Processing error without conversationObjectId", {
|
|
403
409
|
messageId: message.id,
|
|
404
410
|
method: message.payload?.method,
|
|
@@ -499,8 +505,11 @@ export class MessageHandler {
|
|
|
499
505
|
}
|
|
500
506
|
);
|
|
501
507
|
|
|
508
|
+
const provider = this.resolveAgentProvider(conversationData, config);
|
|
509
|
+
const manager = this.getManagerForProvider(provider);
|
|
510
|
+
|
|
502
511
|
// Start the conversation with the provided/loaded conversation details
|
|
503
|
-
await
|
|
512
|
+
await manager.startConversation(
|
|
504
513
|
finalObjectType,
|
|
505
514
|
finalObjectId,
|
|
506
515
|
config,
|
|
@@ -551,7 +560,8 @@ export class MessageHandler {
|
|
|
551
560
|
|
|
552
561
|
if (context && targetConversationId) {
|
|
553
562
|
context.status = "stopping";
|
|
554
|
-
|
|
563
|
+
const manager = this.getManagerForConversationContext(context);
|
|
564
|
+
await manager.stopConversation(
|
|
555
565
|
context.agentSessionId,
|
|
556
566
|
context,
|
|
557
567
|
false, // Not a runner shutdown
|
|
@@ -611,7 +621,9 @@ export class MessageHandler {
|
|
|
611
621
|
throw new Error("Cannot resume conversation without agentSessionId");
|
|
612
622
|
}
|
|
613
623
|
|
|
614
|
-
|
|
624
|
+
const provider = this.resolveAgentProvider(conversationData, config);
|
|
625
|
+
const manager = this.getManagerForProvider(provider);
|
|
626
|
+
await manager.resumeConversation(
|
|
615
627
|
conversationData.objectType,
|
|
616
628
|
conversationData.objectId,
|
|
617
629
|
agentSessionId,
|
|
@@ -666,7 +678,9 @@ export class MessageHandler {
|
|
|
666
678
|
);
|
|
667
679
|
|
|
668
680
|
// Stop the current conversation
|
|
669
|
-
|
|
681
|
+
const manager = this.getManagerForConversationContext(context);
|
|
682
|
+
|
|
683
|
+
await manager.stopConversation(
|
|
670
684
|
context.agentSessionId,
|
|
671
685
|
context,
|
|
672
686
|
false // Not a runner shutdown, just updating config
|
|
@@ -680,7 +694,7 @@ export class MessageHandler {
|
|
|
680
694
|
);
|
|
681
695
|
|
|
682
696
|
// Resume with new config
|
|
683
|
-
await
|
|
697
|
+
await manager.resumeConversation(
|
|
684
698
|
context.conversationObjectType,
|
|
685
699
|
context.conversationObjectId,
|
|
686
700
|
context.agentSessionId,
|
|
@@ -717,6 +731,7 @@ export class MessageHandler {
|
|
|
717
731
|
conversationObjectType = message.conversationObjectType || "Task",
|
|
718
732
|
conversationObjectId = message.conversationObjectId,
|
|
719
733
|
conversation,
|
|
734
|
+
agentSessionId,
|
|
720
735
|
} = params;
|
|
721
736
|
|
|
722
737
|
// Validate required parameters
|
|
@@ -728,13 +743,21 @@ export class MessageHandler {
|
|
|
728
743
|
throw new Error("Missing required parameter: content");
|
|
729
744
|
}
|
|
730
745
|
|
|
731
|
-
|
|
746
|
+
const existingContext = this.runner.getConversationContext(conversationId);
|
|
747
|
+
const manager = existingContext
|
|
748
|
+
? this.getManagerForConversationContext(existingContext)
|
|
749
|
+
: this.getManagerForProvider(
|
|
750
|
+
this.resolveAgentProvider(conversation, config)
|
|
751
|
+
);
|
|
752
|
+
|
|
753
|
+
await manager.sendUserMessage(
|
|
732
754
|
conversationId,
|
|
733
755
|
content,
|
|
734
756
|
config,
|
|
735
757
|
conversationObjectType,
|
|
736
758
|
conversationObjectId,
|
|
737
|
-
conversation
|
|
759
|
+
conversation,
|
|
760
|
+
agentSessionId
|
|
738
761
|
);
|
|
739
762
|
}
|
|
740
763
|
|
|
@@ -748,7 +771,7 @@ export class MessageHandler {
|
|
|
748
771
|
`MessageHandler: Handling UID change notification - new UID: ${runnerUid}, lastProcessedAt: ${lastProcessedAt}`
|
|
749
772
|
);
|
|
750
773
|
|
|
751
|
-
if (
|
|
774
|
+
if (isRunnerDebugEnabled()) {
|
|
752
775
|
logger.debug("UID change notification received", {
|
|
753
776
|
newUid: runnerUid,
|
|
754
777
|
currentUid: this.runner.getRunnerUid(),
|
|
@@ -770,7 +793,7 @@ export class MessageHandler {
|
|
|
770
793
|
lastProcessedAt ? new Date(lastProcessedAt) : null
|
|
771
794
|
);
|
|
772
795
|
|
|
773
|
-
if (
|
|
796
|
+
if (isRunnerDebugEnabled()) {
|
|
774
797
|
logger.debug("Runner activated as primary", {
|
|
775
798
|
runnerUid: runnerUid,
|
|
776
799
|
lastProcessedAt: lastProcessedAt,
|
|
@@ -786,7 +809,7 @@ export class MessageHandler {
|
|
|
786
809
|
});
|
|
787
810
|
} catch (error) {
|
|
788
811
|
console.error("Failed to send activation notification:", error);
|
|
789
|
-
if (
|
|
812
|
+
if (isRunnerDebugEnabled()) {
|
|
790
813
|
logger.debug("Activation notification failed", {
|
|
791
814
|
error: error instanceof Error ? error.message : String(error),
|
|
792
815
|
});
|
|
@@ -808,7 +831,7 @@ export class MessageHandler {
|
|
|
808
831
|
console.log(
|
|
809
832
|
`MessageHandler: Ignoring old UID change (${lastProcessedAt} < ${currentLastProcessedAt.toISOString()})`
|
|
810
833
|
);
|
|
811
|
-
if (
|
|
834
|
+
if (isRunnerDebugEnabled()) {
|
|
812
835
|
logger.debug("Ignoring old UID change", {
|
|
813
836
|
newUid: runnerUid,
|
|
814
837
|
newLastProcessedAt: lastProcessedAt,
|
|
@@ -833,7 +856,7 @@ export class MessageHandler {
|
|
|
833
856
|
}
|
|
834
857
|
}
|
|
835
858
|
|
|
836
|
-
if (
|
|
859
|
+
if (isRunnerDebugEnabled()) {
|
|
837
860
|
logger.debug("Runner deactivated - being replaced", {
|
|
838
861
|
newRunnerUid: runnerUid,
|
|
839
862
|
ourUid: this.runner.getRunnerUid(),
|
|
@@ -860,7 +883,7 @@ export class MessageHandler {
|
|
|
860
883
|
});
|
|
861
884
|
} catch (error) {
|
|
862
885
|
console.error("Failed to send deactivation notification:", error);
|
|
863
|
-
if (
|
|
886
|
+
if (isRunnerDebugEnabled()) {
|
|
864
887
|
logger.debug("Deactivation notification failed", {
|
|
865
888
|
error: error instanceof Error ? error.message : String(error),
|
|
866
889
|
});
|
|
@@ -1022,4 +1045,53 @@ export class MessageHandler {
|
|
|
1022
1045
|
timestamp: new Date(),
|
|
1023
1046
|
});
|
|
1024
1047
|
}
|
|
1048
|
+
|
|
1049
|
+
private resolveAgentProvider(
|
|
1050
|
+
conversation?: {
|
|
1051
|
+
providerType?: string;
|
|
1052
|
+
agentProviderType?: string;
|
|
1053
|
+
model?: string;
|
|
1054
|
+
},
|
|
1055
|
+
config?: ConversationConfig
|
|
1056
|
+
): "openai" | "claude" {
|
|
1057
|
+
const explicitProvider =
|
|
1058
|
+
conversation?.providerType ||
|
|
1059
|
+
conversation?.agentProviderType ||
|
|
1060
|
+
(config as any)?.providerType ||
|
|
1061
|
+
(config as any)?.agentProviderType;
|
|
1062
|
+
|
|
1063
|
+
if (typeof explicitProvider === "string") {
|
|
1064
|
+
const normalized = explicitProvider.toLowerCase();
|
|
1065
|
+
if (normalized === "openai") return "openai";
|
|
1066
|
+
if (normalized === "claude") return "claude";
|
|
1067
|
+
}
|
|
1068
|
+
|
|
1069
|
+
const model =
|
|
1070
|
+
conversation?.model ||
|
|
1071
|
+
(config as any)?.model ||
|
|
1072
|
+
(config as any)?.defaultModel ||
|
|
1073
|
+
"";
|
|
1074
|
+
const normalizedModel = model.toLowerCase();
|
|
1075
|
+
|
|
1076
|
+
const looksLikeCodex =
|
|
1077
|
+
normalizedModel.includes("gpt") ||
|
|
1078
|
+
/^o\d/.test(normalizedModel) ||
|
|
1079
|
+
normalizedModel.includes("openai") ||
|
|
1080
|
+
normalizedModel.includes("codex");
|
|
1081
|
+
|
|
1082
|
+
return looksLikeCodex ? "openai" : "claude";
|
|
1083
|
+
}
|
|
1084
|
+
|
|
1085
|
+
private getManagerForProvider(provider?: string) {
|
|
1086
|
+
if (provider?.toLowerCase() === "openai") {
|
|
1087
|
+
return this.runner.codexManager_;
|
|
1088
|
+
}
|
|
1089
|
+
return this.runner.claudeManager_;
|
|
1090
|
+
}
|
|
1091
|
+
|
|
1092
|
+
private getManagerForConversationContext(context: ConversationContext) {
|
|
1093
|
+
return context.provider === "openai"
|
|
1094
|
+
? this.runner.codexManager_
|
|
1095
|
+
: this.runner.claudeManager_;
|
|
1096
|
+
}
|
|
1025
1097
|
}
|
package/src/index.ts
CHANGED
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
import { RunnerApp } from "./runner-sse";
|
|
6
6
|
import { ConfigManager } from "./utils/config";
|
|
7
7
|
import { logger, configureFileLogging } from "./utils/logger";
|
|
8
|
+
import { isRunnerDebugEnabled } from "./utils/debug";
|
|
8
9
|
import path from "path";
|
|
9
10
|
import fs from "fs/promises";
|
|
10
11
|
|
|
@@ -13,6 +14,7 @@ let runner: RunnerApp | null = null;
|
|
|
13
14
|
async function main() {
|
|
14
15
|
try {
|
|
15
16
|
logger.info("Starting Northflare Runner...");
|
|
17
|
+
const debugEnabled = isRunnerDebugEnabled();
|
|
16
18
|
|
|
17
19
|
// Load configuration (args already parsed by CLI)
|
|
18
20
|
let configPath = process.argv[2]; // This is set by the CLI if --config was provided
|
|
@@ -53,7 +55,7 @@ async function main() {
|
|
|
53
55
|
});
|
|
54
56
|
|
|
55
57
|
// Additional debug logging
|
|
56
|
-
if (
|
|
58
|
+
if (debugEnabled) {
|
|
57
59
|
logger.debug("Debug mode enabled - verbose logging active", {
|
|
58
60
|
dataDir: config.dataDir,
|
|
59
61
|
heartbeatInterval: config.heartbeatInterval,
|
|
@@ -75,7 +77,7 @@ async function main() {
|
|
|
75
77
|
});
|
|
76
78
|
|
|
77
79
|
// Log additional details in debug mode
|
|
78
|
-
if (
|
|
80
|
+
if (debugEnabled && runner) {
|
|
79
81
|
logger.debug("Runner started with full details", {
|
|
80
82
|
runnerId: runner.getRunnerId(),
|
|
81
83
|
runnerUid: runner.getRunnerUid(),
|
package/src/runner-sse.ts
CHANGED
|
@@ -13,19 +13,35 @@ import {
|
|
|
13
13
|
import { IRunnerApp } from "./types/runner-interface";
|
|
14
14
|
import { MessageHandler } from "./components/message-handler-sse";
|
|
15
15
|
import { ClaudeManager } from "./components/claude-sdk-manager";
|
|
16
|
+
import { CodexManager } from "./components/codex-sdk-manager";
|
|
16
17
|
import { EnhancedRepositoryManager } from "./components/enhanced-repository-manager";
|
|
17
18
|
import { StateManager } from "./utils/StateManager";
|
|
18
19
|
import { createLogger } from "./utils/logger";
|
|
19
20
|
import { statusLineManager } from "./utils/status-line";
|
|
21
|
+
import { isRunnerDebugEnabled } from "./utils/debug";
|
|
20
22
|
import fs from "fs/promises";
|
|
21
23
|
import path from "path";
|
|
22
24
|
import computerName from "computer-name";
|
|
25
|
+
import {
|
|
26
|
+
sanitizeToolResponsePayload,
|
|
27
|
+
TOOL_RESPONSE_BYTE_LIMIT,
|
|
28
|
+
} from "./utils/tool-response-sanitizer";
|
|
23
29
|
|
|
24
30
|
const logger = createLogger("RunnerApp");
|
|
25
31
|
|
|
32
|
+
function logToolResponseTruncation(toolUseId?: string) {
|
|
33
|
+
const message = `Tool response exceeded ${TOOL_RESPONSE_BYTE_LIMIT} bytes and was truncated`;
|
|
34
|
+
if (toolUseId) {
|
|
35
|
+
logger.warn(message, { toolUseId });
|
|
36
|
+
} else {
|
|
37
|
+
logger.warn(message);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
26
41
|
export class RunnerApp implements IRunnerApp {
|
|
27
42
|
private messageHandler!: MessageHandler;
|
|
28
43
|
private claudeManager!: ClaudeManager;
|
|
44
|
+
private codexManager!: CodexManager;
|
|
29
45
|
private repositoryManager!: EnhancedRepositoryManager;
|
|
30
46
|
private stateManager!: StateManager;
|
|
31
47
|
private agentConversations: Map<string, ConversationContext>; // Keyed by conversation.id
|
|
@@ -91,6 +107,9 @@ export class RunnerApp implements IRunnerApp {
|
|
|
91
107
|
// Initialize Claude manager with repository manager (using SDK-native manager)
|
|
92
108
|
this.claudeManager = new ClaudeManager(this, this.repositoryManager);
|
|
93
109
|
|
|
110
|
+
// Initialize Codex manager for OpenAI-based conversations
|
|
111
|
+
this.codexManager = new CodexManager(this, this.repositoryManager);
|
|
112
|
+
|
|
94
113
|
// Initialize message handler with SSE support
|
|
95
114
|
this.messageHandler = new MessageHandler(this);
|
|
96
115
|
}
|
|
@@ -139,7 +158,7 @@ export class RunnerApp implements IRunnerApp {
|
|
|
139
158
|
await this.registerWithRetry();
|
|
140
159
|
|
|
141
160
|
// Log debug info after registration
|
|
142
|
-
if (
|
|
161
|
+
if (isRunnerDebugEnabled()) {
|
|
143
162
|
logger.debug("Runner initialized with ownership details", {
|
|
144
163
|
runnerId: this.config.runnerId,
|
|
145
164
|
runnerUid: this.runnerUid,
|
|
@@ -193,17 +212,24 @@ export class RunnerApp implements IRunnerApp {
|
|
|
193
212
|
|
|
194
213
|
async notify(method: string, params: any): Promise<void> {
|
|
195
214
|
try {
|
|
215
|
+
const sanitization = sanitizeToolResponsePayload(method, params);
|
|
216
|
+
if (sanitization.truncated) {
|
|
217
|
+
logToolResponseTruncation(sanitization.toolUseId);
|
|
218
|
+
}
|
|
219
|
+
const safeParams = sanitization.truncated
|
|
220
|
+
? sanitization.params
|
|
221
|
+
: params;
|
|
196
222
|
// Log RPC notification in debug mode
|
|
197
223
|
logger.debug(`[RPC] Sending notification: ${method}`, {
|
|
198
224
|
method,
|
|
199
|
-
params: JSON.stringify(
|
|
225
|
+
params: JSON.stringify(safeParams, null, 2),
|
|
200
226
|
});
|
|
201
227
|
|
|
202
228
|
// Send notification with retry logic
|
|
203
229
|
await this.sendToOrchestratorWithRetry({
|
|
204
230
|
jsonrpc: "2.0",
|
|
205
231
|
method,
|
|
206
|
-
params,
|
|
232
|
+
params: safeParams,
|
|
207
233
|
});
|
|
208
234
|
} catch (error) {
|
|
209
235
|
// Special handling for heartbeat errors - just log a simple line
|
|
@@ -224,13 +250,28 @@ export class RunnerApp implements IRunnerApp {
|
|
|
224
250
|
}
|
|
225
251
|
|
|
226
252
|
async sendToOrchestrator(message: JsonRpcMessage): Promise<any> {
|
|
253
|
+
const sanitization = sanitizeToolResponsePayload(
|
|
254
|
+
message.method,
|
|
255
|
+
message.params
|
|
256
|
+
);
|
|
257
|
+
if (sanitization.truncated) {
|
|
258
|
+
logToolResponseTruncation(sanitization.toolUseId);
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
const messageToSend = sanitization.truncated
|
|
262
|
+
? {
|
|
263
|
+
...message,
|
|
264
|
+
params: sanitization.params,
|
|
265
|
+
}
|
|
266
|
+
: message;
|
|
267
|
+
|
|
227
268
|
try {
|
|
228
269
|
// Log RPC request in debug mode
|
|
229
270
|
logger.debug(`[RPC] Sending request:`, {
|
|
230
|
-
method:
|
|
231
|
-
id:
|
|
232
|
-
params:
|
|
233
|
-
? JSON.stringify(
|
|
271
|
+
method: messageToSend.method,
|
|
272
|
+
id: messageToSend.id,
|
|
273
|
+
params: messageToSend.params
|
|
274
|
+
? JSON.stringify(messageToSend.params, null, 2)
|
|
234
275
|
: undefined,
|
|
235
276
|
});
|
|
236
277
|
|
|
@@ -250,7 +291,7 @@ export class RunnerApp implements IRunnerApp {
|
|
|
250
291
|
{
|
|
251
292
|
method: "POST",
|
|
252
293
|
headers,
|
|
253
|
-
body: JSON.stringify(
|
|
294
|
+
body: JSON.stringify(messageToSend),
|
|
254
295
|
signal: AbortSignal.timeout(30000), // 30 second timeout
|
|
255
296
|
}
|
|
256
297
|
);
|
|
@@ -264,8 +305,8 @@ export class RunnerApp implements IRunnerApp {
|
|
|
264
305
|
|
|
265
306
|
// Log RPC response in debug mode
|
|
266
307
|
logger.debug(`[RPC] Received response:`, {
|
|
267
|
-
method:
|
|
268
|
-
id:
|
|
308
|
+
method: messageToSend.method,
|
|
309
|
+
id: messageToSend.id,
|
|
269
310
|
result: result?.result
|
|
270
311
|
? JSON.stringify(result.result, null, 2)
|
|
271
312
|
: undefined,
|
|
@@ -288,8 +329,8 @@ export class RunnerApp implements IRunnerApp {
|
|
|
288
329
|
} else {
|
|
289
330
|
// For other RPC messages, log the attempted message and error
|
|
290
331
|
logger.error(`RPC failed:`, {
|
|
291
|
-
method:
|
|
292
|
-
params:
|
|
332
|
+
method: messageToSend.method,
|
|
333
|
+
params: messageToSend.params,
|
|
293
334
|
error: errorMessage,
|
|
294
335
|
});
|
|
295
336
|
}
|
|
@@ -302,7 +343,7 @@ export class RunnerApp implements IRunnerApp {
|
|
|
302
343
|
): ConversationContext | undefined {
|
|
303
344
|
// Using conversation.id as primary key for conversation tracking
|
|
304
345
|
const context = this.agentConversations.get(conversationId);
|
|
305
|
-
|
|
346
|
+
logger.debug(`[Runner] getConversationContext lookup:`, {
|
|
306
347
|
conversationId,
|
|
307
348
|
found: !!context,
|
|
308
349
|
totalConversations: this.agentConversations.size,
|
|
@@ -327,12 +368,12 @@ export class RunnerApp implements IRunnerApp {
|
|
|
327
368
|
`RunnerRepo validated: ${repo.name} at ${resolvedPath}`
|
|
328
369
|
);
|
|
329
370
|
} else {
|
|
330
|
-
logger.
|
|
371
|
+
logger.warn(
|
|
331
372
|
`RunnerRepo path is not a directory: ${repo.name} at ${resolvedPath}`
|
|
332
373
|
);
|
|
333
374
|
}
|
|
334
375
|
} catch (error) {
|
|
335
|
-
logger.
|
|
376
|
+
logger.warn(
|
|
336
377
|
`RunnerRepo path does not exist: ${repo.name} at ${repo.path}`
|
|
337
378
|
);
|
|
338
379
|
}
|
|
@@ -362,7 +403,7 @@ export class RunnerApp implements IRunnerApp {
|
|
|
362
403
|
logger.info(`Registration response:`, JSON.stringify(response, null, 2));
|
|
363
404
|
|
|
364
405
|
// Log the runnerRepos being sent and received
|
|
365
|
-
if (
|
|
406
|
+
if (isRunnerDebugEnabled()) {
|
|
366
407
|
logger.debug(
|
|
367
408
|
"Registration runnerRepos sent:",
|
|
368
409
|
JSON.stringify(filteredRunnerRepos)
|
|
@@ -424,7 +465,7 @@ export class RunnerApp implements IRunnerApp {
|
|
|
424
465
|
}
|
|
425
466
|
|
|
426
467
|
// Debug logging for registration details
|
|
427
|
-
if (
|
|
468
|
+
if (isRunnerDebugEnabled()) {
|
|
428
469
|
logger.debug("Registration complete with details", {
|
|
429
470
|
runnerId: this.config.runnerId,
|
|
430
471
|
runnerUid: this.runnerUid,
|
|
@@ -760,8 +801,9 @@ export class RunnerApp implements IRunnerApp {
|
|
|
760
801
|
|
|
761
802
|
for (const [conversationId, context] of this.agentConversations) {
|
|
762
803
|
if (context.status === "active" || context.status === "starting") {
|
|
804
|
+
const manager = this.getManagerForContext(context);
|
|
763
805
|
stopPromises.push(
|
|
764
|
-
|
|
806
|
+
manager
|
|
765
807
|
.stopConversation(context.agentSessionId, context, isRunnerShutdown)
|
|
766
808
|
.catch((error) => {
|
|
767
809
|
logger.error(
|
|
@@ -797,6 +839,9 @@ export class RunnerApp implements IRunnerApp {
|
|
|
797
839
|
get claudeManager_(): ClaudeManager {
|
|
798
840
|
return this.claudeManager;
|
|
799
841
|
}
|
|
842
|
+
get codexManager_(): CodexManager {
|
|
843
|
+
return this.codexManager;
|
|
844
|
+
}
|
|
800
845
|
get repositoryManager_(): EnhancedRepositoryManager {
|
|
801
846
|
return this.repositoryManager;
|
|
802
847
|
}
|
|
@@ -827,7 +872,7 @@ export class RunnerApp implements IRunnerApp {
|
|
|
827
872
|
logger.error("Failed to persist active status:", error);
|
|
828
873
|
});
|
|
829
874
|
|
|
830
|
-
if (
|
|
875
|
+
if (isRunnerDebugEnabled()) {
|
|
831
876
|
logger.debug("Active runner status changed", {
|
|
832
877
|
previous: previousState,
|
|
833
878
|
new: active,
|
|
@@ -841,7 +886,7 @@ export class RunnerApp implements IRunnerApp {
|
|
|
841
886
|
const previousTimestamp = this.lastProcessedAt;
|
|
842
887
|
this.lastProcessedAt = timestamp;
|
|
843
888
|
|
|
844
|
-
if (
|
|
889
|
+
if (isRunnerDebugEnabled()) {
|
|
845
890
|
logger.debug("LastProcessedAt updated", {
|
|
846
891
|
previous: previousTimestamp?.toISOString() || "null",
|
|
847
892
|
new: timestamp?.toISOString() || "null",
|
|
@@ -859,4 +904,14 @@ export class RunnerApp implements IRunnerApp {
|
|
|
859
904
|
setDelayFunction(fn: (ms: number) => Promise<void>): void {
|
|
860
905
|
this.delayFn = fn;
|
|
861
906
|
}
|
|
907
|
+
|
|
908
|
+
private getManagerForContext(
|
|
909
|
+
context?: ConversationContext | null
|
|
910
|
+
): ClaudeManager | CodexManager {
|
|
911
|
+
const provider = context?.provider?.toLowerCase();
|
|
912
|
+
if (provider === "openai") {
|
|
913
|
+
return this.codexManager;
|
|
914
|
+
}
|
|
915
|
+
return this.claudeManager;
|
|
916
|
+
}
|
|
862
917
|
}
|
package/src/types/claude.ts
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
5
|
import { Conversation } from "@botanicastudios/claude-code-sdk-ts";
|
|
6
|
+
import type { Thread } from "@northflare/codex-sdk";
|
|
6
7
|
|
|
7
8
|
// Repository information passed in conversation config
|
|
8
9
|
export interface RepositoryInfo {
|
|
@@ -25,6 +26,7 @@ export interface ConversationConfig {
|
|
|
25
26
|
repository?: RepositoryInfo; // Repository details from orchestrator
|
|
26
27
|
sessionId?: string; // For resume operations
|
|
27
28
|
runnerRepoPath?: string; // Path to local runner repo for local workspaces
|
|
29
|
+
codexAuth?: CodexAuthConfig;
|
|
28
30
|
}
|
|
29
31
|
|
|
30
32
|
// Internal conversation tracking
|
|
@@ -39,7 +41,9 @@ export interface ConversationContext {
|
|
|
39
41
|
config: ConversationConfig;
|
|
40
42
|
startedAt: Date;
|
|
41
43
|
lastActivityAt: Date;
|
|
42
|
-
conversation?: Conversation; //
|
|
44
|
+
conversation?: Conversation | Thread; // Conversation or Codex thread instance
|
|
45
|
+
provider?: "claude" | "openai" | string;
|
|
46
|
+
metadata?: Record<string, any>;
|
|
43
47
|
|
|
44
48
|
// Additional conversation details from database
|
|
45
49
|
model: string;
|
|
@@ -48,6 +52,13 @@ export interface ConversationContext {
|
|
|
48
52
|
permissionsMode: string;
|
|
49
53
|
}
|
|
50
54
|
|
|
55
|
+
export interface CodexAuthConfig {
|
|
56
|
+
accessToken: string;
|
|
57
|
+
idToken: string;
|
|
58
|
+
accountId: string;
|
|
59
|
+
lastRefresh?: string | null;
|
|
60
|
+
}
|
|
61
|
+
|
|
51
62
|
// Message type for initial messages
|
|
52
63
|
export interface Message {
|
|
53
64
|
content: string;
|
package/src/types/index.ts
CHANGED
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
import { RunnerConfig, ConversationContext, JsonRpcMessage } from './index';
|
|
6
6
|
import { ClaudeManager } from '../components/claude-sdk-manager';
|
|
7
|
+
import { CodexManager } from '../components/codex-sdk-manager';
|
|
7
8
|
import { EnhancedRepositoryManager } from '../components/enhanced-repository-manager';
|
|
8
9
|
|
|
9
10
|
export interface IRunnerApp {
|
|
@@ -18,6 +19,7 @@ export interface IRunnerApp {
|
|
|
18
19
|
get config_(): RunnerConfig;
|
|
19
20
|
get activeConversations_(): Map<string, ConversationContext>;
|
|
20
21
|
get claudeManager_(): ClaudeManager;
|
|
22
|
+
get codexManager_(): CodexManager;
|
|
21
23
|
get repositoryManager_(): EnhancedRepositoryManager;
|
|
22
24
|
|
|
23
25
|
// Runner state
|
|
@@ -31,4 +33,4 @@ export interface IRunnerApp {
|
|
|
31
33
|
|
|
32
34
|
// Optional methods for SSE implementation
|
|
33
35
|
updateLastProcessedAt?(timestamp: Date | null): Promise<void>;
|
|
34
|
-
}
|
|
36
|
+
}
|
package/src/utils/config.ts
CHANGED
|
@@ -294,6 +294,7 @@ export class ConfigManager {
|
|
|
294
294
|
NORTHFLARE_RUNNER_TOKEN: process.env["NORTHFLARE_RUNNER_TOKEN"]!,
|
|
295
295
|
NORTHFLARE_WORKSPACE_DIR: process.env["NORTHFLARE_WORKSPACE_DIR"]!,
|
|
296
296
|
NORTHFLARE_ORCHESTRATOR_URL: process.env["NORTHFLARE_ORCHESTRATOR_URL"]!,
|
|
297
|
+
NORTHFLARE_RUNNER_DEBUG: process.env["NORTHFLARE_RUNNER_DEBUG"],
|
|
297
298
|
DEBUG: process.env["DEBUG"],
|
|
298
299
|
};
|
|
299
300
|
}
|
package/src/utils/console.ts
CHANGED
|
@@ -2,7 +2,9 @@
|
|
|
2
2
|
* Console wrapper that suppresses output when not in debug mode
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
import { isRunnerDebugEnabled } from "./debug";
|
|
6
|
+
|
|
7
|
+
const isDebug = isRunnerDebugEnabled();
|
|
6
8
|
|
|
7
9
|
export const console = {
|
|
8
10
|
log: isDebug ? global.console.log.bind(global.console) : () => {},
|
|
@@ -10,4 +12,4 @@ export const console = {
|
|
|
10
12
|
error: global.console.error.bind(global.console), // Always show errors
|
|
11
13
|
info: isDebug ? global.console.info.bind(global.console) : () => {},
|
|
12
14
|
debug: isDebug ? global.console.debug.bind(global.console) : () => {},
|
|
13
|
-
};
|
|
15
|
+
};
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export function isRunnerDebugEnabled(): boolean {
|
|
2
|
+
const explicitFlag = process.env["NORTHFLARE_RUNNER_DEBUG"];
|
|
3
|
+
if (typeof explicitFlag === "string") {
|
|
4
|
+
return isTruthy(explicitFlag);
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
const legacyFlag = process.env["DEBUG"];
|
|
8
|
+
if (typeof legacyFlag === "string") {
|
|
9
|
+
return isTruthy(legacyFlag);
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
return false;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
function isTruthy(value: string): boolean {
|
|
16
|
+
const normalized = value.trim().toLowerCase();
|
|
17
|
+
return normalized === "true" || normalized === "1" || normalized === "yes" || normalized === "on";
|
|
18
|
+
}
|