@jskit-ai/assistant-core 0.2.7 → 0.2.8
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 +18 -7
- package/src/client/browser.js +21 -0
- package/src/client/conversation/AssistantAttachmentQueue.vue +25 -108
- package/src/client/conversation/AssistantComposerActions.vue +1 -1
- package/src/client/conversation/AssistantConversationElement.vue +14 -52
- package/src/client/conversation/AssistantGoalControl.vue +13 -10
- package/src/client/conversation/AssistantPromptInput.vue +6 -91
- package/src/client/conversation/AssistantTranscript.css +505 -0
- package/src/client/conversation/AssistantTranscript.vue +24 -1197
- package/src/client/conversation/attachmentFiles.js +158 -0
- package/src/client/conversation/attachmentQueueItems.js +121 -0
- package/src/client/conversation/attachmentUploadRows.js +265 -0
- package/src/client/conversation/conversationDisplay.js +54 -0
- package/src/client/conversation/messageDelivery.js +13 -9
- package/src/client/conversation/retainedConversation.js +14 -3
- package/src/client/conversation/submitText.js +13 -2
- package/src/client/conversation/transcriptEntries.js +225 -0
- package/src/client/conversation/useAssistantAttachments.js +86 -388
- package/src/client/conversation/useAssistantQuestions.js +16 -3
- package/src/client/conversation/useAssistantSuggestions.js +16 -2
- package/src/client/conversation/useScrollToBottom.js +17 -19
- package/src/client/conversation/useTextareaAutoGrow.js +115 -0
- package/src/client/conversation/useTranscriptScrollFollow.js +525 -0
- package/src/client/lib/assistantApi.js +192 -161
- package/src/client/types.js +110 -0
- package/src/server/conversation/attachments.js +21 -6
- package/src/server/conversation/boundedToolLoop.js +1 -0
- package/src/server/conversation/claudeClient.js +71 -20
- package/src/server/conversation/claudeCommandRun.js +191 -0
- package/src/server/conversation/claudeHistory.js +7 -0
- package/src/server/conversation/claudeNativeTurn.js +708 -0
- package/src/server/conversation/claudeProcess.js +186 -112
- package/src/server/conversation/claudeProcessStart.js +214 -0
- package/src/server/conversation/claudePromptDelivery.js +183 -0
- package/src/server/conversation/claudeSessionCleanup.js +248 -0
- package/src/server/conversation/claudeTools.js +15 -3
- package/src/server/conversation/claudeTurn.js +212 -1388
- package/src/server/conversation/codexAccountReader.js +168 -0
- package/src/server/conversation/codexAuthPreflight.js +5 -4
- package/src/server/conversation/codexClient.js +18 -6
- package/src/server/conversation/codexConfiguration.js +8 -844
- package/src/server/conversation/codexConversationStops.js +377 -0
- package/src/server/conversation/codexConversationStore.js +119 -85
- package/src/server/conversation/codexConversationTurns.js +378 -0
- package/src/server/conversation/codexConversations.js +134 -866
- package/src/server/conversation/codexDetachedConversation.js +203 -0
- package/src/server/conversation/codexDetachedTurn.js +145 -104
- package/src/server/conversation/codexEvents.js +5 -200
- package/src/server/conversation/codexGoalCommands.js +14 -4
- package/src/server/conversation/codexHelperExecution.js +57 -57
- package/src/server/conversation/codexHelperThreadLedger.js +30 -288
- package/src/server/conversation/codexHelperThreadRecord.js +304 -0
- package/src/server/conversation/codexHelperThreadRecovery.js +54 -76
- package/src/server/conversation/codexHelperThreads.js +94 -93
- package/src/server/conversation/codexHistoryAdapter.js +13 -8
- package/src/server/conversation/codexIsolation.js +672 -0
- package/src/server/conversation/codexLiveItems.js +379 -0
- package/src/server/conversation/codexMessageCommands.js +68 -286
- package/src/server/conversation/codexMessageDelivery.js +46 -37
- package/src/server/conversation/codexModelCatalog.js +86 -7
- package/src/server/conversation/codexNotificationObserver.js +81 -88
- package/src/server/conversation/codexNotificationQueue.js +21 -10
- package/src/server/conversation/codexObservationControl.js +105 -89
- package/src/server/conversation/codexOutput.js +84 -419
- package/src/server/conversation/codexProcess.js +29 -1053
- package/src/server/conversation/codexProcessLeader.js +1 -0
- package/src/server/conversation/codexPromptDispatch.js +241 -0
- package/src/server/conversation/codexProvider.js +147 -1807
- package/src/server/conversation/codexProviderAuth.js +348 -0
- package/src/server/conversation/codexProviderInvalidation.js +371 -0
- package/src/server/conversation/codexProviderInventories.js +437 -0
- package/src/server/conversation/codexProviderOwner.js +149 -957
- package/src/server/conversation/codexProviderRelease.js +465 -0
- package/src/server/conversation/codexProviderSelection.js +26 -15
- package/src/server/conversation/codexProviderThreads.js +698 -0
- package/src/server/conversation/codexProviderTurns.js +453 -0
- package/src/server/conversation/codexReasoning.js +32 -23
- package/src/server/conversation/codexRenewalCommands.js +18 -6
- package/src/server/conversation/codexRenewalThreads.js +7 -22
- package/src/server/conversation/codexResultSettlement.js +70 -88
- package/src/server/conversation/codexRunJournal.js +91 -97
- package/src/server/conversation/codexRuntime.js +426 -0
- package/src/server/conversation/codexRuntimeInventory.js +113 -0
- package/src/server/conversation/codexRuntimeLifecycle.js +39 -13
- package/src/server/conversation/codexRuntimeStart.js +431 -0
- package/src/server/conversation/codexRuntimeStop.js +324 -0
- package/src/server/conversation/codexSessionCleanup.js +25 -10
- package/src/server/conversation/codexSessionReconciliation.js +21 -7
- package/src/server/conversation/codexThreadReadiness.js +49 -52
- package/src/server/conversation/codexThreadSnapshot.js +210 -0
- package/src/server/conversation/codexThreadStatus.js +48 -62
- package/src/server/conversation/codexTurn.js +171 -55
- package/src/server/conversation/codexTurnActivity.js +210 -0
- package/src/server/conversation/codexTurnControl.js +44 -48
- package/src/server/conversation/codexTurnEndings.js +610 -0
- package/src/server/conversation/codexTurnRecovery.js +97 -848
- package/src/server/conversation/codexTurnState.js +138 -111
- package/src/server/conversation/completedResponses.js +227 -0
- package/src/server/conversation/configuration.js +2 -2
- package/src/server/conversation/continuity.js +43 -6
- package/src/server/conversation/conversationDelivery.js +394 -0
- package/src/server/conversation/conversationEntries.js +365 -0
- package/src/server/conversation/conversationEvents.js +192 -0
- package/src/server/conversation/conversationGoals.js +187 -0
- package/src/server/conversation/conversationHandles.js +237 -0
- package/src/server/conversation/conversationReads.js +206 -0
- package/src/server/conversation/conversationRefusals.js +58 -0
- package/src/server/conversation/conversationReplacement.js +254 -0
- package/src/server/conversation/conversationSending.js +273 -0
- package/src/server/conversation/conversationStopping.js +121 -0
- package/src/server/conversation/conversationTurnDelivery.js +413 -0
- package/src/server/conversation/conversationTurns.js +511 -0
- package/src/server/conversation/deliveryTiming.js +25 -3
- package/src/server/conversation/fileStorage.js +11 -6
- package/src/server/conversation/hookBridge.js +14 -3
- package/src/server/conversation/index.js +1 -1
- package/src/server/conversation/localExecution.js +82 -625
- package/src/server/conversation/nativeCommandCallbacks.js +10 -0
- package/src/server/conversation/nativeConversationLifecycle.js +379 -0
- package/src/server/conversation/nativeHistoryExport.js +27 -18
- package/src/server/conversation/normalize.js +9 -0
- package/src/server/conversation/openCodeClient.js +295 -366
- package/src/server/conversation/openCodeNativeHistory.js +141 -0
- package/src/server/conversation/openCodeNativeSession.js +79 -0
- package/src/server/conversation/openCodeProcess.js +109 -53
- package/src/server/conversation/openCodeProcessOwner.js +565 -0
- package/src/server/conversation/openCodeRuntime.js +111 -1814
- package/src/server/conversation/openCodeSessionTurns.js +547 -0
- package/src/server/conversation/openCodeTemporaryConversations.js +394 -0
- package/src/server/conversation/openCodeTools.js +28 -14
- package/src/server/conversation/openCodeTurn.js +80 -74
- package/src/server/conversation/openCodeTurnMonitor.js +388 -0
- package/src/server/conversation/processIdentity.js +582 -0
- package/src/server/conversation/provider.js +21 -6
- package/src/server/conversation/providers/api.js +268 -107
- package/src/server/conversation/providers/claude.js +29 -6
- package/src/server/conversation/providers/claudeDriver.js +325 -250
- package/src/server/conversation/providers/codex.js +69 -33
- package/src/server/conversation/providers/codexDriver.js +503 -1081
- package/src/server/conversation/providers/codexDriverConnection.js +331 -0
- package/src/server/conversation/providers/codexDriverTurns.js +464 -0
- package/src/server/conversation/providers/opencode.js +30 -4
- package/src/server/conversation/providers/opencodeDriver.js +321 -659
- package/src/server/conversation/providers/opencodeStandalone.js +475 -0
- package/src/server/conversation/providers/scoped.js +64 -19
- package/src/server/conversation/runtime.js +171 -2863
- package/src/server/conversation/storage.js +91 -50
- package/src/server/conversation/streams.js +15 -2
- package/src/server/conversation/structuredOutput.js +7 -11
- package/src/server/conversation/systemPrompt.js +13 -1
- package/src/server/conversation/tools.js +47 -15
- package/src/server/conversation/transcript.js +49 -20
- package/src/server/hosts/claudeTurn.js +2 -4
- package/src/server/hosts/codexConfiguration.js +6 -8
- package/src/server/hosts/codexEvents.js +4 -2
- package/src/server/hosts/codexProcess.js +1 -1
- package/src/server/hosts/codexProvider.js +11 -9
- package/src/server/hosts/codexTurn.js +3 -3
- package/src/server/hosts/openCodeClient.js +4 -2
- package/src/server/index.js +0 -2
- package/src/server/lib/aiConnectionClient.js +35 -25
- package/src/server/lib/ndjson.js +1 -0
- package/src/server/lib/providers/anthropicClient.js +15 -6
- package/src/server/lib/providers/common.js +10 -6
- package/src/server/lib/providers/openAiCompatibleClient.js +40 -23
- package/src/server/lib/serviceToolCatalog.js +29 -283
- package/src/server/lib/serviceToolEntries.js +270 -0
- package/src/server/types.js +78 -0
- package/src/shared/assistantResource.js +0 -23
- package/src/shared/conversation/answerChoiceSugar.js +2 -14
- package/src/shared/conversation/messageInputSugar.js +18 -0
- package/src/shared/conversation/numberedQuestionSugar.js +6 -16
- package/src/shared/conversation/pagination.js +1 -1
- package/src/shared/conversation/questions.js +1 -0
- package/src/shared/conversation/streaming.js +1 -0
- package/src/shared/index.js +0 -1
- package/src/testing/conversationStorageContract.js +20 -0
- package/test/aiConnectionClient.test.js +42 -1
- package/test/apiConversationDriver.test.js +217 -38
- package/test/assistantBoundedToolLoop.test.js +1 -1
- package/test/claudeConversationSession.test.js +15 -11
- package/test/claudeInstructionResume.test.js +1 -1
- package/test/claudeProcess.test.js +9 -9
- package/test/claudeTurn.test.js +21 -8
- package/test/codexAccountChange.test.js +5 -3
- package/test/codexConversationSession.test.js +22 -21
- package/test/codexEvents.test.js +3 -1
- package/test/codexHelperDeletion.test.js +3 -7
- package/test/codexIsolation.test.js +6 -6
- package/test/codexModelCatalog.test.js +6 -7
- package/test/codexProcess.test.js +3 -3
- package/test/codexThreadSelection.test.js +4 -1
- package/test/codexTurn.test.js +29 -20
- package/test/conversationApiFacilities.test.js +11 -9
- package/test/conversationAttachments.test.js +3 -3
- package/test/conversationConfiguration.test.js +4 -4
- package/test/conversationNativeStorage.test.js +11 -10
- package/test/conversationReplacement.test.js +13 -13
- package/test/conversationRuntime.test.js +9 -5
- package/test/conversationSession.test.js +78 -22
- package/test/conversationTools.test.js +47 -26
- package/test/fileConversationStorage.test.js +10 -3
- package/test/fixtures/codexHelperThreadLedger.js +3 -3
- package/test/frameworkActions.test.js +33 -18
- package/test/localConversationExecution.test.js +4 -4
- package/test/localExecution.test.js +1 -1
- package/test/openCodeConnectionChange.test.js +3 -2
- package/test/openCodeRuntime.test.js +8 -7
- package/test/openCodeTools.test.js +1 -1
- package/test/opencodeConversationSession.test.js +4 -3
- package/test/serviceToolCatalog.test.js +3 -8
- package/src/server/lib/assistantCompletion.js +0 -190
- package/src/server/lib/assistantToolLoop.js +0 -259
|
@@ -0,0 +1,453 @@
|
|
|
1
|
+
import { CODEX_APP_SERVER_PROVIDER_ID } from "./codexProcess.js";
|
|
2
|
+
import { createHash, randomUUID } from "node:crypto";
|
|
3
|
+
import { codexAppServerErrorText } from "./codexEvents.js";
|
|
4
|
+
import { isRecord } from "@jskit-ai/kernel/shared/support/normalize";
|
|
5
|
+
import { normalizeNullableText as normalizeAgentText } from "./normalize.js";
|
|
6
|
+
|
|
7
|
+
/** @typedef {import("./codexProvider.js").CodexAppServerAgentProvider} CodexAppServerAgentProvider */
|
|
8
|
+
|
|
9
|
+
export function codexAppServerEndpointForTarget(endpoint = "") {
|
|
10
|
+
const normalizedEndpoint = normalizeAgentText(endpoint);
|
|
11
|
+
if (!normalizedEndpoint) {
|
|
12
|
+
return "";
|
|
13
|
+
}
|
|
14
|
+
return normalizedEndpoint;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export function codexTextInput(text = "") {
|
|
18
|
+
return {
|
|
19
|
+
text: String(text ?? ""),
|
|
20
|
+
text_elements: [],
|
|
21
|
+
type: "text"
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export function codexLocalImageInput(attachments = []) {
|
|
26
|
+
return attachments
|
|
27
|
+
.filter((attachment) => attachment.contentType?.startsWith("image/"))
|
|
28
|
+
.map((attachment) => ({ type: "localImage", path: attachment.path }));
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export async function sendCodexAppServerPrompt({
|
|
32
|
+
attachments = [],
|
|
33
|
+
clientUserMessageId = "",
|
|
34
|
+
outputSchema = null,
|
|
35
|
+
provider,
|
|
36
|
+
prompt = "",
|
|
37
|
+
threadId = "",
|
|
38
|
+
readOnly = false
|
|
39
|
+
} = {}, authorized = {}) {
|
|
40
|
+
const authoredInput = String(prompt ?? "");
|
|
41
|
+
const preparedInput = authorized.preparedInput;
|
|
42
|
+
if (preparedInput === undefined && !authoredInput.trim()) {
|
|
43
|
+
throw new Error("Codex app-server prompt is empty.");
|
|
44
|
+
}
|
|
45
|
+
const input = preparedInput === undefined ? [authoredInput, ...codexLocalImageInput(attachments)] : preparedInput;
|
|
46
|
+
const turnSettings = {
|
|
47
|
+
...authorized.turnSettings,
|
|
48
|
+
...(readOnly
|
|
49
|
+
? {
|
|
50
|
+
sandboxPolicy: {
|
|
51
|
+
networkAccess: false,
|
|
52
|
+
type: "readOnly"
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
: {}),
|
|
56
|
+
...(normalizeAgentText(clientUserMessageId)
|
|
57
|
+
? { clientUserMessageId: normalizeAgentText(clientUserMessageId) }
|
|
58
|
+
: {})
|
|
59
|
+
};
|
|
60
|
+
if (outputSchema && typeof outputSchema === "object" && !Array.isArray(outputSchema)) {
|
|
61
|
+
turnSettings.outputSchema = outputSchema;
|
|
62
|
+
}
|
|
63
|
+
const turn = await provider.sendTurn(threadId, input, turnSettings);
|
|
64
|
+
return {
|
|
65
|
+
input,
|
|
66
|
+
turn
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
export function codexTurnInput(input = []) {
|
|
71
|
+
const values = Array.isArray(input) ? input : [input];
|
|
72
|
+
return values.map((item) => {
|
|
73
|
+
if (isRecord(item) && item.type === "localImage" && typeof item.path === "string") {
|
|
74
|
+
return { type: "localImage", path: item.path };
|
|
75
|
+
}
|
|
76
|
+
if (isRecord(item) && item.type === "image" && typeof item.url === "string") {
|
|
77
|
+
return { type: "image", url: item.url };
|
|
78
|
+
}
|
|
79
|
+
if (isRecord(item) && item.type === "text") {
|
|
80
|
+
return codexTextInput(item.text);
|
|
81
|
+
}
|
|
82
|
+
return codexTextInput(item);
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
export function shellQuote(value = "") {
|
|
87
|
+
const text = String(value ?? "");
|
|
88
|
+
if (/^[A-Za-z0-9_./:=@+-]+$/u.test(text)) {
|
|
89
|
+
return text;
|
|
90
|
+
}
|
|
91
|
+
return `'${text.replaceAll("'", "'\"'\"'")}'`;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
export function codexControlProbeCommand(keys, marker) {
|
|
95
|
+
const source = [
|
|
96
|
+
"const {createHash}=require('node:crypto');",
|
|
97
|
+
`const keys=${JSON.stringify(keys)};`,
|
|
98
|
+
`process.stdout.write(${JSON.stringify(marker)}+createHash('sha256').update(JSON.stringify(keys.map(key=>[key,process.env[key]]))).digest('hex'))`
|
|
99
|
+
].join("");
|
|
100
|
+
return `${shellQuote(process.execPath)} -e ${shellQuote(source)}`;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
export function codexCliResumeCommand({
|
|
104
|
+
codexCommand = "",
|
|
105
|
+
endpoint = "",
|
|
106
|
+
threadId = ""
|
|
107
|
+
} = {}) {
|
|
108
|
+
const normalizedEndpoint = codexAppServerEndpointForTarget(endpoint);
|
|
109
|
+
const resolvedCodexCommand = normalizeAgentText(codexCommand) || "codex";
|
|
110
|
+
const normalizedThreadId = normalizeAgentText(threadId);
|
|
111
|
+
if (!normalizedEndpoint) {
|
|
112
|
+
throw new Error("Codex app-server endpoint is required for the native CLI command.");
|
|
113
|
+
}
|
|
114
|
+
if (!normalizedThreadId) {
|
|
115
|
+
throw new Error("Codex thread id is required for the native CLI command.");
|
|
116
|
+
}
|
|
117
|
+
const argv = [
|
|
118
|
+
resolvedCodexCommand,
|
|
119
|
+
"-c",
|
|
120
|
+
"check_for_update_on_startup=false",
|
|
121
|
+
"--remote",
|
|
122
|
+
normalizedEndpoint,
|
|
123
|
+
"resume",
|
|
124
|
+
normalizedThreadId
|
|
125
|
+
];
|
|
126
|
+
return {
|
|
127
|
+
argv,
|
|
128
|
+
command: argv.map(shellQuote).join(" ")
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
function normalizeAgentTurn(value = {}) {
|
|
133
|
+
const turn = value && typeof value === "object" && !Array.isArray(value) ? value : {};
|
|
134
|
+
return {
|
|
135
|
+
id: normalizeAgentText(turn.id || turn.turnId),
|
|
136
|
+
provider: normalizeAgentText(turn.provider),
|
|
137
|
+
// readable-check: allow no-dual-shape - data: a turn record arrives with Codex's raw turn or is that raw turn
|
|
138
|
+
raw: turn.raw || turn,
|
|
139
|
+
status: normalizeAgentText(turn.status || turn.raw?.status)
|
|
140
|
+
};
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
// The one reading of a sendTurn delivery. Its turn is already normalized; the
|
|
144
|
+
// provider's own error stays on the raw native turn.
|
|
145
|
+
export function codexAppServerDeliveredTurn(delivery) {
|
|
146
|
+
const turn = delivery?.turn || {};
|
|
147
|
+
return {
|
|
148
|
+
turnId: normalizeAgentText(turn.id),
|
|
149
|
+
status: normalizeAgentText(turn.status || turn.raw?.status),
|
|
150
|
+
error: codexAppServerErrorText(turn.raw?.error || turn.response?.turn?.error || turn.error)
|
|
151
|
+
};
|
|
152
|
+
}
|
|
153
|
+
/**
|
|
154
|
+
* The provider's turns: sending, steering and interrupting them, the native commands they start, and the
|
|
155
|
+
* control probes that verify a thread's environment.
|
|
156
|
+
* @param {object} dependencies
|
|
157
|
+
* @param {CodexAppServerAgentProvider} dependencies.provider
|
|
158
|
+
*/
|
|
159
|
+
export function createCodexProviderTurns({ provider }) {
|
|
160
|
+
// Native commands a turn started, by thread, turn and item.
|
|
161
|
+
const commandExecutions = new Map();
|
|
162
|
+
// How each interrupted turn ended, by thread and turn.
|
|
163
|
+
const interruptedTurns = new Map();
|
|
164
|
+
// Each thread's pending or verified environment probe.
|
|
165
|
+
const threadControlProbes = new Map();
|
|
166
|
+
let commandStopFailure = null;
|
|
167
|
+
|
|
168
|
+
async function sendTurn(threadId = "", input = [], params = {}, { signal } = {}) {
|
|
169
|
+
const operation = async () => {
|
|
170
|
+
const client = await provider.activeClient();
|
|
171
|
+
return client.request("turn/start", {
|
|
172
|
+
...params,
|
|
173
|
+
input: codexTurnInput(input),
|
|
174
|
+
threadId: normalizeAgentText(threadId || params.threadId)
|
|
175
|
+
}, { signal });
|
|
176
|
+
};
|
|
177
|
+
const response = provider.options.prepareThreadEnvironment
|
|
178
|
+
? await provider.withThreadEnvironment(threadId || params.threadId, {}, operation)
|
|
179
|
+
: await provider.runRequest(operation, "codex-app-server-turn-start");
|
|
180
|
+
return {
|
|
181
|
+
...normalizeAgentTurn({
|
|
182
|
+
id: response?.turn?.id || response?.turnId,
|
|
183
|
+
provider: CODEX_APP_SERVER_PROVIDER_ID,
|
|
184
|
+
// readable-check: allow no-dual-shape - data: Codex replies to a turn request with the turn wrapped or bare
|
|
185
|
+
raw: response?.turn || response
|
|
186
|
+
}),
|
|
187
|
+
response
|
|
188
|
+
};
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
async function steerTurn(threadId = "", turnId = "", input = [], params = {}, { signal } = {}) {
|
|
192
|
+
const client = await provider.activeClient();
|
|
193
|
+
const response = await provider.runRequest(
|
|
194
|
+
() => client.request("turn/steer", {
|
|
195
|
+
...params,
|
|
196
|
+
expectedTurnId: normalizeAgentText(turnId || params.expectedTurnId),
|
|
197
|
+
input: codexTurnInput(input),
|
|
198
|
+
threadId: normalizeAgentText(threadId || params.threadId)
|
|
199
|
+
}, { signal }),
|
|
200
|
+
"codex-app-server-turn-steer"
|
|
201
|
+
);
|
|
202
|
+
return {
|
|
203
|
+
...normalizeAgentTurn({
|
|
204
|
+
id: response?.turn?.id || response?.turnId || turnId,
|
|
205
|
+
provider: CODEX_APP_SERVER_PROVIDER_ID,
|
|
206
|
+
// readable-check: allow no-dual-shape - data: Codex replies to a turn request with the turn wrapped or bare
|
|
207
|
+
raw: response?.turn || response
|
|
208
|
+
}),
|
|
209
|
+
response
|
|
210
|
+
};
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
function interruptionOutcome(threadId = "", turnId = "") {
|
|
214
|
+
const key = JSON.stringify([normalizeAgentText(threadId), normalizeAgentText(turnId)]);
|
|
215
|
+
return interruptedTurns.get(key) || "";
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
async function interruptTurn(threadId = "", turnId = "", { outcome = "" } = {}) {
|
|
219
|
+
const client = await provider.activeClient();
|
|
220
|
+
return provider.runRequest(
|
|
221
|
+
() => interruptNativeTurn(client, normalizeAgentText(threadId), normalizeAgentText(turnId), undefined, outcome),
|
|
222
|
+
"codex-app-server-turn-interrupt"
|
|
223
|
+
);
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
async function interruptNativeTurn(client, threadId, turnId, signal, outcome = "") {
|
|
227
|
+
const key = JSON.stringify([threadId, turnId]);
|
|
228
|
+
interruptedTurns.set(key, outcome || interruptedTurns.get(key) || "");
|
|
229
|
+
const result = await client.request("turn/interrupt", { threadId, turnId }, { signal });
|
|
230
|
+
await Promise.all([...commandExecutions.values()]
|
|
231
|
+
.filter((command) => command.threadId === threadId && command.turnId === turnId)
|
|
232
|
+
.map((command) => stopCommandExecution(command)));
|
|
233
|
+
return result;
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
function stopCommandExecution(command) {
|
|
237
|
+
if (command.stopTask) return command.stopTask;
|
|
238
|
+
command.stopTask = (async () => {
|
|
239
|
+
const signal = AbortSignal.timeout(5000);
|
|
240
|
+
const request = (method, params) => command.client.request(method, params, { signal });
|
|
241
|
+
while (!command.completed) {
|
|
242
|
+
signal.throwIfAborted();
|
|
243
|
+
let cursor;
|
|
244
|
+
let terminal;
|
|
245
|
+
const cursors = new Set();
|
|
246
|
+
do {
|
|
247
|
+
const page = await request("thread/backgroundTerminals/list", {
|
|
248
|
+
threadId: command.threadId, limit: 100, ...(cursor ? { cursor } : {})
|
|
249
|
+
});
|
|
250
|
+
if (!Array.isArray(page.data)) throw new Error("Codex returned no command inventory.");
|
|
251
|
+
terminal = page.data.find((entry) => entry.processId === command.processId);
|
|
252
|
+
cursor = page.nextCursor;
|
|
253
|
+
if (cursor && cursors.has(cursor)) throw new Error("Codex repeated its command inventory cursor.");
|
|
254
|
+
cursors.add(cursor);
|
|
255
|
+
} while (!terminal && cursor);
|
|
256
|
+
if (command.completed) return;
|
|
257
|
+
if (terminal) {
|
|
258
|
+
// A recycled process ID must never target a different command.
|
|
259
|
+
if (terminal.itemId !== command.itemId) throw new Error("The native command identity changed during Stop.");
|
|
260
|
+
const stopped = await request("thread/backgroundTerminals/terminate", {
|
|
261
|
+
threadId: command.threadId, processId: command.processId
|
|
262
|
+
});
|
|
263
|
+
if (stopped.terminated === true) return;
|
|
264
|
+
}
|
|
265
|
+
// Codex emits command-start before adding it to the process inventory.
|
|
266
|
+
// Absence during that interval is not proof that the command exited.
|
|
267
|
+
await new Promise((resolve) => setTimeout(resolve, 25));
|
|
268
|
+
}
|
|
269
|
+
})().catch((cause) => {
|
|
270
|
+
const error = Object.assign(new Error("Codex could not confirm that the stopped turn's command exited.", { cause }), {
|
|
271
|
+
code: `${provider.errorPrefix}codex_command_stop_unconfirmed`
|
|
272
|
+
});
|
|
273
|
+
commandStopFailure = error;
|
|
274
|
+
// A failed native control stops work through the lost-observation path, whose owner verifies the
|
|
275
|
+
// runtime stop. That owner may already be awaiting this command while stopping a lost observation,
|
|
276
|
+
// so command cleanup does not wait on its own caller.
|
|
277
|
+
void Promise.resolve(provider.failObservation(error)).catch(() => null);
|
|
278
|
+
throw error;
|
|
279
|
+
});
|
|
280
|
+
return command.stopTask;
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
function nativeCliResumeCommand(threadId = "") {
|
|
284
|
+
const runtime = provider.runtime || {};
|
|
285
|
+
return codexCliResumeCommand({
|
|
286
|
+
codexCommand: provider.options.codexCommand || "codex",
|
|
287
|
+
endpoint: runtime.endpoint,
|
|
288
|
+
threadId
|
|
289
|
+
});
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
async function verifyThreadEnvironment(threadId, environment, request, signal, { requiredKeys = [] } = {}) {
|
|
293
|
+
const keys = Object.keys(environment).filter((key) => key.startsWith(provider.configuration.controlEnvironmentPrefix) || requiredKeys.includes(key)).sort();
|
|
294
|
+
if (!keys.length) return;
|
|
295
|
+
const marker = `${provider.configuration.controlProbePrefix}${randomUUID()}:`;
|
|
296
|
+
const probe = { marker, pending: [], verified: false, turnId: "" };
|
|
297
|
+
threadControlProbes.set(threadId, probe);
|
|
298
|
+
const expected = createHash("sha256").update(JSON.stringify(keys.map((key) => [key, environment[key]]))).digest("hex");
|
|
299
|
+
// This bounded native shell check uses no model and prints only a digest,
|
|
300
|
+
// never credentials or environment values.
|
|
301
|
+
await request("thread/shellCommand", {
|
|
302
|
+
threadId, command: codexControlProbeCommand(keys, marker), timeoutMs: 2000
|
|
303
|
+
});
|
|
304
|
+
while (true) {
|
|
305
|
+
signal.throwIfAborted();
|
|
306
|
+
// The native completion event owns this result; saved history is not a
|
|
307
|
+
// second acknowledgement of this live control operation.
|
|
308
|
+
if (probe.completed && probe.result) {
|
|
309
|
+
if (probe.result.type !== "commandExecution" || probe.result.exitCode !== 0 ||
|
|
310
|
+
probe.result.aggregatedOutput?.trim() !== `${marker}${expected}`) {
|
|
311
|
+
throw Object.assign(new Error("Another native subscriber retained the previous assistant settings. Close the native assistant terminal and retry Resume."), {
|
|
312
|
+
code: "assistant_agent_control_binding_retained"
|
|
313
|
+
});
|
|
314
|
+
}
|
|
315
|
+
return;
|
|
316
|
+
}
|
|
317
|
+
await new Promise((resolve) => setTimeout(resolve, 25));
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
function isControlProbeTurn(threadId, turnId) {
|
|
322
|
+
const probe = threadControlProbes.get(threadId);
|
|
323
|
+
return Boolean(turnId && probe?.verified && probe.turnId === turnId);
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
function recordInterruption(threadId, turnId) {
|
|
327
|
+
const key = JSON.stringify([threadId, turnId]);
|
|
328
|
+
interruptedTurns.set(key, interruptedTurns.get(key) || "control_reconfiguration");
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
// A thread whose control recovery failed publishes every event its unverified probe held back.
|
|
332
|
+
function abandonControlProbe(threadId) {
|
|
333
|
+
const probe = threadControlProbes.get(threadId);
|
|
334
|
+
if (probe && !probe.verified) {
|
|
335
|
+
threadControlProbes.delete(threadId);
|
|
336
|
+
for (const pending of probe.pending) provider.publishNotification(pending);
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
/**
|
|
341
|
+
* Tracks the native commands and control probes a notification reports, and says whether subscribers see it:
|
|
342
|
+
* a verified control probe's events, and an unverified probe's held events, are not published.
|
|
343
|
+
*/
|
|
344
|
+
function observeNotification(notification) {
|
|
345
|
+
const threadId = notification.params?.threadId;
|
|
346
|
+
const turnId = notification.params?.turnId;
|
|
347
|
+
const item = notification.params?.item;
|
|
348
|
+
if (item?.type === "commandExecution" && item.processId && item.source === "unifiedExecStartup") {
|
|
349
|
+
const key = JSON.stringify([threadId, turnId, item.id]);
|
|
350
|
+
if (notification.method === "item/completed") {
|
|
351
|
+
const command = commandExecutions.get(key);
|
|
352
|
+
if (command) command.completed = true;
|
|
353
|
+
commandExecutions.delete(key);
|
|
354
|
+
} else if (notification.method === "item/started") {
|
|
355
|
+
const command = commandExecutions.get(key) || {
|
|
356
|
+
threadId, turnId, itemId: item.id, processId: item.processId, client: provider.client
|
|
357
|
+
};
|
|
358
|
+
commandExecutions.set(key, command);
|
|
359
|
+
// Native startup may finish after turn/interrupt has already returned.
|
|
360
|
+
if (interruptedTurns.has(JSON.stringify([threadId, turnId]))) {
|
|
361
|
+
void stopCommandExecution(command).catch(() => null);
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
const probe = threadControlProbes.get(threadId);
|
|
366
|
+
const method = notification.method;
|
|
367
|
+
if (probe && (/^(turn|item)\//u.test(method) || method === "thread/status/changed")) {
|
|
368
|
+
const turnId = notification.params?.turnId || notification.params?.turn?.id;
|
|
369
|
+
if (method === "turn/started" && probe.turnId && probe.turnId !== turnId) {
|
|
370
|
+
threadControlProbes.delete(threadId);
|
|
371
|
+
} else if (probe.verified) {
|
|
372
|
+
if (turnId === probe.turnId) {
|
|
373
|
+
if (method === "item/completed" && notification.params.item?.id === probe.itemId) {
|
|
374
|
+
probe.result = notification.params.item;
|
|
375
|
+
}
|
|
376
|
+
if (method === "turn/completed") probe.completed = true;
|
|
377
|
+
}
|
|
378
|
+
return false;
|
|
379
|
+
} else {
|
|
380
|
+
if (method === "turn/started") probe.turnId = turnId;
|
|
381
|
+
probe.pending.push(notification);
|
|
382
|
+
if (method === "item/started" || probe.pending.length >= 32) {
|
|
383
|
+
const item = notification.params?.item;
|
|
384
|
+
if (item?.type === "commandExecution" && item.command?.includes(probe.marker)) {
|
|
385
|
+
probe.verified = true;
|
|
386
|
+
probe.itemId = item.id;
|
|
387
|
+
probe.pending = [];
|
|
388
|
+
} else {
|
|
389
|
+
// A concurrent native user turn must retain every event. Only a
|
|
390
|
+
// positively identified control probe may be hidden from chat.
|
|
391
|
+
threadControlProbes.delete(threadId);
|
|
392
|
+
for (const pending of probe.pending) provider.publishNotification(pending);
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
return false;
|
|
396
|
+
}
|
|
397
|
+
}
|
|
398
|
+
return true;
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
async function stopThreadForObservationLoss(threadId, turnId) {
|
|
402
|
+
// Control uses only this open socket. It must not spawn or resume work
|
|
403
|
+
// to find out whether the work we lost sight of has stopped.
|
|
404
|
+
const client = provider.client;
|
|
405
|
+
if (!client?.isOpen()) throw new Error("Codex control connection is unavailable.");
|
|
406
|
+
if (commandStopFailure) throw commandStopFailure;
|
|
407
|
+
const signal = AbortSignal.timeout(5_000);
|
|
408
|
+
const request = (method, params) => client.request(method, params, { signal });
|
|
409
|
+
let { goal } = await request("thread/goal/get", { threadId });
|
|
410
|
+
if (goal?.status === "active") {
|
|
411
|
+
const result = await request("thread/goal/set", { threadId, status: "paused" });
|
|
412
|
+
if (result.goal?.status !== "paused" || result.goal?.createdAt !== goal.createdAt || result.goal?.objective !== goal.objective) {
|
|
413
|
+
throw new Error("Codex did not confirm that the same goal was paused.");
|
|
414
|
+
}
|
|
415
|
+
goal = result.goal;
|
|
416
|
+
}
|
|
417
|
+
const readStatus = async () => {
|
|
418
|
+
const { thread } = await request("thread/read", { threadId, includeTurns: false });
|
|
419
|
+
return typeof thread?.status === "string" ? thread.status : thread?.status?.type;
|
|
420
|
+
};
|
|
421
|
+
if (!["idle", "notLoaded"].includes(await readStatus())) {
|
|
422
|
+
if (!turnId) {
|
|
423
|
+
const page = await request("thread/turns/list", { threadId, limit: 1, sortDirection: "desc", itemsView: "summary" });
|
|
424
|
+
turnId = page.data?.[0]?.id;
|
|
425
|
+
}
|
|
426
|
+
if (!turnId) throw new Error("Codex's running turn could not be identified.");
|
|
427
|
+
await interruptNativeTurn(client, threadId, turnId, signal);
|
|
428
|
+
if (await readStatus() !== "idle") throw new Error("Codex did not confirm that its turn stopped.");
|
|
429
|
+
}
|
|
430
|
+
return { goal };
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
function clear() {
|
|
434
|
+
threadControlProbes.clear();
|
|
435
|
+
commandExecutions.clear();
|
|
436
|
+
interruptedTurns.clear();
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
return Object.freeze({
|
|
440
|
+
sendTurn,
|
|
441
|
+
steerTurn,
|
|
442
|
+
interruptionOutcome,
|
|
443
|
+
interruptTurn,
|
|
444
|
+
nativeCliResumeCommand,
|
|
445
|
+
verifyThreadEnvironment,
|
|
446
|
+
isControlProbeTurn,
|
|
447
|
+
recordInterruption,
|
|
448
|
+
abandonControlProbe,
|
|
449
|
+
observeNotification,
|
|
450
|
+
stopThreadForObservationLoss,
|
|
451
|
+
clear
|
|
452
|
+
});
|
|
453
|
+
}
|
|
@@ -1,8 +1,17 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { codexAppServerTurnCanReceiveProviderActivity, codexAppServerTurnKey } from "./codexTurnState.js";
|
|
2
2
|
import { codexAppServerContentText, codexAppServerNotificationItem, codexAppServerOutputOwnerTurnId, codexAppServerNotificationParams, codexAppServerNotificationTurnId } from "./codexEvents.js";
|
|
3
|
+
import { normalizeText } from "@jskit-ai/kernel/shared/support/normalize";
|
|
3
4
|
|
|
4
|
-
|
|
5
|
-
|
|
5
|
+
/**
|
|
6
|
+
* Per-turn reasoning channels, their persistence queue and cleanup. The output owner that builds it shares these Maps
|
|
7
|
+
* with its run owner.
|
|
8
|
+
* @param {object} dependencies
|
|
9
|
+
* @param {import("./codexTurn.js").CodexCreateStore} dependencies.createStore
|
|
10
|
+
* @param {import("./codexTurn.js").CodexPublish} dependencies.publish
|
|
11
|
+
* @param {import("./codexTurn.js").CodexAgentRunTurnStateReader} dependencies.turnStateFromAgentRun
|
|
12
|
+
* @param {import("./codexTurn.js").CodexDebugLog} dependencies.debugLog
|
|
13
|
+
* @param {(store: object, sessionId?: string) => Promise<object | null>} dependencies.readCodexAppServerAgentRunForSession
|
|
14
|
+
*/
|
|
6
15
|
export function createCodexAppServerReasoning({
|
|
7
16
|
createStore,
|
|
8
17
|
publish,
|
|
@@ -41,7 +50,7 @@ export function createCodexAppServerReasoning({
|
|
|
41
50
|
function codexAppServerReasoningSummaryKey(notification = {}) {
|
|
42
51
|
const params = codexAppServerNotificationParams(notification);
|
|
43
52
|
const item = codexAppServerNotificationItem(notification);
|
|
44
|
-
const itemId =
|
|
53
|
+
const itemId = normalizeText(params.itemId || item?.id || "summary");
|
|
45
54
|
const summaryIndex = String(params.summaryIndex ?? params.contentIndex ?? params.index ?? 0).trim() || "0";
|
|
46
55
|
return `${itemId}:${summaryIndex}`;
|
|
47
56
|
}
|
|
@@ -63,7 +72,7 @@ export function createCodexAppServerReasoning({
|
|
|
63
72
|
}
|
|
64
73
|
|
|
65
74
|
function codexAppServerReasoningSummaryDisplayText(value = "") {
|
|
66
|
-
let text =
|
|
75
|
+
let text = normalizeText(value).replace(/\r\n/gu, "\n");
|
|
67
76
|
if (!text) {
|
|
68
77
|
return "";
|
|
69
78
|
}
|
|
@@ -79,7 +88,7 @@ export function createCodexAppServerReasoning({
|
|
|
79
88
|
}
|
|
80
89
|
|
|
81
90
|
function codexAppServerReasoningDisplayText(value = "") {
|
|
82
|
-
return
|
|
91
|
+
return normalizeText(value)
|
|
83
92
|
.replace(/\r\n/gu, "\n")
|
|
84
93
|
.split(/\n{2,}/u)
|
|
85
94
|
.map(codexAppServerReasoningSummaryDisplayText)
|
|
@@ -91,28 +100,28 @@ export function createCodexAppServerReasoning({
|
|
|
91
100
|
function recordCodexAppServerReasoningNotification(threadId = "", notification = {}, {
|
|
92
101
|
turnId = ""
|
|
93
102
|
} = {}) {
|
|
94
|
-
const method =
|
|
103
|
+
const method = normalizeText(notification.method);
|
|
95
104
|
const item = codexAppServerNotificationItem(notification);
|
|
96
105
|
const completed = method === "item/completed" && item?.type === "reasoning";
|
|
97
106
|
if (!completed && !["item/reasoning/summaryPartAdded", "item/reasoning/summaryTextDelta", "item/reasoning/textDelta"].includes(method)) {
|
|
98
107
|
return false;
|
|
99
108
|
}
|
|
100
|
-
const normalizedThreadId =
|
|
101
|
-
const normalizedTurnId =
|
|
109
|
+
const normalizedThreadId = normalizeText(threadId);
|
|
110
|
+
const normalizedTurnId = normalizeText(turnId) || codexAppServerNotificationTurnId(notification);
|
|
102
111
|
if (!normalizedThreadId) {
|
|
103
112
|
return false;
|
|
104
113
|
}
|
|
105
114
|
const state = codexAppServerReasoningTurnState(normalizedThreadId, normalizedTurnId);
|
|
106
115
|
const params = codexAppServerNotificationParams(notification);
|
|
107
|
-
const itemId =
|
|
116
|
+
const itemId = normalizeText(params.itemId || item?.id || "summary");
|
|
108
117
|
if (completed) {
|
|
109
118
|
// Completed-only providers expose the same readable parts in the item.
|
|
110
119
|
// Streamed items have already been recorded; do not replay their text.
|
|
111
120
|
if (state.channels.has(itemId)) return false;
|
|
112
121
|
const summary = codexAppServerContentText(item.summary);
|
|
113
|
-
const text =
|
|
122
|
+
const text = normalizeText(summary) ? summary : codexAppServerContentText(item.content);
|
|
114
123
|
return recordCodexAppServerReasoningNotification(normalizedThreadId, {
|
|
115
|
-
method:
|
|
124
|
+
method: normalizeText(summary) ? "item/reasoning/summaryTextDelta" : "item/reasoning/textDelta",
|
|
116
125
|
params: { itemId, delta: text }
|
|
117
126
|
}, { turnId: normalizedTurnId });
|
|
118
127
|
}
|
|
@@ -147,8 +156,8 @@ export function createCodexAppServerReasoning({
|
|
|
147
156
|
}
|
|
148
157
|
|
|
149
158
|
async function recordCodexAppServerReasoningForSession(sessionId = "", threadId = "", notifications = []) {
|
|
150
|
-
const normalizedSessionId =
|
|
151
|
-
const normalizedThreadId =
|
|
159
|
+
const normalizedSessionId = normalizeText(sessionId);
|
|
160
|
+
const normalizedThreadId = normalizeText(threadId);
|
|
152
161
|
const store = await createStore(normalizedSessionId);
|
|
153
162
|
const run = await readCodexAppServerAgentRunForSession(store, normalizedSessionId);
|
|
154
163
|
const currentTurn = turnStateFromAgentRun(run || {});
|
|
@@ -189,14 +198,14 @@ export function createCodexAppServerReasoning({
|
|
|
189
198
|
|
|
190
199
|
function codexAppServerReasoningPersistKey(sessionId = "", threadId = "", turnId = "") {
|
|
191
200
|
return [
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
201
|
+
normalizeText(sessionId),
|
|
202
|
+
normalizeText(threadId),
|
|
203
|
+
normalizeText(turnId) || "*"
|
|
195
204
|
].filter(Boolean).join(":");
|
|
196
205
|
}
|
|
197
206
|
|
|
198
207
|
async function persistCodexAppServerReasoningSummary(sessionId = "", threadId = "", turnId = "") {
|
|
199
|
-
const normalizedSessionId =
|
|
208
|
+
const normalizedSessionId = normalizeText(sessionId);
|
|
200
209
|
const state = codexAppServerReasoningExistingTurnState(threadId, turnId);
|
|
201
210
|
const segments = Array.isArray(state?.segments) ? state.segments : [];
|
|
202
211
|
const pendingSegments = segments
|
|
@@ -210,7 +219,7 @@ export function createCodexAppServerReasoning({
|
|
|
210
219
|
}
|
|
211
220
|
const store = await createStore(normalizedSessionId);
|
|
212
221
|
const run = await readCodexAppServerAgentRunForSession(store, normalizedSessionId);
|
|
213
|
-
if (
|
|
222
|
+
if (normalizeText(run?.inputSource) === "terminal") {
|
|
214
223
|
return;
|
|
215
224
|
}
|
|
216
225
|
const turn = turnStateFromAgentRun(run || {});
|
|
@@ -221,8 +230,8 @@ export function createCodexAppServerReasoning({
|
|
|
221
230
|
currentThreadId: turn.threadId,
|
|
222
231
|
currentTurnId: turn.turnId,
|
|
223
232
|
sessionId: normalizedSessionId,
|
|
224
|
-
threadId:
|
|
225
|
-
turnId:
|
|
233
|
+
threadId: normalizeText(threadId),
|
|
234
|
+
turnId: normalizeText(turnId)
|
|
226
235
|
});
|
|
227
236
|
return;
|
|
228
237
|
}
|
|
@@ -302,7 +311,7 @@ export function createCodexAppServerReasoning({
|
|
|
302
311
|
return true;
|
|
303
312
|
}
|
|
304
313
|
|
|
305
|
-
return {
|
|
314
|
+
return Object.freeze({
|
|
306
315
|
reasoningTurns: codexAppServerReasoningTurns,
|
|
307
316
|
reasoningPersistQueues: codexAppServerReasoningPersistQueues,
|
|
308
317
|
recordReasoningForSession: recordCodexAppServerReasoningForSession,
|
|
@@ -310,5 +319,5 @@ export function createCodexAppServerReasoning({
|
|
|
310
319
|
flushReasoningPersist: flushCodexAppServerReasoningPersist,
|
|
311
320
|
cleanupReasoningTurn: cleanupCodexAppServerReasoningTurn,
|
|
312
321
|
splitReasoningTurn: splitCodexAppServerReasoningTurn
|
|
313
|
-
};
|
|
322
|
+
});
|
|
314
323
|
}
|
|
@@ -1,10 +1,23 @@
|
|
|
1
1
|
import { codexAppServerTurnStatusIsSuccessfulComplete, codexAppServerTurnStatusIsProviderFailure, codexAppServerErrorMessage } from "./codexTurnState.js";
|
|
2
2
|
import { createCodexAppServerDetachedTurnWatcher, waitForCodexAppServerTurn } from "./codexDetachedTurn.js";
|
|
3
|
-
import { codexAppServerDeliveredTurn, sendCodexAppServerPrompt } from "./
|
|
3
|
+
import { codexAppServerDeliveredTurn, sendCodexAppServerPrompt } from "./codexProviderTurns.js";
|
|
4
4
|
import { resumeExactCodexAppServerThread, startFreshCodexAppServerThread } from "./codexRenewalThreads.js";
|
|
5
|
-
import { codexAppServerProviderTurnId, inspectCodexAppServerRenewalThread } from "./
|
|
5
|
+
import { codexAppServerProviderTurnId, inspectCodexAppServerRenewalThread } from "./codexThreadSnapshot.js";
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
/**
|
|
8
|
+
* The run owner's renewal commands: the handover of a running conversation to a renewed runtime, and its seed turn.
|
|
9
|
+
* @param {object} dependencies
|
|
10
|
+
* @param {import("./codexRunJournal.js").CodexRunJournal["claimTurnStart"]} dependencies.claimCodexAppServerTurnStart
|
|
11
|
+
* @param {import("./codexNotificationQueue.js").CodexAppServerNotificationQueue} dependencies.codexAppServerNotificationQueue
|
|
12
|
+
* @param {import("./codexTurnRecovery.js").CodexTurnRecovery["completeTurn"]} dependencies.completeCodexAppServerTurn
|
|
13
|
+
* @param {string} dependencies.errorPrefix
|
|
14
|
+
* @param {import("./codexTurnRecovery.js").CodexTurnRecovery["markTurnActive"]} dependencies.markCodexAppServerTurnActive
|
|
15
|
+
* @param {import("./codexRunJournal.js").CodexRunJournal["markTurnIdle"]} dependencies.markCodexAppServerTurnIdle
|
|
16
|
+
* @param {import("./codexNotificationObserver.js").CodexNotificationObserver} dependencies.observer
|
|
17
|
+
* @param {import("./codexProviderSelection.js").CodexProviderSelection} dependencies.selection
|
|
18
|
+
* @param {string} dependencies.turnAlreadyRunningError
|
|
19
|
+
* @param {import("./codexRunJournal.js").CodexRunJournal["writeUserMessageOwnership"]} dependencies.writeCodexAppServerUserMessageOwnership
|
|
20
|
+
*/
|
|
8
21
|
export function createCodexRenewalCommands({
|
|
9
22
|
claimCodexAppServerTurnStart,
|
|
10
23
|
codexAppServerNotificationQueue,
|
|
@@ -285,9 +298,8 @@ export function createCodexRenewalCommands({
|
|
|
285
298
|
return { result, reconciled, turnId, threadId, freshThread: started.fresh };
|
|
286
299
|
}
|
|
287
300
|
|
|
288
|
-
|
|
289
|
-
return {
|
|
301
|
+
return Object.freeze({
|
|
290
302
|
runCodexAppServerRenewalHandover,
|
|
291
303
|
runCodexAppServerRenewalSeed
|
|
292
|
-
};
|
|
304
|
+
});
|
|
293
305
|
}
|