replicas-engine 0.1.7 → 0.1.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/services/codex-manager.js +75 -11
- package/package.json +1 -1
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { Codex, Thread } from '@openai/codex-sdk';
|
|
2
|
+
import { randomUUID } from 'crypto';
|
|
2
3
|
import { findSessionFile, readJSONL } from '../utils/jsonl-reader.js';
|
|
3
4
|
export class CodexManager {
|
|
4
5
|
codex;
|
|
@@ -23,74 +24,133 @@ export class CodexManager {
|
|
|
23
24
|
}
|
|
24
25
|
}
|
|
25
26
|
async sendMessage(message) {
|
|
27
|
+
console.log(`[CodexManager] sendMessage called with message length: ${message.length}`);
|
|
26
28
|
if (!this.currentThread) {
|
|
27
29
|
if (this.currentThreadId) {
|
|
28
|
-
console.log(`Resuming thread ${this.currentThreadId}`);
|
|
30
|
+
console.log(`[CodexManager] Resuming existing thread: ${this.currentThreadId}`);
|
|
29
31
|
this.currentThread = this.codex.resumeThread(this.currentThreadId, {
|
|
30
32
|
workingDirectory: this.workingDirectory,
|
|
31
33
|
skipGitRepoCheck: true,
|
|
32
34
|
sandboxMode: 'danger-full-access',
|
|
33
35
|
});
|
|
36
|
+
console.log(`[CodexManager] Thread resumed successfully`);
|
|
34
37
|
}
|
|
35
38
|
else {
|
|
36
|
-
console.log('
|
|
39
|
+
console.log('[CodexManager] No existing thread, starting new thread');
|
|
40
|
+
console.log(`[CodexManager] Working directory: ${this.workingDirectory}`);
|
|
37
41
|
this.currentThread = this.codex.startThread({
|
|
38
42
|
workingDirectory: this.workingDirectory,
|
|
39
43
|
skipGitRepoCheck: true,
|
|
40
44
|
sandboxMode: 'danger-full-access',
|
|
41
45
|
});
|
|
46
|
+
if (this.currentThread.id) {
|
|
47
|
+
this.currentThreadId = this.currentThread.id;
|
|
48
|
+
console.log(`[CodexManager] New thread created with ID: ${this.currentThreadId}`);
|
|
49
|
+
}
|
|
50
|
+
else {
|
|
51
|
+
console.error('[CodexManager] ERROR: Thread created but no ID available');
|
|
52
|
+
}
|
|
53
|
+
// prime the thread with system instructions if thread is new
|
|
54
|
+
const workspaceName = process.env.WORKSPACE_NAME || 'workspace';
|
|
55
|
+
console.log(`[CodexManager] Workspace name from env: ${workspaceName}`);
|
|
56
|
+
const workspaceBranchSegment = workspaceName
|
|
57
|
+
.trim()
|
|
58
|
+
.toLowerCase()
|
|
59
|
+
.replace(/[^a-z0-9]+/g, '-')
|
|
60
|
+
.replace(/^-+|-+$/g, '') || 'workspace';
|
|
61
|
+
const uuid = randomUUID().slice(0, 8);
|
|
62
|
+
const branchName = `replicas/${workspaceBranchSegment}-${uuid}`;
|
|
63
|
+
console.log(`[CodexManager] Generated branch name: ${branchName}`);
|
|
64
|
+
const systemMessage = `<replicas_important_instructions>When completing solutions, push your changes to branch ${branchName} and to origin. Greet the user.</replicas_important_instructions>`;
|
|
65
|
+
console.log('[CodexManager] Starting thread priming with system instructions');
|
|
66
|
+
const primingStartTime = Date.now();
|
|
67
|
+
await this.currentThread.run(systemMessage);
|
|
68
|
+
const primingDuration = Date.now() - primingStartTime;
|
|
69
|
+
console.log(`[CodexManager] Thread priming completed in ${primingDuration}ms`);
|
|
42
70
|
}
|
|
43
71
|
}
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
this.currentThreadId = this.currentThread.id;
|
|
47
|
-
console.log(`Thread started: ${this.currentThreadId}`);
|
|
72
|
+
else {
|
|
73
|
+
console.log(`[CodexManager] Using existing thread object for thread ID: ${this.currentThreadId}`);
|
|
48
74
|
}
|
|
75
|
+
console.log(`[CodexManager] Running user message on thread ${this.currentThreadId}`);
|
|
76
|
+
const messageStartTime = Date.now();
|
|
77
|
+
await this.currentThread.run(message);
|
|
78
|
+
const messageDuration = Date.now() - messageStartTime;
|
|
79
|
+
console.log(`[CodexManager] User message run completed in ${messageDuration}ms`);
|
|
49
80
|
}
|
|
50
81
|
async getHistory() {
|
|
82
|
+
console.log('[CodexManager] getHistory called');
|
|
51
83
|
if (!this.currentThreadId) {
|
|
84
|
+
console.log('[CodexManager] No active thread ID, returning empty history');
|
|
52
85
|
return {
|
|
53
86
|
thread_id: null,
|
|
54
87
|
events: [],
|
|
55
88
|
};
|
|
56
89
|
}
|
|
90
|
+
console.log(`[CodexManager] Looking for session file for thread: ${this.currentThreadId}`);
|
|
57
91
|
const sessionFile = await findSessionFile(this.currentThreadId);
|
|
58
92
|
if (!sessionFile) {
|
|
59
|
-
console.warn(`Session file not found for thread ${this.currentThreadId}`);
|
|
93
|
+
console.warn(`[CodexManager] WARNING: Session file not found for thread ${this.currentThreadId}`);
|
|
60
94
|
return {
|
|
61
95
|
thread_id: this.currentThreadId,
|
|
62
96
|
events: [],
|
|
63
97
|
};
|
|
64
98
|
}
|
|
65
|
-
console.log(`Reading session file: ${sessionFile}`);
|
|
99
|
+
console.log(`[CodexManager] Reading session file: ${sessionFile}`);
|
|
66
100
|
const events = await readJSONL(sessionFile);
|
|
101
|
+
console.log(`[CodexManager] Read ${events.length} events from session file`);
|
|
102
|
+
const filteredEvents = events.filter((event) => {
|
|
103
|
+
const eventStr = JSON.stringify(event);
|
|
104
|
+
return !eventStr.includes('<replicas_important_instructions>');
|
|
105
|
+
});
|
|
106
|
+
const filteredCount = events.length - filteredEvents.length;
|
|
107
|
+
if (filteredCount > 0) {
|
|
108
|
+
console.log(`[CodexManager] Filtered out ${filteredCount} priming events`);
|
|
109
|
+
}
|
|
110
|
+
console.log(`[CodexManager] Returning ${filteredEvents.length} events`);
|
|
67
111
|
return {
|
|
68
112
|
thread_id: this.currentThreadId,
|
|
69
|
-
events,
|
|
113
|
+
events: filteredEvents,
|
|
70
114
|
};
|
|
71
115
|
}
|
|
72
116
|
async getStatus() {
|
|
117
|
+
console.log('[CodexManager] getStatus called');
|
|
73
118
|
let sessionFile = null;
|
|
74
119
|
if (this.currentThreadId) {
|
|
120
|
+
console.log(`[CodexManager] Checking for session file for thread: ${this.currentThreadId}`);
|
|
75
121
|
sessionFile = await findSessionFile(this.currentThreadId);
|
|
122
|
+
if (sessionFile) {
|
|
123
|
+
console.log(`[CodexManager] Session file found: ${sessionFile}`);
|
|
124
|
+
}
|
|
125
|
+
else {
|
|
126
|
+
console.log('[CodexManager] Session file not found');
|
|
127
|
+
}
|
|
76
128
|
}
|
|
77
|
-
|
|
129
|
+
else {
|
|
130
|
+
console.log('[CodexManager] No active thread ID');
|
|
131
|
+
}
|
|
132
|
+
const status = {
|
|
78
133
|
has_active_thread: this.currentThreadId !== null,
|
|
79
134
|
thread_id: this.currentThreadId,
|
|
80
135
|
session_file: sessionFile,
|
|
81
136
|
working_directory: this.workingDirectory,
|
|
82
137
|
};
|
|
138
|
+
console.log(`[CodexManager] Status: ${JSON.stringify(status)}`);
|
|
139
|
+
return status;
|
|
83
140
|
}
|
|
84
141
|
reset() {
|
|
85
|
-
console.log(
|
|
142
|
+
console.log(`[CodexManager] Resetting thread (was: ${this.currentThreadId})`);
|
|
86
143
|
this.currentThread = null;
|
|
87
144
|
this.currentThreadId = null;
|
|
145
|
+
console.log('[CodexManager] Thread reset complete');
|
|
88
146
|
}
|
|
89
147
|
getThreadId() {
|
|
90
148
|
return this.currentThreadId;
|
|
91
149
|
}
|
|
92
150
|
async getUpdates(since) {
|
|
151
|
+
console.log(`[CodexManager] getUpdates called with since: ${since}`);
|
|
93
152
|
if (!this.currentThreadId) {
|
|
153
|
+
console.log('[CodexManager] No active thread, returning empty updates');
|
|
94
154
|
return {
|
|
95
155
|
events: [],
|
|
96
156
|
isComplete: true,
|
|
@@ -98,20 +158,24 @@ export class CodexManager {
|
|
|
98
158
|
}
|
|
99
159
|
const sessionFile = await findSessionFile(this.currentThreadId);
|
|
100
160
|
if (!sessionFile) {
|
|
161
|
+
console.log('[CodexManager] Session file not found, returning empty updates');
|
|
101
162
|
return {
|
|
102
163
|
events: [],
|
|
103
164
|
isComplete: true,
|
|
104
165
|
};
|
|
105
166
|
}
|
|
106
167
|
const allEvents = await readJSONL(sessionFile);
|
|
168
|
+
console.log(`[CodexManager] Read ${allEvents.length} total events`);
|
|
107
169
|
// Filter events that occurred after the 'since' timestamp
|
|
108
170
|
const filteredEvents = allEvents.filter((event) => {
|
|
109
171
|
return event.timestamp > since;
|
|
110
172
|
});
|
|
173
|
+
console.log(`[CodexManager] Found ${filteredEvents.length} events since ${since}`);
|
|
111
174
|
// Check if thread is complete by looking for turn.completed or error events
|
|
112
175
|
const isComplete = this.currentThread === null ||
|
|
113
176
|
allEvents.some((event) => event.type === 'event_msg' &&
|
|
114
177
|
(event.payload?.type === 'turn.completed' || event.payload?.type === 'error'));
|
|
178
|
+
console.log(`[CodexManager] Thread complete: ${isComplete}`);
|
|
115
179
|
return {
|
|
116
180
|
events: filteredEvents,
|
|
117
181
|
isComplete,
|