@jskit-ai/assistant-core 0.1.240 → 0.1.242
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/examples/conversation/package.json +5 -5
- package/package.json +5 -5
- package/src/client/conversation/AssistantTranscript.vue +26 -29
- package/src/client/conversation/LongTextPreviewBlocks.vue +11 -0
- package/src/client/conversation/messageDelivery.js +8 -2
- package/src/client/conversation/useAssistantAttachments.js +1 -1
- package/src/server/conversation/agentRun.js +12 -198
- package/src/server/conversation/attachments.js +6 -5
- package/src/server/conversation/boundedToolLoop.js +160 -0
- package/src/server/conversation/claudeHistory.js +37 -23
- package/src/server/conversation/claudeProcess.js +2 -2
- package/src/server/conversation/claudeTurn.js +41 -38
- package/src/server/conversation/codexAuthPreflight.js +104 -0
- package/src/server/conversation/codexClient.js +11 -16
- package/src/server/conversation/codexConfiguration.js +112 -98
- package/src/server/conversation/codexConversationStore.js +189 -0
- package/src/server/conversation/codexConversations.js +47 -44
- package/src/server/conversation/codexDetachedTurn.js +12 -11
- package/src/server/conversation/codexEvents.js +95 -99
- package/src/server/conversation/codexHelperExecution.js +3 -13
- package/src/server/conversation/codexHelperThreadLedger.js +7 -13
- package/src/server/conversation/codexHelperThreadRecovery.js +2 -16
- package/src/server/conversation/codexHelperThreads.js +5 -6
- package/src/server/conversation/codexHistoryAdapter.js +32 -26
- package/src/server/conversation/codexMessageCommands.js +22 -22
- package/src/server/conversation/codexMessageDelivery.js +12 -7
- package/src/server/conversation/codexModelCatalog.js +97 -0
- package/src/server/conversation/codexNotificationObserver.js +24 -40
- package/src/server/conversation/codexNotificationQueue.js +2 -3
- package/src/server/conversation/codexOutput.js +20 -27
- package/src/server/conversation/codexProcess.js +123 -127
- package/src/server/conversation/codexProcessLeader.js +3 -3
- package/src/server/conversation/codexProvider.js +31 -614
- package/src/server/conversation/codexProviderOwner.js +2 -2
- package/src/server/conversation/codexProviderSelection.js +38 -40
- package/src/server/conversation/codexRenewalCommands.js +13 -10
- package/src/server/conversation/codexRenewalThreads.js +412 -0
- package/src/server/conversation/codexRunJournal.js +24 -42
- package/src/server/conversation/codexRuntimeLifecycle.js +19 -15
- package/src/server/conversation/codexSessionCleanup.js +11 -10
- package/src/server/conversation/codexSessionReconciliation.js +6 -6
- package/src/server/conversation/codexThreadReadiness.js +19 -33
- package/src/server/conversation/codexThreadStatus.js +3 -3
- package/src/server/conversation/codexTurn.js +124 -297
- package/src/server/conversation/codexTurnRecovery.js +49 -28
- package/src/server/conversation/codexTurnState.js +34 -13
- package/src/server/conversation/commandWrapper.js +3 -0
- package/src/server/conversation/deliveryTiming.js +14 -5
- package/src/server/conversation/index.js +1 -0
- package/src/server/conversation/localExecution.js +13 -17
- package/src/server/conversation/normalize.js +8 -3
- package/src/server/conversation/openCodeClient.js +9 -10
- package/src/server/conversation/openCodeProcess.js +9 -5
- package/src/server/conversation/openCodeRuntime.js +10 -11
- package/src/server/conversation/openCodeTurn.js +43 -29
- package/src/server/conversation/providers/claudeDriver.js +8 -16
- package/src/server/conversation/providers/codexDriver.js +25 -41
- package/src/server/conversation/providers/opencodeDriver.js +17 -42
- package/src/server/conversation/providers/scoped.js +48 -4
- package/src/server/conversation/runtime.js +50 -49
- package/src/server/conversation/runtimeStateUpgrade.js +34 -22
- package/src/server/conversation/transcript.js +10 -10
- package/src/server/hosts/codexConfiguration.js +1 -0
- package/src/server/hosts/codexProvider.js +8 -6
- package/src/server/index.js +2 -1
- package/src/server/lib/assistantToolLoop.js +1 -153
- package/src/server/lib/serviceToolCatalog.js +17 -42
- package/src/shared/assistantResource.js +4 -2
- package/src/shared/conversation/attachments.js +4 -0
- package/src/shared/conversation/longTextBlocks.js +54 -19
- package/src/shared/conversation/numberedQuestionSugar.js +17 -10
- package/src/shared/conversation/pagination.js +4 -6
- package/src/shared/conversation/patches.js +1 -4
- package/src/shared/conversation/streaming.js +3 -11
- package/src/shared/conversation/turns.js +11 -0
- package/src/shared/index.js +1 -0
- package/test/assistantBoundedToolLoop.test.js +2 -2
- package/test/assistantResource.test.js +4 -4
- package/test/assistantSettingsResource.test.js +2 -2
- package/test/claudeConversationSession.test.js +11 -1
- package/test/claudeTurn.test.js +35 -7
- package/test/codexClient.test.js +20 -0
- package/test/codexConversationSession.test.js +2 -2
- package/test/codexConversationsCheckpoint.test.js +51 -0
- package/test/codexModelCatalog.test.js +1 -1
- package/test/codexProviderHome.test.js +51 -0
- package/test/codexProviderSelection.test.js +71 -0
- package/test/codexTurn.test.js +222 -6
- package/test/conversationAgentRun.test.js +2 -1
- package/test/conversationAttachments.test.js +27 -2
- package/test/conversationDeliveryTiming.test.js +21 -0
- package/test/conversationNormalize.test.js +11 -0
- package/test/fixtures/nestedListQuestionMessage.md +37 -0
- package/test/frameworkActions.test.js +2 -2
- package/test/longTextBlocks.test.js +102 -0
- package/test/messageDelivery.test.js +7 -1
- package/test/openCodeClient.test.js +20 -0
- package/test/openCodeRuntime.test.js +1 -1
- package/test/openCodeTurn.test.js +90 -0
- package/test/opencodeConversationSession.test.js +1 -1
- package/test/serviceToolCatalog.test.js +27 -0
|
@@ -1,7 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
normalizeText
|
|
4
|
-
} from "./normalize.js";
|
|
1
|
+
import { isRecord } from "@jskit-ai/kernel/shared/support/normalize";
|
|
2
|
+
import { normalizeNullableText } from "./normalize.js";
|
|
5
3
|
|
|
6
4
|
const CODEX_TOKEN_USAGE_METHOD = "thread/tokenUsage/updated";
|
|
7
5
|
|
|
@@ -14,7 +12,7 @@ function nonNegativeInteger(value) {
|
|
|
14
12
|
}
|
|
15
13
|
|
|
16
14
|
function codexContextUsageFromNotification(notification = {}) {
|
|
17
|
-
if (
|
|
15
|
+
if (normalizeNullableText(notification?.method) !== CODEX_TOKEN_USAGE_METHOD) {
|
|
18
16
|
return null;
|
|
19
17
|
}
|
|
20
18
|
const params = notification?.params && typeof notification.params === "object"
|
|
@@ -33,8 +31,8 @@ function codexContextUsageFromNotification(notification = {}) {
|
|
|
33
31
|
const inputTokens = nonNegativeInteger(last.inputTokens);
|
|
34
32
|
const cumulativeTokens = nonNegativeInteger(total.totalTokens);
|
|
35
33
|
const windowTokens = nonNegativeInteger(tokenUsage.modelContextWindow);
|
|
36
|
-
const threadId =
|
|
37
|
-
const turnId =
|
|
34
|
+
const threadId = normalizeNullableText(params.threadId);
|
|
35
|
+
const turnId = normalizeNullableText(params.turnId);
|
|
38
36
|
if (
|
|
39
37
|
!threadId ||
|
|
40
38
|
!turnId ||
|
|
@@ -75,7 +73,7 @@ const CODEX_APP_SERVER_CONTEXT_REFRESH_SIGNALS = new Set([
|
|
|
75
73
|
|
|
76
74
|
function codexAppServerStatusFromValue(status = null) {
|
|
77
75
|
if (typeof status === "string") {
|
|
78
|
-
const normalized =
|
|
76
|
+
const normalized = normalizeNullableText(status);
|
|
79
77
|
if (normalized === "active") {
|
|
80
78
|
return "inProgress";
|
|
81
79
|
}
|
|
@@ -87,10 +85,10 @@ function codexAppServerStatusFromValue(status = null) {
|
|
|
87
85
|
}
|
|
88
86
|
return normalized;
|
|
89
87
|
}
|
|
90
|
-
if (!
|
|
88
|
+
if (!isRecord(status)) {
|
|
91
89
|
return "";
|
|
92
90
|
}
|
|
93
|
-
const type =
|
|
91
|
+
const type = normalizeNullableText(status.type);
|
|
94
92
|
if (type === "active") {
|
|
95
93
|
return "inProgress";
|
|
96
94
|
}
|
|
@@ -107,11 +105,11 @@ function codexAppServerStatusFromValue(status = null) {
|
|
|
107
105
|
}
|
|
108
106
|
|
|
109
107
|
function codexAppServerNotificationParams(notification = {}) {
|
|
110
|
-
return
|
|
108
|
+
return isRecord(notification?.params) ? notification.params : {};
|
|
111
109
|
}
|
|
112
110
|
|
|
113
111
|
function codexAppServerNotificationEvent(notification = {}) {
|
|
114
|
-
const method =
|
|
112
|
+
const method = normalizeNullableText(notification.method);
|
|
115
113
|
const params = codexAppServerNotificationParams(notification);
|
|
116
114
|
const candidates = [
|
|
117
115
|
params.event,
|
|
@@ -124,17 +122,17 @@ function codexAppServerNotificationEvent(notification = {}) {
|
|
|
124
122
|
notification.record
|
|
125
123
|
];
|
|
126
124
|
for (const candidate of candidates) {
|
|
127
|
-
if (
|
|
125
|
+
if (isRecord(candidate)) {
|
|
128
126
|
return candidate;
|
|
129
127
|
}
|
|
130
128
|
}
|
|
131
|
-
if (
|
|
129
|
+
if (isRecord(params.payload) || normalizeNullableText(params.type)) {
|
|
132
130
|
return params;
|
|
133
131
|
}
|
|
134
|
-
if (
|
|
132
|
+
if (isRecord(notification.payload) || normalizeNullableText(notification.type)) {
|
|
135
133
|
return notification;
|
|
136
134
|
}
|
|
137
|
-
if (["event_msg", "response_item", "task_complete"].includes(method) &&
|
|
135
|
+
if (["event_msg", "response_item", "task_complete"].includes(method) && isRecord(params)) {
|
|
138
136
|
return params;
|
|
139
137
|
}
|
|
140
138
|
return null;
|
|
@@ -142,33 +140,33 @@ function codexAppServerNotificationEvent(notification = {}) {
|
|
|
142
140
|
|
|
143
141
|
function codexAppServerNotificationEventType(notification = {}, event = null) {
|
|
144
142
|
const params = codexAppServerNotificationParams(notification);
|
|
145
|
-
return
|
|
143
|
+
return normalizeNullableText(event?.type || params.type || notification.type || notification.method);
|
|
146
144
|
}
|
|
147
145
|
|
|
148
146
|
function codexAppServerNotificationEventPayload(notification = {}, event = null) {
|
|
149
|
-
if (
|
|
147
|
+
if (isRecord(event?.payload)) {
|
|
150
148
|
return event.payload;
|
|
151
149
|
}
|
|
152
150
|
const params = codexAppServerNotificationParams(notification);
|
|
153
|
-
if (
|
|
151
|
+
if (isRecord(params.payload)) {
|
|
154
152
|
return params.payload;
|
|
155
153
|
}
|
|
156
|
-
if (
|
|
154
|
+
if (isRecord(notification.payload)) {
|
|
157
155
|
return notification.payload;
|
|
158
156
|
}
|
|
159
|
-
return
|
|
157
|
+
return isRecord(event) ? event : {};
|
|
160
158
|
}
|
|
161
159
|
|
|
162
160
|
function codexAppServerNotificationItem(notification = {}) {
|
|
163
161
|
const item = codexAppServerNotificationParams(notification).item;
|
|
164
|
-
return
|
|
162
|
+
return isRecord(item) ? item : null;
|
|
165
163
|
}
|
|
166
164
|
|
|
167
165
|
function codexAppServerNotificationThreadId(notification = {}) {
|
|
168
166
|
const params = codexAppServerNotificationParams(notification);
|
|
169
167
|
const event = codexAppServerNotificationEvent(notification);
|
|
170
168
|
const payload = codexAppServerNotificationEventPayload(notification, event);
|
|
171
|
-
return
|
|
169
|
+
return normalizeNullableText(
|
|
172
170
|
params.threadId ||
|
|
173
171
|
params.thread_id ||
|
|
174
172
|
params.thread?.id ||
|
|
@@ -184,7 +182,7 @@ function codexAppServerNotificationTurnId(notification = {}) {
|
|
|
184
182
|
const event = codexAppServerNotificationEvent(notification);
|
|
185
183
|
const payload = codexAppServerNotificationEventPayload(notification, event);
|
|
186
184
|
const item = codexAppServerNotificationItem(notification);
|
|
187
|
-
return
|
|
185
|
+
return normalizeNullableText(
|
|
188
186
|
params.turnId ||
|
|
189
187
|
params.turn_id ||
|
|
190
188
|
params.turn?.id ||
|
|
@@ -199,7 +197,7 @@ function codexAppServerNotificationTurnId(notification = {}) {
|
|
|
199
197
|
|
|
200
198
|
function codexAppServerNotificationTurnStatus(notification = {}) {
|
|
201
199
|
const params = codexAppServerNotificationParams(notification);
|
|
202
|
-
const turnStatus =
|
|
200
|
+
const turnStatus = normalizeNullableText(params.turn?.status);
|
|
203
201
|
return turnStatus || codexAppServerStatusFromValue(params.status);
|
|
204
202
|
}
|
|
205
203
|
|
|
@@ -208,7 +206,7 @@ function codexAppServerErrorText(value = null, seen = new Set()) {
|
|
|
208
206
|
return "";
|
|
209
207
|
}
|
|
210
208
|
if (typeof value === "string") {
|
|
211
|
-
const text =
|
|
209
|
+
const text = normalizeNullableText(value);
|
|
212
210
|
if (text.startsWith("{") || text.startsWith("[")) {
|
|
213
211
|
try {
|
|
214
212
|
const parsed = JSON.parse(text);
|
|
@@ -222,7 +220,7 @@ function codexAppServerErrorText(value = null, seen = new Set()) {
|
|
|
222
220
|
}
|
|
223
221
|
return text;
|
|
224
222
|
}
|
|
225
|
-
if (!
|
|
223
|
+
if (!isRecord(value)) {
|
|
226
224
|
return "";
|
|
227
225
|
}
|
|
228
226
|
if (seen.has(value)) {
|
|
@@ -238,16 +236,16 @@ function codexAppServerErrorText(value = null, seen = new Set()) {
|
|
|
238
236
|
codexAppServerErrorText(value.codexErrorInfo || value.codex_error_info, seen)
|
|
239
237
|
].filter(Boolean);
|
|
240
238
|
if (!messages.length) {
|
|
241
|
-
return
|
|
239
|
+
return normalizeNullableText(value.code);
|
|
242
240
|
}
|
|
243
241
|
return [...new Set(messages)].join(" ");
|
|
244
242
|
}
|
|
245
243
|
|
|
246
244
|
function codexAppServerNotificationError(notification = {}) {
|
|
247
245
|
const params = codexAppServerNotificationParams(notification);
|
|
248
|
-
const status =
|
|
249
|
-
const turn =
|
|
250
|
-
return
|
|
246
|
+
const status = isRecord(params.status) ? params.status : {};
|
|
247
|
+
const turn = isRecord(params.turn) ? params.turn : {};
|
|
248
|
+
return normalizeNullableText(
|
|
251
249
|
codexAppServerErrorText(params.error) ||
|
|
252
250
|
params.message ||
|
|
253
251
|
codexAppServerErrorText(status.error) ||
|
|
@@ -259,23 +257,23 @@ function codexAppServerNotificationError(notification = {}) {
|
|
|
259
257
|
|
|
260
258
|
function codexAppServerNotificationUsageLimitExceeded(notification = {}) {
|
|
261
259
|
const params = codexAppServerNotificationParams(notification);
|
|
262
|
-
const status =
|
|
263
|
-
const turn =
|
|
260
|
+
const status = isRecord(params.status) ? params.status : {};
|
|
261
|
+
const turn = isRecord(params.turn) ? params.turn : {};
|
|
264
262
|
return [params.error, status.error, turn.error].some((error) => (
|
|
265
|
-
|
|
266
|
-
|
|
263
|
+
isRecord(error) &&
|
|
264
|
+
normalizeNullableText(error.codexErrorInfo || error.codex_error_info) === "usageLimitExceeded"
|
|
267
265
|
));
|
|
268
266
|
}
|
|
269
267
|
|
|
270
268
|
function codexAppServerTextInputText(input = {}) {
|
|
271
|
-
if (!
|
|
269
|
+
if (!isRecord(input) || normalizeNullableText(input.type) !== "text") {
|
|
272
270
|
return "";
|
|
273
271
|
}
|
|
274
|
-
return
|
|
272
|
+
return normalizeNullableText(input.text);
|
|
275
273
|
}
|
|
276
274
|
|
|
277
275
|
function codexAppServerUserMessageText(item = {}) {
|
|
278
|
-
if (!
|
|
276
|
+
if (!isRecord(item) || normalizeNullableText(item.type) !== "userMessage") {
|
|
279
277
|
return "";
|
|
280
278
|
}
|
|
281
279
|
return (Array.isArray(item.content) ? item.content : [])
|
|
@@ -291,7 +289,7 @@ function codexAppServerContentText(value = null) {
|
|
|
291
289
|
if (Array.isArray(value)) {
|
|
292
290
|
return value.map((entry) => codexAppServerContentText(entry)).filter(Boolean).join("");
|
|
293
291
|
}
|
|
294
|
-
if (!
|
|
292
|
+
if (!isRecord(value)) {
|
|
295
293
|
return "";
|
|
296
294
|
}
|
|
297
295
|
if (typeof value.text === "string") {
|
|
@@ -306,18 +304,18 @@ function codexAppServerContentText(value = null) {
|
|
|
306
304
|
if (typeof value.message === "string" || Array.isArray(value.message)) {
|
|
307
305
|
return codexAppServerContentText(value.message);
|
|
308
306
|
}
|
|
309
|
-
if (
|
|
307
|
+
if (isRecord(value.message)) {
|
|
310
308
|
return codexAppServerContentText(value.message.content || value.message.text);
|
|
311
309
|
}
|
|
312
310
|
return "";
|
|
313
311
|
}
|
|
314
312
|
|
|
315
313
|
function codexAppServerAssistantItemText(item = {}) {
|
|
316
|
-
if (!
|
|
314
|
+
if (!isRecord(item)) {
|
|
317
315
|
return "";
|
|
318
316
|
}
|
|
319
|
-
const type =
|
|
320
|
-
const role =
|
|
317
|
+
const type = normalizeNullableText(item.type);
|
|
318
|
+
const role = normalizeNullableText(item.role || item.author?.role);
|
|
321
319
|
const isAssistant = role === "assistant" ||
|
|
322
320
|
type === "agentMessage" ||
|
|
323
321
|
type === "assistantMessage" ||
|
|
@@ -327,7 +325,7 @@ function codexAppServerAssistantItemText(item = {}) {
|
|
|
327
325
|
if (!isAssistant) {
|
|
328
326
|
return "";
|
|
329
327
|
}
|
|
330
|
-
return
|
|
328
|
+
return normalizeNullableText(
|
|
331
329
|
codexAppServerContentText(item.content) ||
|
|
332
330
|
codexAppServerContentText(item.text) ||
|
|
333
331
|
codexAppServerContentText(item.message)
|
|
@@ -335,11 +333,11 @@ function codexAppServerAssistantItemText(item = {}) {
|
|
|
335
333
|
}
|
|
336
334
|
|
|
337
335
|
function codexAppServerHookPromptText(item = {}) {
|
|
338
|
-
if (!
|
|
336
|
+
if (!isRecord(item) || normalizeNullableText(item.type) !== "hookPrompt") {
|
|
339
337
|
return "";
|
|
340
338
|
}
|
|
341
339
|
return (Array.isArray(item.fragments) ? item.fragments : [])
|
|
342
|
-
.map((fragment) =>
|
|
340
|
+
.map((fragment) => normalizeNullableText(fragment?.text))
|
|
343
341
|
.filter(Boolean)
|
|
344
342
|
.join("\n\n");
|
|
345
343
|
}
|
|
@@ -349,7 +347,7 @@ function codexAppServerNotificationItemId(notification = {}) {
|
|
|
349
347
|
const item = codexAppServerNotificationItem(notification);
|
|
350
348
|
const event = codexAppServerNotificationEvent(notification);
|
|
351
349
|
const payload = codexAppServerNotificationEventPayload(notification, event);
|
|
352
|
-
return
|
|
350
|
+
return normalizeNullableText(
|
|
353
351
|
item?.id ||
|
|
354
352
|
params.itemId ||
|
|
355
353
|
params.item_id ||
|
|
@@ -361,22 +359,27 @@ function codexAppServerNotificationItemId(notification = {}) {
|
|
|
361
359
|
);
|
|
362
360
|
}
|
|
363
361
|
|
|
362
|
+
// Text of an event_msg agent_message payload.
|
|
363
|
+
function codexAppServerAgentMessageText(payload = {}) {
|
|
364
|
+
return normalizeNullableText(
|
|
365
|
+
codexAppServerContentText(payload.message) ||
|
|
366
|
+
codexAppServerContentText(payload.text) ||
|
|
367
|
+
codexAppServerContentText(payload.content)
|
|
368
|
+
);
|
|
369
|
+
}
|
|
370
|
+
|
|
364
371
|
function codexAppServerFinalEventText(notification = {}, event = null, payload = {}) {
|
|
365
372
|
const eventType = codexAppServerNotificationEventType(notification, event);
|
|
366
|
-
const payloadType =
|
|
367
|
-
const phase =
|
|
373
|
+
const payloadType = normalizeNullableText(payload.type);
|
|
374
|
+
const phase = normalizeNullableText(payload.phase || event?.phase);
|
|
368
375
|
if (eventType === "task_complete") {
|
|
369
|
-
return
|
|
376
|
+
return normalizeNullableText(
|
|
370
377
|
codexAppServerContentText(payload.last_agent_message) ||
|
|
371
378
|
codexAppServerContentText(payload.lastAgentMessage)
|
|
372
379
|
);
|
|
373
380
|
}
|
|
374
381
|
if (eventType === "event_msg" && payloadType === "agent_message" && phase === "final_answer") {
|
|
375
|
-
return
|
|
376
|
-
codexAppServerContentText(payload.message) ||
|
|
377
|
-
codexAppServerContentText(payload.text) ||
|
|
378
|
-
codexAppServerContentText(payload.content)
|
|
379
|
-
);
|
|
382
|
+
return codexAppServerAgentMessageText(payload);
|
|
380
383
|
}
|
|
381
384
|
if (eventType === "response_item" && phase === "final_answer") {
|
|
382
385
|
return codexAppServerAssistantItemText(payload);
|
|
@@ -385,15 +388,15 @@ function codexAppServerFinalEventText(notification = {}, event = null, payload =
|
|
|
385
388
|
}
|
|
386
389
|
|
|
387
390
|
function classifyCodexAppServerEvent(notification = {}) {
|
|
388
|
-
const method =
|
|
391
|
+
const method = normalizeNullableText(notification.method);
|
|
389
392
|
const event = codexAppServerNotificationEvent(notification);
|
|
390
393
|
const payload = codexAppServerNotificationEventPayload(notification, event);
|
|
391
394
|
const eventType = event ? codexAppServerNotificationEventType(notification, event) : "";
|
|
392
|
-
const payloadType =
|
|
395
|
+
const payloadType = normalizeNullableText(payload.type);
|
|
393
396
|
const item = codexAppServerNotificationItem(notification);
|
|
394
|
-
const itemType =
|
|
397
|
+
const itemType = normalizeNullableText(item?.type);
|
|
395
398
|
const itemText = codexAppServerAssistantItemText(item);
|
|
396
|
-
const phase =
|
|
399
|
+
const phase = normalizeNullableText(payload.phase || event?.phase || item?.phase || item?.purpose || item?.category);
|
|
397
400
|
const base = {
|
|
398
401
|
itemId: codexAppServerNotificationItemId(notification),
|
|
399
402
|
source: method || eventType || "notification",
|
|
@@ -437,7 +440,7 @@ function classifyCodexAppServerEvent(notification = {}) {
|
|
|
437
440
|
...base,
|
|
438
441
|
kind: "reasoning_summary",
|
|
439
442
|
delta: codexAppServerContentText(codexAppServerNotificationParams(notification).delta),
|
|
440
|
-
text:
|
|
443
|
+
text: normalizeNullableText(codexAppServerContentText(codexAppServerNotificationParams(notification).delta))
|
|
441
444
|
};
|
|
442
445
|
}
|
|
443
446
|
|
|
@@ -495,11 +498,7 @@ function classifyCodexAppServerEvent(notification = {}) {
|
|
|
495
498
|
...base,
|
|
496
499
|
kind: "live_progress",
|
|
497
500
|
source: eventType,
|
|
498
|
-
text:
|
|
499
|
-
codexAppServerContentText(payload.message) ||
|
|
500
|
-
codexAppServerContentText(payload.text) ||
|
|
501
|
-
codexAppServerContentText(payload.content)
|
|
502
|
-
)
|
|
501
|
+
text: codexAppServerAgentMessageText(payload)
|
|
503
502
|
};
|
|
504
503
|
}
|
|
505
504
|
|
|
@@ -535,7 +534,7 @@ function classifyCodexAppServerEvent(notification = {}) {
|
|
|
535
534
|
}
|
|
536
535
|
|
|
537
536
|
function codexAppServerSignalName(value = "") {
|
|
538
|
-
return
|
|
537
|
+
return normalizeNullableText(value)
|
|
539
538
|
.toLowerCase()
|
|
540
539
|
.replaceAll("-", "_")
|
|
541
540
|
.replaceAll("/", "_");
|
|
@@ -551,7 +550,7 @@ function codexAppServerSignalNames(value = null) {
|
|
|
551
550
|
if (Array.isArray(value)) {
|
|
552
551
|
return value.flatMap((entry) => codexAppServerSignalNames(entry));
|
|
553
552
|
}
|
|
554
|
-
if (!
|
|
553
|
+
if (!isRecord(value)) {
|
|
555
554
|
return [];
|
|
556
555
|
}
|
|
557
556
|
return [
|
|
@@ -567,12 +566,12 @@ function codexAppServerSignalNames(value = null) {
|
|
|
567
566
|
}
|
|
568
567
|
|
|
569
568
|
function codexAppServerContextRefreshReason(notification = {}) {
|
|
570
|
-
const method =
|
|
569
|
+
const method = normalizeNullableText(notification.method);
|
|
571
570
|
const item = codexAppServerNotificationItem(notification);
|
|
572
571
|
const event = codexAppServerNotificationEvent(notification);
|
|
573
572
|
const payload = codexAppServerNotificationEventPayload(notification, event);
|
|
574
573
|
const eventType = codexAppServerNotificationEventType(notification, event);
|
|
575
|
-
const payloadType =
|
|
574
|
+
const payloadType = normalizeNullableText(payload.type);
|
|
576
575
|
const signals = [
|
|
577
576
|
method,
|
|
578
577
|
item?.type,
|
|
@@ -592,32 +591,28 @@ function codexAppServerContextRefreshReason(notification = {}) {
|
|
|
592
591
|
return "";
|
|
593
592
|
}
|
|
594
593
|
|
|
594
|
+
// Like codexAppServerThreadRawValue, but provider results may also wrap the
|
|
595
|
+
// thread once more under `thread`, checked after raw and response.thread.
|
|
595
596
|
function codexAppServerProviderThread(value = {}) {
|
|
596
|
-
if (
|
|
597
|
-
return value.raw;
|
|
598
|
-
}
|
|
599
|
-
if (isPlainObject(value?.response?.thread)) {
|
|
600
|
-
return value.response.thread;
|
|
601
|
-
}
|
|
602
|
-
if (isPlainObject(value?.thread)) {
|
|
597
|
+
if (!isRecord(value?.raw) && !isRecord(value?.response?.thread) && isRecord(value?.thread)) {
|
|
603
598
|
return value.thread;
|
|
604
599
|
}
|
|
605
|
-
return
|
|
600
|
+
return codexAppServerThreadRawValue(value || {});
|
|
606
601
|
}
|
|
607
602
|
|
|
608
603
|
function codexAppServerProviderTurnId(turn = {}) {
|
|
609
|
-
return
|
|
604
|
+
return normalizeNullableText(turn.id || turn.turnId || turn.turn_id || turn.turn?.id || "");
|
|
610
605
|
}
|
|
611
606
|
|
|
612
607
|
function codexAppServerProviderTurnItems(turn = {}) {
|
|
613
608
|
return [
|
|
614
609
|
...(Array.isArray(turn.items) ? turn.items : []),
|
|
615
610
|
...(Array.isArray(turn.itemsView) ? turn.itemsView : [])
|
|
616
|
-
].filter(
|
|
611
|
+
].filter(isRecord);
|
|
617
612
|
}
|
|
618
613
|
|
|
619
614
|
function codexAppServerProviderThreadTurn(value = {}, turnId = "") {
|
|
620
|
-
const normalizedTurnId =
|
|
615
|
+
const normalizedTurnId = normalizeNullableText(turnId);
|
|
621
616
|
if (!normalizedTurnId) {
|
|
622
617
|
return null;
|
|
623
618
|
}
|
|
@@ -637,11 +632,11 @@ function codexAppServerProviderTurnAssistantSegments(turn = {}) {
|
|
|
637
632
|
const active = ["inProgress", "starting"].includes(codexAppServerStatusFromValue(turn.status));
|
|
638
633
|
return items
|
|
639
634
|
.filter((item, index) => {
|
|
640
|
-
const phase =
|
|
635
|
+
const phase = normalizeNullableText(item.phase);
|
|
641
636
|
return phase === "final_answer" || (!phase && !active && index >= responseStart);
|
|
642
637
|
})
|
|
643
638
|
.map((item) => {
|
|
644
|
-
const itemId =
|
|
639
|
+
const itemId = normalizeNullableText(item.id);
|
|
645
640
|
const text = codexAppServerAssistantItemText(item);
|
|
646
641
|
if (
|
|
647
642
|
!itemId ||
|
|
@@ -672,37 +667,37 @@ function codexAppServerOutputOwnerTurnId({
|
|
|
672
667
|
trackedThreadId = "",
|
|
673
668
|
trackedTurnId = ""
|
|
674
669
|
} = {}) {
|
|
675
|
-
const normalizedNotificationThreadId =
|
|
676
|
-
const normalizedTrackedThreadId =
|
|
677
|
-
const normalizedTrackedTurnId =
|
|
670
|
+
const normalizedNotificationThreadId = normalizeNullableText(notificationThreadId);
|
|
671
|
+
const normalizedTrackedThreadId = normalizeNullableText(trackedThreadId);
|
|
672
|
+
const normalizedTrackedTurnId = normalizeNullableText(trackedTurnId);
|
|
678
673
|
const trackedTurnOwnsResult = trackedActive === true &&
|
|
679
|
-
["active", "finalizing"].includes(
|
|
674
|
+
["active", "finalizing"].includes(normalizeNullableText(trackedState)) &&
|
|
680
675
|
Boolean(normalizedTrackedTurnId) &&
|
|
681
676
|
Boolean(normalizedNotificationThreadId) &&
|
|
682
677
|
normalizedNotificationThreadId === normalizedTrackedThreadId;
|
|
683
678
|
return trackedTurnOwnsResult
|
|
684
679
|
? normalizedTrackedTurnId
|
|
685
|
-
:
|
|
680
|
+
: normalizeNullableText(notificationTurnId);
|
|
686
681
|
}
|
|
687
682
|
|
|
688
683
|
function codexAppServerThreadRawValue(thread = {}) {
|
|
689
|
-
if (
|
|
684
|
+
if (isRecord(thread.raw)) {
|
|
690
685
|
return thread.raw;
|
|
691
686
|
}
|
|
692
|
-
if (
|
|
687
|
+
if (isRecord(thread.response?.thread)) {
|
|
693
688
|
return thread.response.thread;
|
|
694
689
|
}
|
|
695
|
-
return
|
|
690
|
+
return isRecord(thread) ? thread : {};
|
|
696
691
|
}
|
|
697
692
|
|
|
698
693
|
function codexAppServerThreadTurnId(thread = {}) {
|
|
699
|
-
const observedTurnId =
|
|
694
|
+
const observedTurnId = normalizeNullableText(thread.observedTurn?.id || "");
|
|
700
695
|
if (observedTurnId) {
|
|
701
696
|
return observedTurnId;
|
|
702
697
|
}
|
|
703
698
|
const rawThread = codexAppServerThreadRawValue(thread);
|
|
704
|
-
const status =
|
|
705
|
-
return
|
|
699
|
+
const status = isRecord(rawThread.status) ? rawThread.status : {};
|
|
700
|
+
return normalizeNullableText(
|
|
706
701
|
thread.turnId ||
|
|
707
702
|
thread.turn_id ||
|
|
708
703
|
thread.turn?.id ||
|
|
@@ -726,14 +721,14 @@ function codexAppServerThreadTurnId(thread = {}) {
|
|
|
726
721
|
|
|
727
722
|
function codexAppServerThreadError(thread = {}) {
|
|
728
723
|
const rawThread = codexAppServerThreadRawValue(thread);
|
|
729
|
-
const status =
|
|
724
|
+
const status = isRecord(rawThread.status) ? rawThread.status : {};
|
|
730
725
|
return codexAppServerErrorText(rawThread.error || status.error);
|
|
731
726
|
}
|
|
732
727
|
|
|
733
728
|
function codexAppServerProviderThreadTurns(thread = null) {
|
|
734
729
|
const rawThread = codexAppServerThreadRawValue(thread || {});
|
|
735
730
|
return (Array.isArray(rawThread.turns) ? rawThread.turns : [])
|
|
736
|
-
.filter((turn) =>
|
|
731
|
+
.filter((turn) => isRecord(turn));
|
|
737
732
|
}
|
|
738
733
|
|
|
739
734
|
function codexAppServerProviderTurnStatus(turn = {}) {
|
|
@@ -742,7 +737,7 @@ function codexAppServerProviderTurnStatus(turn = {}) {
|
|
|
742
737
|
|
|
743
738
|
function codexAppServerProviderTurnClientIds(turn = {}) {
|
|
744
739
|
return codexAppServerProviderTurnItems(turn)
|
|
745
|
-
.map((item) =>
|
|
740
|
+
.map((item) => normalizeNullableText(
|
|
746
741
|
item.clientId ||
|
|
747
742
|
item.client_id ||
|
|
748
743
|
item.clientUserMessageId ||
|
|
@@ -756,8 +751,8 @@ function codexAppServerProviderTurnForOperation(thread = null, {
|
|
|
756
751
|
clientMessageId = "",
|
|
757
752
|
turnId = ""
|
|
758
753
|
} = {}) {
|
|
759
|
-
const normalizedTurnId =
|
|
760
|
-
const normalizedClientMessageId =
|
|
754
|
+
const normalizedTurnId = normalizeNullableText(turnId || "");
|
|
755
|
+
const normalizedClientMessageId = normalizeNullableText(clientMessageId || "");
|
|
761
756
|
const turns = codexAppServerProviderThreadTurns(thread);
|
|
762
757
|
if (normalizedTurnId) {
|
|
763
758
|
return turns.find((turn) => (
|
|
@@ -772,7 +767,7 @@ function codexAppServerProviderTurnForOperation(thread = null, {
|
|
|
772
767
|
)) || null;
|
|
773
768
|
}
|
|
774
769
|
|
|
775
|
-
// Native snapshot matching
|
|
770
|
+
// Native snapshot matching for renewal handover and seeding.
|
|
776
771
|
// The application projects these classifications into its approval/error policy.
|
|
777
772
|
function inspectCodexAppServerRenewalThread(thread = null, {
|
|
778
773
|
clientMessageId = "",
|
|
@@ -818,6 +813,7 @@ export {
|
|
|
818
813
|
inspectCodexAppServerRenewalThread,
|
|
819
814
|
codexAppServerProviderTurnText,
|
|
820
815
|
codexAppServerProviderTurnError,
|
|
816
|
+
codexAppServerAgentMessageText,
|
|
821
817
|
codexAppServerAssistantItemText,
|
|
822
818
|
codexAppServerContentText,
|
|
823
819
|
codexAppServerContextRefreshReason,
|
|
@@ -1,13 +1,6 @@
|
|
|
1
|
-
import { deleteCodexAppServerThread } from "./codexProvider.js";
|
|
1
|
+
import { codexAppServerDeliveredTurn, deleteCodexAppServerThread } from "./codexProvider.js";
|
|
2
2
|
import { CODEX_HELPER_THREAD_LIFECYCLES } from "./codexHelperThreadLedger.js";
|
|
3
|
-
|
|
4
|
-
function normalizeText(value) {
|
|
5
|
-
return String(value || "").trim();
|
|
6
|
-
}
|
|
7
|
-
|
|
8
|
-
export function errorMessage(value, fallback = "Codex could not be prepared.") {
|
|
9
|
-
return normalizeText(value?.error || value?.message || value) || fallback;
|
|
10
|
-
}
|
|
3
|
+
import { codexAppServerErrorMessage as errorMessage, normalizeCodexRunText as normalizeText } from "./codexTurnState.js";
|
|
11
4
|
|
|
12
5
|
export function createCodexHelperOwnershipError({ applicationName = "Application", errorPrefix = "" } = {}) {
|
|
13
6
|
return function codexAppServerHelperOwnershipError(message = "", details = {}) {
|
|
@@ -253,10 +246,7 @@ export async function prepareDetachedCodexHelperThread(owner, scope, preparation
|
|
|
253
246
|
const currentDelivery = await sendPreparedCodexAppServerHelperTurn(
|
|
254
247
|
provider, preparation.turn(threadId), preparation.isolation
|
|
255
248
|
);
|
|
256
|
-
const currentTurnId =
|
|
257
|
-
const currentStatus = normalizeText(
|
|
258
|
-
currentDelivery.turn?.status || currentDelivery.turn?.raw?.status
|
|
259
|
-
);
|
|
249
|
+
const { turnId: currentTurnId, status: currentStatus } = codexAppServerDeliveredTurn(currentDelivery);
|
|
260
250
|
helperThreadRecord = await updateCodexAppServerHelperThread(
|
|
261
251
|
helperThreadRecord,
|
|
262
252
|
{
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import crypto from "node:crypto";
|
|
2
2
|
import { link, mkdir, open, readdir, rename, rm } from "node:fs/promises";
|
|
3
3
|
import path from "node:path";
|
|
4
|
+
import { isRecord } from "@jskit-ai/kernel/shared/support/normalize";
|
|
5
|
+
import { normalizeNullableText } from "./normalize.js";
|
|
4
6
|
|
|
5
7
|
import { tryAcquireExclusiveFileLock } from "@jskit-ai/kernel/server/support";
|
|
6
8
|
|
|
@@ -72,16 +74,8 @@ function createCodexHelperThreadLedgerOwner({
|
|
|
72
74
|
const codexHelperThreadLedgerMutationQueues = new Map();
|
|
73
75
|
const codexHelperThreadLedgerProcessId = crypto.randomUUID();
|
|
74
76
|
|
|
75
|
-
function normalizeText(value) {
|
|
76
|
-
return String(value ?? "").trim();
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
function isRecord(value) {
|
|
80
|
-
return Boolean(value && typeof value === "object" && !Array.isArray(value));
|
|
81
|
-
}
|
|
82
|
-
|
|
83
77
|
function ledgerError(message = "", code = `${errorPrefix}ledger_invalid`) {
|
|
84
|
-
const error = new Error(
|
|
78
|
+
const error = new Error(normalizeNullableText(message) || "Codex helper ownership record is invalid.");
|
|
85
79
|
error.code = code;
|
|
86
80
|
error.retryable = true;
|
|
87
81
|
return error;
|
|
@@ -102,7 +96,7 @@ function createCodexHelperThreadLedgerOwner({
|
|
|
102
96
|
}
|
|
103
97
|
|
|
104
98
|
function requiredText(value, label, maxLength = 4096) {
|
|
105
|
-
const normalized =
|
|
99
|
+
const normalized = normalizeNullableText(value);
|
|
106
100
|
if (!normalized) {
|
|
107
101
|
throw ledgerError(`${label} is required.`);
|
|
108
102
|
}
|
|
@@ -137,7 +131,7 @@ function createCodexHelperThreadLedgerOwner({
|
|
|
137
131
|
}
|
|
138
132
|
|
|
139
133
|
function optionalText(value, label = "value", maxLength = 4096) {
|
|
140
|
-
const normalized =
|
|
134
|
+
const normalized = normalizeNullableText(value);
|
|
141
135
|
if (normalized.length > maxLength) {
|
|
142
136
|
throw ledgerError(`${label} exceeds ${maxLength} characters.`);
|
|
143
137
|
}
|
|
@@ -635,8 +629,8 @@ function createCodexHelperThreadLedgerOwner({
|
|
|
635
629
|
records.push(await readRecordFile(filePath));
|
|
636
630
|
} catch (error) {
|
|
637
631
|
failures.push(Object.freeze({
|
|
638
|
-
code:
|
|
639
|
-
error:
|
|
632
|
+
code: normalizeNullableText(error?.code),
|
|
633
|
+
error: normalizeNullableText(error?.message || error),
|
|
640
634
|
fileName: entry.name,
|
|
641
635
|
retryable: true
|
|
642
636
|
}));
|
|
@@ -1,21 +1,7 @@
|
|
|
1
|
-
import { stat } from "node:fs/promises";
|
|
2
1
|
import { deleteCodexAppServerThread, codexAppServerRuntimeStopWasVerified } from "./codexProvider.js";
|
|
2
|
+
import { directoryExists } from "./codexProviderOwner.js";
|
|
3
3
|
import { CODEX_HELPER_THREAD_LIFECYCLES } from "./codexHelperThreadLedger.js";
|
|
4
|
-
|
|
5
|
-
export function normalizeText(value) {
|
|
6
|
-
return String(value || "").trim();
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
export async function directoryExists(filePath = "") {
|
|
10
|
-
try {
|
|
11
|
-
return (await stat(filePath)).isDirectory();
|
|
12
|
-
} catch (error) {
|
|
13
|
-
if (error?.code === "ENOENT" || error?.code === "ENOTDIR") {
|
|
14
|
-
return false;
|
|
15
|
-
}
|
|
16
|
-
throw error;
|
|
17
|
-
}
|
|
18
|
-
}
|
|
4
|
+
import { normalizeCodexRunText as normalizeText } from "./codexTurnState.js";
|
|
19
5
|
|
|
20
6
|
// Recovery operations of the same Helper lifecycle. All maps and record mutations
|
|
21
7
|
// belong to the supplied lifecycle; this module creates no owner or registry.
|
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
import crypto from "node:crypto";
|
|
2
|
-
import {
|
|
2
|
+
import { isRecord } from "@jskit-ai/kernel/shared/support/normalize";
|
|
3
|
+
import { createCodexHelperOwnershipError, prepareDetachedCodexHelperThread } from "./codexHelperExecution.js";
|
|
3
4
|
import { deleteCodexAppServerHelperThread } from "./codexProvider.js";
|
|
4
|
-
import {
|
|
5
|
+
import { directoryExists } from "./codexProviderOwner.js";
|
|
6
|
+
import { createCodexHelperThreadRecovery } from "./codexHelperThreadRecovery.js";
|
|
7
|
+
import { codexAppServerErrorMessage as errorMessage, normalizeCodexRunText as normalizeText } from "./codexTurnState.js";
|
|
5
8
|
import {
|
|
6
9
|
CODEX_HELPER_THREAD_LEDGER_SCHEMA_VERSION,
|
|
7
10
|
CODEX_HELPER_THREAD_LIFECYCLES
|
|
@@ -9,10 +12,6 @@ import {
|
|
|
9
12
|
|
|
10
13
|
const CODEX_APP_SERVER_PROVIDER_ID = "codex_app_server";
|
|
11
14
|
|
|
12
|
-
function isRecord(value) {
|
|
13
|
-
return Boolean(value && typeof value === "object" && !Array.isArray(value));
|
|
14
|
-
}
|
|
15
|
-
|
|
16
15
|
// Internal facet of the original run owner. Public supplies policy and authorized
|
|
17
16
|
// scope inputs; native ownership, pending work and retirement have one owner.
|
|
18
17
|
export function createCodexHelperThreadLifecycle({
|