@northflare/runner 0.0.8 → 0.0.9
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 +25 -12
- package/dist/components/claude-sdk-manager.js.map +1 -1
- package/dist/components/codex-sdk-manager.d.ts +58 -0
- package/dist/components/codex-sdk-manager.d.ts.map +1 -0
- package/dist/components/codex-sdk-manager.js +907 -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 +51 -7
- package/dist/components/message-handler-sse.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 +145 -15
- package/dist/runner-sse.js.map +1 -1
- package/dist/types/claude.d.ts +11 -1
- package/dist/types/claude.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/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 +2 -2
- package/dist/utils/status-line.js +5 -5
- package/dist/utils/status-line.js.map +1 -1
- 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 +2 -0
- package/src/components/claude-sdk-manager.ts +33 -13
- package/src/components/codex-sdk-manager.ts +1248 -0
- package/src/components/message-handler-sse.ts +79 -8
- package/src/runner-sse.ts +174 -15
- package/src/types/claude.ts +12 -1
- package/src/types/runner-interface.ts +3 -1
- package/src/utils/model.ts +29 -0
- package/src/utils/status-line.ts +6 -6
- package/src/utils/codex-sdk.js +0 -448
- package/src/utils/sdk-demo.js +0 -34
|
@@ -3,7 +3,12 @@
|
|
|
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";
|
|
@@ -499,8 +504,11 @@ export class MessageHandler {
|
|
|
499
504
|
}
|
|
500
505
|
);
|
|
501
506
|
|
|
507
|
+
const provider = this.resolveAgentProvider(conversationData, config);
|
|
508
|
+
const manager = this.getManagerForProvider(provider);
|
|
509
|
+
|
|
502
510
|
// Start the conversation with the provided/loaded conversation details
|
|
503
|
-
await
|
|
511
|
+
await manager.startConversation(
|
|
504
512
|
finalObjectType,
|
|
505
513
|
finalObjectId,
|
|
506
514
|
config,
|
|
@@ -551,7 +559,8 @@ export class MessageHandler {
|
|
|
551
559
|
|
|
552
560
|
if (context && targetConversationId) {
|
|
553
561
|
context.status = "stopping";
|
|
554
|
-
|
|
562
|
+
const manager = this.getManagerForConversationContext(context);
|
|
563
|
+
await manager.stopConversation(
|
|
555
564
|
context.agentSessionId,
|
|
556
565
|
context,
|
|
557
566
|
false, // Not a runner shutdown
|
|
@@ -611,7 +620,9 @@ export class MessageHandler {
|
|
|
611
620
|
throw new Error("Cannot resume conversation without agentSessionId");
|
|
612
621
|
}
|
|
613
622
|
|
|
614
|
-
|
|
623
|
+
const provider = this.resolveAgentProvider(conversationData, config);
|
|
624
|
+
const manager = this.getManagerForProvider(provider);
|
|
625
|
+
await manager.resumeConversation(
|
|
615
626
|
conversationData.objectType,
|
|
616
627
|
conversationData.objectId,
|
|
617
628
|
agentSessionId,
|
|
@@ -666,7 +677,9 @@ export class MessageHandler {
|
|
|
666
677
|
);
|
|
667
678
|
|
|
668
679
|
// Stop the current conversation
|
|
669
|
-
|
|
680
|
+
const manager = this.getManagerForConversationContext(context);
|
|
681
|
+
|
|
682
|
+
await manager.stopConversation(
|
|
670
683
|
context.agentSessionId,
|
|
671
684
|
context,
|
|
672
685
|
false // Not a runner shutdown, just updating config
|
|
@@ -680,7 +693,7 @@ export class MessageHandler {
|
|
|
680
693
|
);
|
|
681
694
|
|
|
682
695
|
// Resume with new config
|
|
683
|
-
await
|
|
696
|
+
await manager.resumeConversation(
|
|
684
697
|
context.conversationObjectType,
|
|
685
698
|
context.conversationObjectId,
|
|
686
699
|
context.agentSessionId,
|
|
@@ -717,6 +730,7 @@ export class MessageHandler {
|
|
|
717
730
|
conversationObjectType = message.conversationObjectType || "Task",
|
|
718
731
|
conversationObjectId = message.conversationObjectId,
|
|
719
732
|
conversation,
|
|
733
|
+
agentSessionId,
|
|
720
734
|
} = params;
|
|
721
735
|
|
|
722
736
|
// Validate required parameters
|
|
@@ -728,13 +742,21 @@ export class MessageHandler {
|
|
|
728
742
|
throw new Error("Missing required parameter: content");
|
|
729
743
|
}
|
|
730
744
|
|
|
731
|
-
|
|
745
|
+
const existingContext = this.runner.getConversationContext(conversationId);
|
|
746
|
+
const manager = existingContext
|
|
747
|
+
? this.getManagerForConversationContext(existingContext)
|
|
748
|
+
: this.getManagerForProvider(
|
|
749
|
+
this.resolveAgentProvider(conversation, config)
|
|
750
|
+
);
|
|
751
|
+
|
|
752
|
+
await manager.sendUserMessage(
|
|
732
753
|
conversationId,
|
|
733
754
|
content,
|
|
734
755
|
config,
|
|
735
756
|
conversationObjectType,
|
|
736
757
|
conversationObjectId,
|
|
737
|
-
conversation
|
|
758
|
+
conversation,
|
|
759
|
+
agentSessionId
|
|
738
760
|
);
|
|
739
761
|
}
|
|
740
762
|
|
|
@@ -1022,4 +1044,53 @@ export class MessageHandler {
|
|
|
1022
1044
|
timestamp: new Date(),
|
|
1023
1045
|
});
|
|
1024
1046
|
}
|
|
1047
|
+
|
|
1048
|
+
private resolveAgentProvider(
|
|
1049
|
+
conversation?: {
|
|
1050
|
+
providerType?: string;
|
|
1051
|
+
agentProviderType?: string;
|
|
1052
|
+
model?: string;
|
|
1053
|
+
},
|
|
1054
|
+
config?: ConversationConfig
|
|
1055
|
+
): "openai" | "claude" {
|
|
1056
|
+
const explicitProvider =
|
|
1057
|
+
conversation?.providerType ||
|
|
1058
|
+
conversation?.agentProviderType ||
|
|
1059
|
+
(config as any)?.providerType ||
|
|
1060
|
+
(config as any)?.agentProviderType;
|
|
1061
|
+
|
|
1062
|
+
if (typeof explicitProvider === "string") {
|
|
1063
|
+
const normalized = explicitProvider.toLowerCase();
|
|
1064
|
+
if (normalized === "openai") return "openai";
|
|
1065
|
+
if (normalized === "claude") return "claude";
|
|
1066
|
+
}
|
|
1067
|
+
|
|
1068
|
+
const model =
|
|
1069
|
+
conversation?.model ||
|
|
1070
|
+
(config as any)?.model ||
|
|
1071
|
+
(config as any)?.defaultModel ||
|
|
1072
|
+
"";
|
|
1073
|
+
const normalizedModel = model.toLowerCase();
|
|
1074
|
+
|
|
1075
|
+
const looksLikeCodex =
|
|
1076
|
+
normalizedModel.includes("gpt") ||
|
|
1077
|
+
/^o\d/.test(normalizedModel) ||
|
|
1078
|
+
normalizedModel.includes("openai") ||
|
|
1079
|
+
normalizedModel.includes("codex");
|
|
1080
|
+
|
|
1081
|
+
return looksLikeCodex ? "openai" : "claude";
|
|
1082
|
+
}
|
|
1083
|
+
|
|
1084
|
+
private getManagerForProvider(provider?: string) {
|
|
1085
|
+
if (provider?.toLowerCase() === "openai") {
|
|
1086
|
+
return this.runner.codexManager_;
|
|
1087
|
+
}
|
|
1088
|
+
return this.runner.claudeManager_;
|
|
1089
|
+
}
|
|
1090
|
+
|
|
1091
|
+
private getManagerForConversationContext(context: ConversationContext) {
|
|
1092
|
+
return context.provider === "openai"
|
|
1093
|
+
? this.runner.codexManager_
|
|
1094
|
+
: this.runner.claudeManager_;
|
|
1095
|
+
}
|
|
1025
1096
|
}
|
package/src/runner-sse.ts
CHANGED
|
@@ -13,6 +13,7 @@ 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";
|
|
@@ -23,9 +24,137 @@ import computerName from "computer-name";
|
|
|
23
24
|
|
|
24
25
|
const logger = createLogger("RunnerApp");
|
|
25
26
|
|
|
27
|
+
const TOOL_RESPONSE_BYTE_LIMIT = 500 * 1024; // 500 KiB per tool response field
|
|
28
|
+
const TOOL_RESPONSE_SUFFIX = "... [truncated]";
|
|
29
|
+
|
|
30
|
+
function sanitizeToolResponsePayload(
|
|
31
|
+
method: string | undefined,
|
|
32
|
+
params: any
|
|
33
|
+
): any {
|
|
34
|
+
if (method !== "message.agent" || !params) {
|
|
35
|
+
return params;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
if (!isToolResultPayload(params)) {
|
|
39
|
+
return params;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
const [sanitized, changed] = truncateStringsRecursively(params);
|
|
43
|
+
if (!changed) {
|
|
44
|
+
return params;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
const toolUseId = extractToolUseId(params);
|
|
48
|
+
const message = `Tool response exceeded ${TOOL_RESPONSE_BYTE_LIMIT} bytes and was truncated`;
|
|
49
|
+
if (toolUseId) {
|
|
50
|
+
logger.warn(message, { toolUseId });
|
|
51
|
+
} else {
|
|
52
|
+
logger.warn(message);
|
|
53
|
+
}
|
|
54
|
+
return sanitized;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function isToolResultPayload(payload: any): boolean {
|
|
58
|
+
if (!payload) {
|
|
59
|
+
return false;
|
|
60
|
+
}
|
|
61
|
+
if (payload.type === "tool_result" || payload.subtype === "tool_result") {
|
|
62
|
+
return true;
|
|
63
|
+
}
|
|
64
|
+
if (Array.isArray(payload.content)) {
|
|
65
|
+
return payload.content.some((entry: any) => isToolResultBlock(entry));
|
|
66
|
+
}
|
|
67
|
+
return isToolResultBlock(payload.content);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
function isToolResultBlock(block: any): boolean {
|
|
71
|
+
if (!block) {
|
|
72
|
+
return false;
|
|
73
|
+
}
|
|
74
|
+
return (
|
|
75
|
+
block.type === "tool_result" ||
|
|
76
|
+
block.subtype === "tool_result" ||
|
|
77
|
+
typeof block.tool_use_id === "string"
|
|
78
|
+
);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
function extractToolUseId(payload: any): string | undefined {
|
|
82
|
+
if (!payload) {
|
|
83
|
+
return undefined;
|
|
84
|
+
}
|
|
85
|
+
if (typeof payload.tool_use_id === "string") {
|
|
86
|
+
return payload.tool_use_id;
|
|
87
|
+
}
|
|
88
|
+
if (Array.isArray(payload.content)) {
|
|
89
|
+
const match = payload.content.find(
|
|
90
|
+
(entry: any) => entry && typeof entry.tool_use_id === "string"
|
|
91
|
+
);
|
|
92
|
+
if (match) {
|
|
93
|
+
return match.tool_use_id;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
if (payload.content && typeof payload.content === "object") {
|
|
97
|
+
return extractToolUseId(payload.content);
|
|
98
|
+
}
|
|
99
|
+
return undefined;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
function truncateStringsRecursively(value: any): [any, boolean] {
|
|
103
|
+
if (typeof value === "string") {
|
|
104
|
+
return truncateStringValue(value);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
if (Array.isArray(value)) {
|
|
108
|
+
let mutated = false;
|
|
109
|
+
let result: any[] = value;
|
|
110
|
+
for (let i = 0; i < value.length; i++) {
|
|
111
|
+
const [newItem, changed] = truncateStringsRecursively(value[i]);
|
|
112
|
+
if (changed) {
|
|
113
|
+
if (!mutated) {
|
|
114
|
+
result = value.slice();
|
|
115
|
+
mutated = true;
|
|
116
|
+
}
|
|
117
|
+
result[i] = newItem;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
return [result, mutated];
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
if (value && typeof value === "object") {
|
|
124
|
+
let mutated = false;
|
|
125
|
+
let result: any = value;
|
|
126
|
+
for (const key of Object.keys(value)) {
|
|
127
|
+
const [newVal, changed] = truncateStringsRecursively(value[key]);
|
|
128
|
+
if (changed) {
|
|
129
|
+
if (!mutated) {
|
|
130
|
+
result = { ...value };
|
|
131
|
+
mutated = true;
|
|
132
|
+
}
|
|
133
|
+
result[key] = newVal;
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
return [result, mutated];
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
return [value, false];
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
function truncateStringValue(value: string): [string, boolean] {
|
|
143
|
+
const byteLength = Buffer.byteLength(value, "utf8");
|
|
144
|
+
if (byteLength <= TOOL_RESPONSE_BYTE_LIMIT) {
|
|
145
|
+
return [value, false];
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
const suffixBytes = Buffer.byteLength(TOOL_RESPONSE_SUFFIX, "utf8");
|
|
149
|
+
const maxBytes = Math.max(0, TOOL_RESPONSE_BYTE_LIMIT - suffixBytes);
|
|
150
|
+
const truncatedBuffer = Buffer.from(value, "utf8").subarray(0, maxBytes);
|
|
151
|
+
return [truncatedBuffer.toString("utf8") + TOOL_RESPONSE_SUFFIX, true];
|
|
152
|
+
}
|
|
153
|
+
|
|
26
154
|
export class RunnerApp implements IRunnerApp {
|
|
27
155
|
private messageHandler!: MessageHandler;
|
|
28
156
|
private claudeManager!: ClaudeManager;
|
|
157
|
+
private codexManager!: CodexManager;
|
|
29
158
|
private repositoryManager!: EnhancedRepositoryManager;
|
|
30
159
|
private stateManager!: StateManager;
|
|
31
160
|
private agentConversations: Map<string, ConversationContext>; // Keyed by conversation.id
|
|
@@ -91,6 +220,9 @@ export class RunnerApp implements IRunnerApp {
|
|
|
91
220
|
// Initialize Claude manager with repository manager (using SDK-native manager)
|
|
92
221
|
this.claudeManager = new ClaudeManager(this, this.repositoryManager);
|
|
93
222
|
|
|
223
|
+
// Initialize Codex manager for OpenAI-based conversations
|
|
224
|
+
this.codexManager = new CodexManager(this, this.repositoryManager);
|
|
225
|
+
|
|
94
226
|
// Initialize message handler with SSE support
|
|
95
227
|
this.messageHandler = new MessageHandler(this);
|
|
96
228
|
}
|
|
@@ -193,17 +325,18 @@ export class RunnerApp implements IRunnerApp {
|
|
|
193
325
|
|
|
194
326
|
async notify(method: string, params: any): Promise<void> {
|
|
195
327
|
try {
|
|
328
|
+
const safeParams = sanitizeToolResponsePayload(method, params);
|
|
196
329
|
// Log RPC notification in debug mode
|
|
197
330
|
logger.debug(`[RPC] Sending notification: ${method}`, {
|
|
198
331
|
method,
|
|
199
|
-
params: JSON.stringify(
|
|
332
|
+
params: JSON.stringify(safeParams, null, 2),
|
|
200
333
|
});
|
|
201
334
|
|
|
202
335
|
// Send notification with retry logic
|
|
203
336
|
await this.sendToOrchestratorWithRetry({
|
|
204
337
|
jsonrpc: "2.0",
|
|
205
338
|
method,
|
|
206
|
-
params,
|
|
339
|
+
params: safeParams,
|
|
207
340
|
});
|
|
208
341
|
} catch (error) {
|
|
209
342
|
// Special handling for heartbeat errors - just log a simple line
|
|
@@ -224,13 +357,25 @@ export class RunnerApp implements IRunnerApp {
|
|
|
224
357
|
}
|
|
225
358
|
|
|
226
359
|
async sendToOrchestrator(message: JsonRpcMessage): Promise<any> {
|
|
360
|
+
const sanitizedParams = sanitizeToolResponsePayload(
|
|
361
|
+
message.method,
|
|
362
|
+
message.params
|
|
363
|
+
);
|
|
364
|
+
const messageToSend =
|
|
365
|
+
sanitizedParams === message.params
|
|
366
|
+
? message
|
|
367
|
+
: {
|
|
368
|
+
...message,
|
|
369
|
+
params: sanitizedParams,
|
|
370
|
+
};
|
|
371
|
+
|
|
227
372
|
try {
|
|
228
373
|
// Log RPC request in debug mode
|
|
229
374
|
logger.debug(`[RPC] Sending request:`, {
|
|
230
|
-
method:
|
|
231
|
-
id:
|
|
232
|
-
params:
|
|
233
|
-
? JSON.stringify(
|
|
375
|
+
method: messageToSend.method,
|
|
376
|
+
id: messageToSend.id,
|
|
377
|
+
params: messageToSend.params
|
|
378
|
+
? JSON.stringify(messageToSend.params, null, 2)
|
|
234
379
|
: undefined,
|
|
235
380
|
});
|
|
236
381
|
|
|
@@ -250,7 +395,7 @@ export class RunnerApp implements IRunnerApp {
|
|
|
250
395
|
{
|
|
251
396
|
method: "POST",
|
|
252
397
|
headers,
|
|
253
|
-
body: JSON.stringify(
|
|
398
|
+
body: JSON.stringify(messageToSend),
|
|
254
399
|
signal: AbortSignal.timeout(30000), // 30 second timeout
|
|
255
400
|
}
|
|
256
401
|
);
|
|
@@ -264,8 +409,8 @@ export class RunnerApp implements IRunnerApp {
|
|
|
264
409
|
|
|
265
410
|
// Log RPC response in debug mode
|
|
266
411
|
logger.debug(`[RPC] Received response:`, {
|
|
267
|
-
method:
|
|
268
|
-
id:
|
|
412
|
+
method: messageToSend.method,
|
|
413
|
+
id: messageToSend.id,
|
|
269
414
|
result: result?.result
|
|
270
415
|
? JSON.stringify(result.result, null, 2)
|
|
271
416
|
: undefined,
|
|
@@ -288,8 +433,8 @@ export class RunnerApp implements IRunnerApp {
|
|
|
288
433
|
} else {
|
|
289
434
|
// For other RPC messages, log the attempted message and error
|
|
290
435
|
logger.error(`RPC failed:`, {
|
|
291
|
-
method:
|
|
292
|
-
params:
|
|
436
|
+
method: messageToSend.method,
|
|
437
|
+
params: messageToSend.params,
|
|
293
438
|
error: errorMessage,
|
|
294
439
|
});
|
|
295
440
|
}
|
|
@@ -302,7 +447,7 @@ export class RunnerApp implements IRunnerApp {
|
|
|
302
447
|
): ConversationContext | undefined {
|
|
303
448
|
// Using conversation.id as primary key for conversation tracking
|
|
304
449
|
const context = this.agentConversations.get(conversationId);
|
|
305
|
-
|
|
450
|
+
logger.debug(`[Runner] getConversationContext lookup:`, {
|
|
306
451
|
conversationId,
|
|
307
452
|
found: !!context,
|
|
308
453
|
totalConversations: this.agentConversations.size,
|
|
@@ -327,12 +472,12 @@ export class RunnerApp implements IRunnerApp {
|
|
|
327
472
|
`RunnerRepo validated: ${repo.name} at ${resolvedPath}`
|
|
328
473
|
);
|
|
329
474
|
} else {
|
|
330
|
-
logger.
|
|
475
|
+
logger.warn(
|
|
331
476
|
`RunnerRepo path is not a directory: ${repo.name} at ${resolvedPath}`
|
|
332
477
|
);
|
|
333
478
|
}
|
|
334
479
|
} catch (error) {
|
|
335
|
-
logger.
|
|
480
|
+
logger.warn(
|
|
336
481
|
`RunnerRepo path does not exist: ${repo.name} at ${repo.path}`
|
|
337
482
|
);
|
|
338
483
|
}
|
|
@@ -760,8 +905,9 @@ export class RunnerApp implements IRunnerApp {
|
|
|
760
905
|
|
|
761
906
|
for (const [conversationId, context] of this.agentConversations) {
|
|
762
907
|
if (context.status === "active" || context.status === "starting") {
|
|
908
|
+
const manager = this.getManagerForContext(context);
|
|
763
909
|
stopPromises.push(
|
|
764
|
-
|
|
910
|
+
manager
|
|
765
911
|
.stopConversation(context.agentSessionId, context, isRunnerShutdown)
|
|
766
912
|
.catch((error) => {
|
|
767
913
|
logger.error(
|
|
@@ -797,6 +943,9 @@ export class RunnerApp implements IRunnerApp {
|
|
|
797
943
|
get claudeManager_(): ClaudeManager {
|
|
798
944
|
return this.claudeManager;
|
|
799
945
|
}
|
|
946
|
+
get codexManager_(): CodexManager {
|
|
947
|
+
return this.codexManager;
|
|
948
|
+
}
|
|
800
949
|
get repositoryManager_(): EnhancedRepositoryManager {
|
|
801
950
|
return this.repositoryManager;
|
|
802
951
|
}
|
|
@@ -859,4 +1008,14 @@ export class RunnerApp implements IRunnerApp {
|
|
|
859
1008
|
setDelayFunction(fn: (ms: number) => Promise<void>): void {
|
|
860
1009
|
this.delayFn = fn;
|
|
861
1010
|
}
|
|
1011
|
+
|
|
1012
|
+
private getManagerForContext(
|
|
1013
|
+
context?: ConversationContext | null
|
|
1014
|
+
): ClaudeManager | CodexManager {
|
|
1015
|
+
const provider = context?.provider?.toLowerCase();
|
|
1016
|
+
if (provider === "openai") {
|
|
1017
|
+
return this.codexManager;
|
|
1018
|
+
}
|
|
1019
|
+
return this.claudeManager;
|
|
1020
|
+
}
|
|
862
1021
|
}
|
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;
|
|
@@ -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
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
export type ModelReasoningEffort = "low" | "medium" | "high";
|
|
2
|
+
|
|
3
|
+
const REASONING_VALUES: readonly ModelReasoningEffort[] = [
|
|
4
|
+
"low",
|
|
5
|
+
"medium",
|
|
6
|
+
"high",
|
|
7
|
+
];
|
|
8
|
+
|
|
9
|
+
export function parseModelValue(value?: string | null): {
|
|
10
|
+
baseModel?: string;
|
|
11
|
+
reasoningEffort?: ModelReasoningEffort;
|
|
12
|
+
} {
|
|
13
|
+
if (!value) {
|
|
14
|
+
return {};
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
const [model, possibleEffort] = value.split(":");
|
|
18
|
+
if (
|
|
19
|
+
possibleEffort &&
|
|
20
|
+
REASONING_VALUES.includes(possibleEffort as ModelReasoningEffort)
|
|
21
|
+
) {
|
|
22
|
+
return {
|
|
23
|
+
baseModel: model,
|
|
24
|
+
reasoningEffort: possibleEffort as ModelReasoningEffort,
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
return { baseModel: value };
|
|
29
|
+
}
|
package/src/utils/status-line.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* StatusLineManager - Manages persistent status line output for active
|
|
2
|
+
* StatusLineManager - Manages persistent status line output for active agent processes
|
|
3
3
|
*
|
|
4
4
|
* This component maintains a single-line status output that updates every minute to show
|
|
5
|
-
* the count of active
|
|
5
|
+
* the count of active agent processes. It prevents the machine from entering idle
|
|
6
6
|
* state while processes are running and provides clear visual feedback without cluttering
|
|
7
7
|
* the terminal with multiple log lines.
|
|
8
8
|
*/
|
|
@@ -84,11 +84,11 @@ export class StatusLineManager {
|
|
|
84
84
|
|
|
85
85
|
let newLine: string;
|
|
86
86
|
if (this.activeCount === 0) {
|
|
87
|
-
newLine = "No active
|
|
87
|
+
newLine = "No active agent processes";
|
|
88
88
|
} else if (this.activeCount === 1) {
|
|
89
|
-
newLine = `${timeStr} 1 active
|
|
89
|
+
newLine = `${timeStr} 1 active agent process`;
|
|
90
90
|
} else {
|
|
91
|
-
newLine = `${timeStr} ${this.activeCount} active
|
|
91
|
+
newLine = `${timeStr} ${this.activeCount} active agent processes`;
|
|
92
92
|
}
|
|
93
93
|
|
|
94
94
|
// If this is the first status line, position it
|
|
@@ -118,4 +118,4 @@ export class StatusLineManager {
|
|
|
118
118
|
}
|
|
119
119
|
|
|
120
120
|
// Singleton instance
|
|
121
|
-
export const statusLineManager = new StatusLineManager();
|
|
121
|
+
export const statusLineManager = new StatusLineManager();
|