@jskit-ai/assistant-core 0.2.6 → 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 +18 -12
- 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,378 @@
|
|
|
1
|
+
import { codexAppServerTurnStatusIsSuccessfulComplete, codexAppServerTurnStatusIsProviderFailure, codexAppServerThreadStatus, codexAppServerErrorMessage, codexAppServerSteerFailure, codexAppServerInterruptFailure, codexAppServerConversationTurnIsActive } from "./codexTurnState.js";
|
|
2
|
+
import { CODEX_APP_SERVER_DETACHED_TURN_TIMEOUT_MS, createCodexAppServerDetachedTurnWatcher } from "./codexDetachedTurn.js";
|
|
3
|
+
import { assertCodexAppServerHelperAccountIdentity, readCodexAppServerAccountIdentity, sendPreparedCodexAppServerHelperTurn } from "./codexHelperExecution.js";
|
|
4
|
+
import { codexAppServerProjectHookTrustConfig } from "./codexConfiguration.js";
|
|
5
|
+
import { codexAppServerThreadError } from "./codexThreadSnapshot.js";
|
|
6
|
+
import { codexAppServerDeliveredTurn, codexLocalImageInput, sendCodexAppServerPrompt } from "./codexProviderTurns.js";
|
|
7
|
+
import { normalizeText } from "@jskit-ai/kernel/shared/support/normalize";
|
|
8
|
+
|
|
9
|
+
/** A conversation turn's listener when the application supplies none. */
|
|
10
|
+
export function ignoreCodexConversationEvent() {}
|
|
11
|
+
|
|
12
|
+
function notifyNoConversationPromptSending() {}
|
|
13
|
+
|
|
14
|
+
// What a read reports for a conversation this server tracks without a persistent native history.
|
|
15
|
+
export function codexAppServerEphemeralConversationSnapshot(state = {}) {
|
|
16
|
+
return {
|
|
17
|
+
conversationId: normalizeText(state.conversationId),
|
|
18
|
+
error: normalizeText(state.error),
|
|
19
|
+
message: normalizeText(state.message),
|
|
20
|
+
ok: true,
|
|
21
|
+
outcome: state.outcome || null,
|
|
22
|
+
progressUpdates: Array.isArray(state.progressUpdates)
|
|
23
|
+
? state.progressUpdates.map((update = {}) => ({
|
|
24
|
+
id: normalizeText(update.id),
|
|
25
|
+
text: normalizeText(update.text)
|
|
26
|
+
})).filter((update) => update.id && update.text)
|
|
27
|
+
: [],
|
|
28
|
+
rawText: normalizeText(state.rawText),
|
|
29
|
+
messageId: normalizeText(state.messageId),
|
|
30
|
+
runId: normalizeText(state.runId),
|
|
31
|
+
status: normalizeText(state.status) || "ready",
|
|
32
|
+
turnMetadata: state.turnMetadata || null
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// Thread settings for a conversation: a Helper's come from its isolation inspection, others from the
|
|
37
|
+
// application's settings with the project's hook trust when it asks for them.
|
|
38
|
+
export async function prepareCodexAppServerConversationThread(provider, preparation, helperIsolation) {
|
|
39
|
+
if (preparation.inspection) {
|
|
40
|
+
const enforcement = await helperIsolation.inspect(provider, preparation.inspection);
|
|
41
|
+
return preparation.prepared(enforcement);
|
|
42
|
+
}
|
|
43
|
+
const config = preparation.projectHooks
|
|
44
|
+
? await codexAppServerProjectHookTrustConfig(provider, preparation.workdir)
|
|
45
|
+
: null;
|
|
46
|
+
return preparation.settings(config);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Creating, starting, steering and waiting for turns on prepared native conversation threads. The conversation
|
|
51
|
+
* registry and its observation belong to the conversation commands, which pass them in.
|
|
52
|
+
* @param {object} dependencies
|
|
53
|
+
* @param {import("./codexConversations.js").CodexConversationRegistry} dependencies.codexAppServerConversations
|
|
54
|
+
* @param {import("./codexConversations.js").CodexConversationLookup} dependencies.codexAppServerConversation
|
|
55
|
+
* @param {import("./codexConversations.js").CodexConversationObserver} dependencies.observeCodexConversation
|
|
56
|
+
* @param {import("./codexConversations.js").CodexConversationStateUpdate} dependencies.holdWhileActive
|
|
57
|
+
* @param {import("./codexTurn.js").CodexSessionNamespace} dependencies.namespace
|
|
58
|
+
* @param {string} dependencies.errorPrefix
|
|
59
|
+
* @param {string} dependencies.helperOwnershipError
|
|
60
|
+
* @param {string} dependencies.steerFailedCode
|
|
61
|
+
* @param {string} dependencies.interruptFailedCode
|
|
62
|
+
*/
|
|
63
|
+
export function createCodexConversationTurns({
|
|
64
|
+
codexAppServerConversations,
|
|
65
|
+
codexAppServerConversation,
|
|
66
|
+
observeCodexConversation,
|
|
67
|
+
holdWhileActive,
|
|
68
|
+
namespace,
|
|
69
|
+
errorPrefix,
|
|
70
|
+
helperOwnershipError,
|
|
71
|
+
steerFailedCode,
|
|
72
|
+
interruptFailedCode
|
|
73
|
+
}) {
|
|
74
|
+
async function createPreparedCodexAppServerConversation(sessionId, input, {
|
|
75
|
+
provider,
|
|
76
|
+
executionProfile,
|
|
77
|
+
helperIsolation,
|
|
78
|
+
threadPreparation
|
|
79
|
+
}) {
|
|
80
|
+
const prepareThread = () => prepareCodexAppServerConversationThread(provider, threadPreparation(), helperIsolation);
|
|
81
|
+
const thread = executionProfile
|
|
82
|
+
? (await helperIsolation.start(provider, prepareThread)).thread
|
|
83
|
+
: await provider.startThread({
|
|
84
|
+
...await prepareThread(),
|
|
85
|
+
...(input.ephemeral === true ? { ephemeral: true } : {})
|
|
86
|
+
});
|
|
87
|
+
const conversationId = normalizeText(thread.id || thread.response?.thread?.id);
|
|
88
|
+
if (!conversationId) {
|
|
89
|
+
throw new Error("Codex app-server did not return a conversation id.");
|
|
90
|
+
}
|
|
91
|
+
if (input.persistent === true) observeCodexConversation(sessionId, conversationId, provider);
|
|
92
|
+
if (input.ephemeral === true) {
|
|
93
|
+
const sessionKey = namespace(sessionId);
|
|
94
|
+
const conversations = codexAppServerConversations.get(sessionKey) || new Map();
|
|
95
|
+
conversations.set(conversationId, {
|
|
96
|
+
conversationId,
|
|
97
|
+
executionProfile,
|
|
98
|
+
provider,
|
|
99
|
+
error: "",
|
|
100
|
+
message: "",
|
|
101
|
+
messageId: "",
|
|
102
|
+
nextProgressSequence: 0,
|
|
103
|
+
outcome: null,
|
|
104
|
+
progressUpdates: [],
|
|
105
|
+
rawText: "",
|
|
106
|
+
runId: "",
|
|
107
|
+
status: "ready",
|
|
108
|
+
turnMetadata: null,
|
|
109
|
+
watcher: null
|
|
110
|
+
});
|
|
111
|
+
codexAppServerConversations.set(sessionKey, conversations);
|
|
112
|
+
}
|
|
113
|
+
return {
|
|
114
|
+
conversationId,
|
|
115
|
+
ok: true,
|
|
116
|
+
status: "ready"
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
async function steerCodexAppServerConversationTurn(input, {
|
|
121
|
+
conversationId,
|
|
122
|
+
conversationState,
|
|
123
|
+
messageId,
|
|
124
|
+
prompt,
|
|
125
|
+
provider
|
|
126
|
+
}) {
|
|
127
|
+
const images = codexLocalImageInput(input.attachments || []);
|
|
128
|
+
const result = await provider.steerTurn(
|
|
129
|
+
conversationId,
|
|
130
|
+
conversationState.runId,
|
|
131
|
+
images.length ? [prompt, ...images] : prompt,
|
|
132
|
+
{ clientUserMessageId: messageId }
|
|
133
|
+
);
|
|
134
|
+
const failure = codexAppServerSteerFailure(result, steerFailedCode);
|
|
135
|
+
if (failure) return { ...failure, ok: false };
|
|
136
|
+
conversationState.messageId = messageId;
|
|
137
|
+
return {
|
|
138
|
+
conversationId,
|
|
139
|
+
messageId,
|
|
140
|
+
ok: true,
|
|
141
|
+
runId: conversationState.runId,
|
|
142
|
+
status: "inProgress",
|
|
143
|
+
deliveryMode: "steer"
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
async function startPreparedCodexAppServerConversationTurn(sessionId, input, {
|
|
148
|
+
conversationId,
|
|
149
|
+
messageId,
|
|
150
|
+
prompt,
|
|
151
|
+
provider,
|
|
152
|
+
conversationState,
|
|
153
|
+
executionProfile,
|
|
154
|
+
actorMetadata,
|
|
155
|
+
onEvent,
|
|
156
|
+
projectResult,
|
|
157
|
+
helperIsolation,
|
|
158
|
+
threadPreparation,
|
|
159
|
+
prepareTurn,
|
|
160
|
+
authorized,
|
|
161
|
+
readOnly
|
|
162
|
+
}) {
|
|
163
|
+
if (conversationState && messageId && conversationState.messageId === messageId) {
|
|
164
|
+
return codexAppServerEphemeralConversationSnapshot(conversationState);
|
|
165
|
+
}
|
|
166
|
+
if (conversationState && codexAppServerConversationTurnIsActive(conversationState.status)) {
|
|
167
|
+
if (input.steer === true) {
|
|
168
|
+
return steerCodexAppServerConversationTurn(input, {
|
|
169
|
+
conversationId,
|
|
170
|
+
conversationState,
|
|
171
|
+
messageId,
|
|
172
|
+
prompt,
|
|
173
|
+
provider
|
|
174
|
+
});
|
|
175
|
+
}
|
|
176
|
+
return {
|
|
177
|
+
code: `${errorPrefix}temporary_conversation_turn_active`,
|
|
178
|
+
error: "Temporary AI is already working on this conversation.",
|
|
179
|
+
messageCode: "assistant.codex.temporaryConversationBusy",
|
|
180
|
+
messageParams: {},
|
|
181
|
+
ok: false
|
|
182
|
+
};
|
|
183
|
+
}
|
|
184
|
+
if (!conversationState || input.persistent === true) {
|
|
185
|
+
const prepareThread = () => prepareCodexAppServerConversationThread(provider, threadPreparation(), helperIsolation);
|
|
186
|
+
if (executionProfile) await helperIsolation.resume(provider, conversationId, prepareThread);
|
|
187
|
+
else await provider.resumeThread(conversationId, await prepareThread());
|
|
188
|
+
}
|
|
189
|
+
let admittedAccountIdentitySignature = "";
|
|
190
|
+
if (executionProfile) {
|
|
191
|
+
admittedAccountIdentitySignature = await readCodexAppServerAccountIdentity(provider, helperOwnershipError);
|
|
192
|
+
}
|
|
193
|
+
let watcher = null;
|
|
194
|
+
let waitForResult = null;
|
|
195
|
+
if (conversationState && !input.persistent) {
|
|
196
|
+
Object.assign(conversationState, {
|
|
197
|
+
error: "",
|
|
198
|
+
message: "",
|
|
199
|
+
messageId,
|
|
200
|
+
outcome: null,
|
|
201
|
+
progressUpdates: [],
|
|
202
|
+
rawText: "",
|
|
203
|
+
runId: "",
|
|
204
|
+
status: "starting",
|
|
205
|
+
turnMetadata: actorMetadata
|
|
206
|
+
});
|
|
207
|
+
watcher = createCodexAppServerDetachedTurnWatcher(provider, conversationId, {
|
|
208
|
+
includeThreadHistory: false,
|
|
209
|
+
timeoutMs: executionProfile?.limits.timeoutMs || 0,
|
|
210
|
+
onEvent(classification = {}) {
|
|
211
|
+
const current = codexAppServerConversation(sessionId, conversationId);
|
|
212
|
+
if (!current || (classification.turnId && current.runId && classification.turnId !== current.runId)) {
|
|
213
|
+
return;
|
|
214
|
+
}
|
|
215
|
+
onEvent(classification, current);
|
|
216
|
+
}
|
|
217
|
+
});
|
|
218
|
+
waitForResult = watcher.wait();
|
|
219
|
+
void waitForResult.catch(() => null);
|
|
220
|
+
conversationState.watcher = watcher;
|
|
221
|
+
}
|
|
222
|
+
let delivery = null;
|
|
223
|
+
if (input.persistent && conversationState) Object.assign(conversationState, { onEvent, turnOutcome: "" });
|
|
224
|
+
try {
|
|
225
|
+
const { onPromptSending = notifyNoConversationPromptSending } = input;
|
|
226
|
+
await onPromptSending({ threadId: conversationId });
|
|
227
|
+
if (executionProfile) {
|
|
228
|
+
const prepared = prepareTurn();
|
|
229
|
+
delivery = await sendPreparedCodexAppServerHelperTurn(provider, prepared, helperIsolation);
|
|
230
|
+
} else {
|
|
231
|
+
delivery = await sendCodexAppServerPrompt({
|
|
232
|
+
clientUserMessageId: input.messageId,
|
|
233
|
+
outputSchema: input.outputSchema,
|
|
234
|
+
prompt,
|
|
235
|
+
attachments: input.attachments,
|
|
236
|
+
provider,
|
|
237
|
+
readOnly,
|
|
238
|
+
threadId: conversationId
|
|
239
|
+
}, authorized);
|
|
240
|
+
}
|
|
241
|
+
} catch (error) {
|
|
242
|
+
if (input.persistent && conversationState) conversationState.onEvent = ignoreCodexConversationEvent;
|
|
243
|
+
watcher?.failNow(error);
|
|
244
|
+
await waitForResult?.catch(() => null);
|
|
245
|
+
if (conversationState) {
|
|
246
|
+
Object.assign(conversationState, {
|
|
247
|
+
error: codexAppServerErrorMessage(error, "Temporary AI message could not be sent."),
|
|
248
|
+
status: "failed",
|
|
249
|
+
watcher: null
|
|
250
|
+
});
|
|
251
|
+
holdWhileActive(conversationState);
|
|
252
|
+
}
|
|
253
|
+
throw error;
|
|
254
|
+
}
|
|
255
|
+
const { turnId: runId, status } = codexAppServerDeliveredTurn(delivery);
|
|
256
|
+
if (!runId) {
|
|
257
|
+
watcher?.failNow(new Error("Codex app-server accepted a conversation turn without returning its id."));
|
|
258
|
+
await waitForResult?.catch(() => null);
|
|
259
|
+
throw new Error("Codex app-server accepted a conversation turn without returning its id.");
|
|
260
|
+
}
|
|
261
|
+
if (conversationState && !input.persistent) {
|
|
262
|
+
let nativeCompleted = false;
|
|
263
|
+
Object.assign(conversationState, {
|
|
264
|
+
runId,
|
|
265
|
+
status: !executionProfile && codexAppServerTurnStatusIsSuccessfulComplete(status) ? status : "inProgress"
|
|
266
|
+
});
|
|
267
|
+
watcher.setTurnId(runId);
|
|
268
|
+
if (codexAppServerTurnStatusIsProviderFailure(status)) {
|
|
269
|
+
watcher.failNow(new Error(`Codex app-server turn ${status}.`));
|
|
270
|
+
} else if (codexAppServerTurnStatusIsSuccessfulComplete(status)) {
|
|
271
|
+
await watcher.completeNow(status);
|
|
272
|
+
}
|
|
273
|
+
conversationState.completion = waitForResult.then(async (result = {}) => {
|
|
274
|
+
const current = codexAppServerConversation(sessionId, conversationId);
|
|
275
|
+
if (!current || current.runId !== runId) {
|
|
276
|
+
return;
|
|
277
|
+
}
|
|
278
|
+
nativeCompleted = true;
|
|
279
|
+
if (!executionProfile) current.status = result.status || "completed";
|
|
280
|
+
if (executionProfile) {
|
|
281
|
+
const completingRunId = current.runId;
|
|
282
|
+
await assertCodexAppServerHelperAccountIdentity(provider, admittedAccountIdentitySignature, helperOwnershipError);
|
|
283
|
+
if (codexAppServerConversation(sessionId, conversationId) !== current ||
|
|
284
|
+
current.runId !== completingRunId || !codexAppServerConversationTurnIsActive(current.status)) {
|
|
285
|
+
throw new Error("The scoped helper turn is unavailable.");
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
const response = projectResult(result);
|
|
289
|
+
Object.assign(current, {
|
|
290
|
+
error: "",
|
|
291
|
+
...response,
|
|
292
|
+
status: result.status || "completed",
|
|
293
|
+
watcher: null
|
|
294
|
+
});
|
|
295
|
+
return codexAppServerEphemeralConversationSnapshot(current);
|
|
296
|
+
}).catch(async (error) => {
|
|
297
|
+
const current = codexAppServerConversation(sessionId, conversationId);
|
|
298
|
+
if (!current || current.runId !== runId || current.status === "interrupted") {
|
|
299
|
+
throw error;
|
|
300
|
+
}
|
|
301
|
+
if (executionProfile && !nativeCompleted && codexAppServerConversationTurnIsActive(current.status)) {
|
|
302
|
+
try {
|
|
303
|
+
const interrupted = await provider.interruptTurn(conversationId, runId);
|
|
304
|
+
const failure = codexAppServerInterruptFailure(interrupted, interruptFailedCode);
|
|
305
|
+
if (failure) throw new Error(failure.error);
|
|
306
|
+
} catch {
|
|
307
|
+
current.error = "The helper deadline ended, but Stop could not be confirmed. Retry Stop before reusing this helper.";
|
|
308
|
+
current.watcher = null;
|
|
309
|
+
throw new Error(current.error);
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
Object.assign(current, {
|
|
313
|
+
error: codexAppServerErrorMessage(error, "Temporary AI turn failed."),
|
|
314
|
+
status: "failed",
|
|
315
|
+
watcher: null
|
|
316
|
+
});
|
|
317
|
+
throw error;
|
|
318
|
+
});
|
|
319
|
+
void conversationState.completion.catch(() => null);
|
|
320
|
+
}
|
|
321
|
+
if (input.persistent && conversationState) {
|
|
322
|
+
Object.assign(conversationState, { runId, status, messageId });
|
|
323
|
+
holdWhileActive(conversationState);
|
|
324
|
+
}
|
|
325
|
+
return { conversationId, messageId, ok: true, runId, status };
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
async function waitForPreparedCodexAppServerConversationTurn(sessionId, input, {
|
|
329
|
+
provider,
|
|
330
|
+
onEvent
|
|
331
|
+
}) {
|
|
332
|
+
const conversationId = normalizeText(input.conversationId);
|
|
333
|
+
const runId = normalizeText(input.runId);
|
|
334
|
+
const watcher = createCodexAppServerDetachedTurnWatcher(provider, conversationId, {
|
|
335
|
+
onEvent,
|
|
336
|
+
timeoutMs: Number(input.timeoutMs || 0) > 0
|
|
337
|
+
? Number(input.timeoutMs)
|
|
338
|
+
: input.persistent === true ? 0 : CODEX_APP_SERVER_DETACHED_TURN_TIMEOUT_MS
|
|
339
|
+
});
|
|
340
|
+
const conversationState = codexAppServerConversation(sessionId, conversationId);
|
|
341
|
+
if (input.persistent && conversationState) conversationState.watcher = watcher;
|
|
342
|
+
const waitForResult = watcher.wait();
|
|
343
|
+
void waitForResult.catch(() => {});
|
|
344
|
+
watcher.setTurnId(runId);
|
|
345
|
+
try {
|
|
346
|
+
const current = await provider.readThread(conversationId);
|
|
347
|
+
const status = codexAppServerThreadStatus(current);
|
|
348
|
+
if (codexAppServerTurnStatusIsProviderFailure(status)) {
|
|
349
|
+
watcher.failNow(new Error(
|
|
350
|
+
codexAppServerThreadError(current) || `Codex app-server turn ${status}.`
|
|
351
|
+
));
|
|
352
|
+
} else if (codexAppServerTurnStatusIsSuccessfulComplete(status)) {
|
|
353
|
+
await watcher.completeNow(status);
|
|
354
|
+
}
|
|
355
|
+
const result = await waitForResult;
|
|
356
|
+
return {
|
|
357
|
+
conversationId,
|
|
358
|
+
ok: true,
|
|
359
|
+
runId,
|
|
360
|
+
status: result.status || status || "completed",
|
|
361
|
+
rawText: result.text
|
|
362
|
+
};
|
|
363
|
+
} catch (error) {
|
|
364
|
+
watcher.failNow(error);
|
|
365
|
+
throw error;
|
|
366
|
+
} finally {
|
|
367
|
+
if (conversationState?.watcher === watcher) conversationState.watcher = null;
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
return Object.freeze({
|
|
372
|
+
createPreparedCodexAppServerConversation,
|
|
373
|
+
startPreparedCodexAppServerConversationTurn,
|
|
374
|
+
waitForPreparedCodexAppServerConversationTurn
|
|
375
|
+
});
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
/** @typedef {ReturnType<typeof createCodexConversationTurns>} CodexConversationTurns */
|