@jskit-ai/assistant-core 0.2.7 → 0.2.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/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,348 @@
|
|
|
1
|
+
import { CODEX_APP_SERVER_ACCOUNT_ID_MAX_LENGTH, codexAuthOutputRequiresReconnect, createCodexAccountReader } from "./codexAccountReader.js";
|
|
2
|
+
import { assertCodexAuthPreflightReady } from "./codexAuthPreflight.js";
|
|
3
|
+
import { normalizeNullableText as normalizeAgentText } from "./normalize.js";
|
|
4
|
+
import { tailTextFile } from "./codexProcess.js";
|
|
5
|
+
|
|
6
|
+
/** @typedef {import("./codexProvider.js").CodexAppServerAgentProvider} CodexAppServerAgentProvider */
|
|
7
|
+
|
|
8
|
+
export const codexAppServerHelperAuthError = createCodexAccountReader().error;
|
|
9
|
+
|
|
10
|
+
function codexAppServerHelperLoginParams(auth = {}, errorPrefix = "") {
|
|
11
|
+
if (auth.authMode === "chatgpt") {
|
|
12
|
+
return {
|
|
13
|
+
accessToken: auth.accessToken,
|
|
14
|
+
chatgptAccountId: auth.accountId,
|
|
15
|
+
chatgptPlanType: auth.planType || null,
|
|
16
|
+
type: "chatgptAuthTokens"
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
if (auth.authMode === "apiKey") {
|
|
20
|
+
return {
|
|
21
|
+
apiKey: auth.apiKey,
|
|
22
|
+
type: "apiKey"
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
throw codexAppServerHelperAuthError(
|
|
26
|
+
`${errorPrefix}codex_helper_auth_invalid`,
|
|
27
|
+
"The selected Codex authentication mode is unsupported. Reconnect Codex and retry."
|
|
28
|
+
);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function codexAppServerHelperLoginResponseType(auth = {}) {
|
|
32
|
+
return auth.authMode === "chatgpt" ? "chatgptAuthTokens" : "apiKey";
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function codexAppServerHelperAccountType(auth = {}) {
|
|
36
|
+
return auth.authMode === "chatgpt" ? "chatgpt" : "apiKey";
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// Without an application preparing external sign-in, a provider uses Codex's native sign-in.
|
|
40
|
+
function prepareNativeAuth() {
|
|
41
|
+
return "native";
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
function codexPlanUsage(limits) {
|
|
45
|
+
if (limits?.limitId && limits.limitId !== "codex") return { status: "unavailable", windows: [], checkedAt: Date.now() };
|
|
46
|
+
const windows = ["primary", "secondary"].flatMap((id) => {
|
|
47
|
+
const value = limits?.[id];
|
|
48
|
+
if (typeof value?.usedPercent !== "number" || !Number.isFinite(value.usedPercent) || value.usedPercent < 0) return [];
|
|
49
|
+
return [{
|
|
50
|
+
id,
|
|
51
|
+
remainingPercent: Math.max(0, 100 - Math.min(100, value.usedPercent)),
|
|
52
|
+
windowDurationMins: Number.isInteger(value.windowDurationMins) && value.windowDurationMins > 0 ? value.windowDurationMins : null,
|
|
53
|
+
resetsAt: Number.isSafeInteger(value.resetsAt) && value.resetsAt > 0 ? value.resetsAt : null
|
|
54
|
+
}];
|
|
55
|
+
});
|
|
56
|
+
return { status: windows.length ? "available" : "unavailable", windows, checkedAt: Date.now() };
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export function codexAppServerHelperRequestError(error = null, reason = "", errorPrefix = "") {
|
|
60
|
+
if (
|
|
61
|
+
error?.name === "AbortError" ||
|
|
62
|
+
error?.code === "ABORT_ERR" ||
|
|
63
|
+
(typeof error?.code === "string" && error.code.startsWith(`${errorPrefix}codex_helper_`)) ||
|
|
64
|
+
error?.code === `${errorPrefix}codex_model_catalog_invalid`
|
|
65
|
+
) {
|
|
66
|
+
return error;
|
|
67
|
+
}
|
|
68
|
+
const failure = new Error("Codex isolated helper execution failed. Retry the task.");
|
|
69
|
+
failure.code = `${errorPrefix}codex_helper_provider_request_failed`;
|
|
70
|
+
const providerCode = Number(error?.code);
|
|
71
|
+
if (Number.isSafeInteger(providerCode)) {
|
|
72
|
+
failure.providerCode = providerCode;
|
|
73
|
+
}
|
|
74
|
+
const normalizedReason = normalizeAgentText(reason);
|
|
75
|
+
if (normalizedReason && normalizedReason.length <= 128) {
|
|
76
|
+
failure.operation = normalizedReason;
|
|
77
|
+
}
|
|
78
|
+
return failure;
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* The provider's authentication: the helper account it signs its isolated runtime into, the runtime's
|
|
82
|
+
* sign-in checks, and the account's plan usage.
|
|
83
|
+
* @param {object} dependencies
|
|
84
|
+
* @param {CodexAppServerAgentProvider} dependencies.provider
|
|
85
|
+
*/
|
|
86
|
+
export function createCodexProviderAuth({ provider }) {
|
|
87
|
+
// The helper account signed into this provider's isolated runtime, and whether helper work is refused.
|
|
88
|
+
let helperAuth = null;
|
|
89
|
+
let helperAuthBlocked = false;
|
|
90
|
+
let planUsage = null;
|
|
91
|
+
let planUsagePending = null;
|
|
92
|
+
// Counts account changes, so a plan-usage read that started before one is discarded.
|
|
93
|
+
let planUsageAuthGeneration = 0;
|
|
94
|
+
|
|
95
|
+
async function selectedHelperAuth() {
|
|
96
|
+
if (!provider.isHelperProvider()) {
|
|
97
|
+
return null;
|
|
98
|
+
}
|
|
99
|
+
if (provider.host.parameters.providerHome) {
|
|
100
|
+
return { identitySignature: await provider.credentials.identity(provider.host.parameters) };
|
|
101
|
+
}
|
|
102
|
+
return provider.accountReader.readSelected(provider.options);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
async function assertHelperAccountIdentityCurrent() {
|
|
106
|
+
if (!provider.isHelperProvider() || !helperAuth) {
|
|
107
|
+
return;
|
|
108
|
+
}
|
|
109
|
+
if (helperAuthBlocked) {
|
|
110
|
+
throw provider.accountReader.error(
|
|
111
|
+
`${provider.errorPrefix}codex_helper_auth_changed`,
|
|
112
|
+
"The selected Codex account changed during helper work. Retry the task with the current account."
|
|
113
|
+
);
|
|
114
|
+
}
|
|
115
|
+
const current = await selectedHelperAuth();
|
|
116
|
+
if (current.identitySignature !== helperAuth.identitySignature) {
|
|
117
|
+
helperAuthBlocked = true;
|
|
118
|
+
throw provider.accountReader.error(
|
|
119
|
+
`${provider.errorPrefix}codex_helper_auth_changed`,
|
|
120
|
+
"The selected Codex account changed during helper work. Retry the task with the current account."
|
|
121
|
+
);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
async function authenticateHelperClient(client, runtime = {}) {
|
|
126
|
+
if (!provider.isHelperProvider()) {
|
|
127
|
+
return null;
|
|
128
|
+
}
|
|
129
|
+
const auth = await selectedHelperAuth();
|
|
130
|
+
if (
|
|
131
|
+
!runtime.accountIdentitySignature ||
|
|
132
|
+
auth.identitySignature !== runtime.accountIdentitySignature
|
|
133
|
+
) {
|
|
134
|
+
throw provider.accountReader.error(
|
|
135
|
+
`${provider.errorPrefix}codex_helper_auth_changed`,
|
|
136
|
+
"The selected Codex account changed while helper execution was starting. Retry the task."
|
|
137
|
+
);
|
|
138
|
+
}
|
|
139
|
+
helperAuth = auth;
|
|
140
|
+
helperAuthBlocked = false;
|
|
141
|
+
if (provider.host.parameters.providerHome) return auth;
|
|
142
|
+
try {
|
|
143
|
+
const login = await client.request(
|
|
144
|
+
"account/login/start",
|
|
145
|
+
codexAppServerHelperLoginParams(auth, provider.errorPrefix)
|
|
146
|
+
);
|
|
147
|
+
if (normalizeAgentText(login?.type) !== codexAppServerHelperLoginResponseType(auth)) {
|
|
148
|
+
throw new Error("invalid login response");
|
|
149
|
+
}
|
|
150
|
+
const account = await client.request("account/read", {
|
|
151
|
+
refreshToken: false
|
|
152
|
+
});
|
|
153
|
+
if (
|
|
154
|
+
account?.requiresOpenaiAuth !== true ||
|
|
155
|
+
normalizeAgentText(account?.account?.type) !== codexAppServerHelperAccountType(auth)
|
|
156
|
+
) {
|
|
157
|
+
throw new Error("invalid account response");
|
|
158
|
+
}
|
|
159
|
+
return auth;
|
|
160
|
+
} catch {
|
|
161
|
+
helperAuth = null;
|
|
162
|
+
helperAuthBlocked = true;
|
|
163
|
+
throw provider.accountReader.error(
|
|
164
|
+
`${provider.errorPrefix}codex_helper_auth_unavailable`,
|
|
165
|
+
"Codex could not activate the selected account for isolated helper work. Reconnect Codex and retry."
|
|
166
|
+
);
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
async function refreshHelperChatgptAuth(params = {}) {
|
|
171
|
+
const currentAuth = helperAuth;
|
|
172
|
+
const previousAccountId = params.previousAccountId;
|
|
173
|
+
if (
|
|
174
|
+
!provider.isHelperProvider() ||
|
|
175
|
+
currentAuth?.authMode !== "chatgpt" ||
|
|
176
|
+
params.reason !== "unauthorized" ||
|
|
177
|
+
typeof previousAccountId !== "string" ||
|
|
178
|
+
previousAccountId.length === 0 ||
|
|
179
|
+
previousAccountId.length > CODEX_APP_SERVER_ACCOUNT_ID_MAX_LENGTH ||
|
|
180
|
+
previousAccountId !== currentAuth.accountId
|
|
181
|
+
) {
|
|
182
|
+
helperAuthBlocked = true;
|
|
183
|
+
throw provider.accountReader.error(
|
|
184
|
+
`${provider.errorPrefix}codex_helper_auth_refresh_rejected`,
|
|
185
|
+
"Codex helper authentication refresh was rejected. Reconnect Codex and retry."
|
|
186
|
+
);
|
|
187
|
+
}
|
|
188
|
+
const refreshed = await selectedHelperAuth();
|
|
189
|
+
if (
|
|
190
|
+
refreshed.authMode !== "chatgpt" ||
|
|
191
|
+
refreshed.identitySignature !== currentAuth.identitySignature
|
|
192
|
+
) {
|
|
193
|
+
helperAuthBlocked = true;
|
|
194
|
+
throw provider.accountReader.error(
|
|
195
|
+
`${provider.errorPrefix}codex_helper_auth_changed`,
|
|
196
|
+
"The selected Codex account changed during helper work. Retry the task with the current account."
|
|
197
|
+
);
|
|
198
|
+
}
|
|
199
|
+
if (refreshed.secretSignature === currentAuth.secretSignature) {
|
|
200
|
+
helperAuthBlocked = true;
|
|
201
|
+
throw provider.accountReader.error(
|
|
202
|
+
`${provider.errorPrefix}codex_helper_auth_refresh_pending`,
|
|
203
|
+
"The selected Codex account has not produced a newer access token yet. Reconnect Codex and retry."
|
|
204
|
+
);
|
|
205
|
+
}
|
|
206
|
+
helperAuth = refreshed;
|
|
207
|
+
return {
|
|
208
|
+
accessToken: refreshed.accessToken,
|
|
209
|
+
chatgptAccountId: refreshed.accountId,
|
|
210
|
+
chatgptPlanType: refreshed.planType || null
|
|
211
|
+
};
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
async function preflightAuth(reason = "codex-auth-preflight", modelProviderId = "") {
|
|
215
|
+
const { prepareAuth = prepareNativeAuth } = provider.options;
|
|
216
|
+
if (await prepareAuth(modelProviderId) === "external") {
|
|
217
|
+
await provider.assertRuntimeAuthReady(reason);
|
|
218
|
+
return;
|
|
219
|
+
}
|
|
220
|
+
if (provider.options.modelProviderId && provider.options.modelProviderId !== "openai") {
|
|
221
|
+
await provider.credentials.assertCurrent("");
|
|
222
|
+
return;
|
|
223
|
+
}
|
|
224
|
+
await provider.assertRuntimeAuthReady(reason);
|
|
225
|
+
try {
|
|
226
|
+
return await assertCodexAuthPreflightReady({
|
|
227
|
+
...provider.options, codexCommand: provider.host.parameters.codexCommand, env: provider.host.parameters.env
|
|
228
|
+
}, {
|
|
229
|
+
execution: provider.host.execution, credentials: provider.credentials, reason
|
|
230
|
+
});
|
|
231
|
+
} catch (error) {
|
|
232
|
+
if (error?.code === provider.credentials.reconnectRequiredCode && provider.runtime?.runtimeDir) {
|
|
233
|
+
await provider.stopRuntimeAndRequireDrain(reason);
|
|
234
|
+
}
|
|
235
|
+
throw error;
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
async function assertRuntimeAuthReady(reason = "codex-app-server") {
|
|
240
|
+
if (provider.isHelperProvider() || provider.stale) {
|
|
241
|
+
return;
|
|
242
|
+
}
|
|
243
|
+
const runtime = provider.runtime || {};
|
|
244
|
+
let generationError = null;
|
|
245
|
+
try {
|
|
246
|
+
await provider.credentials.assertCurrent(runtime.authStateSignature);
|
|
247
|
+
} catch (error) {
|
|
248
|
+
generationError = error;
|
|
249
|
+
}
|
|
250
|
+
const logTail = await tailTextFile(runtime.logPath || "");
|
|
251
|
+
const reconnectRequired = codexAuthOutputRequiresReconnect(logTail);
|
|
252
|
+
if (!generationError && !reconnectRequired) {
|
|
253
|
+
return;
|
|
254
|
+
}
|
|
255
|
+
await provider.stopRuntimeAndRequireDrain(reason);
|
|
256
|
+
if (reconnectRequired) {
|
|
257
|
+
await provider.markReconnectRequired({
|
|
258
|
+
toolHomeSource: runtime.toolHomeSource || provider.options.toolHomeSource,
|
|
259
|
+
observed: logTail,
|
|
260
|
+
reason
|
|
261
|
+
});
|
|
262
|
+
throw provider.credentials.reconnectError({
|
|
263
|
+
observed: logTail
|
|
264
|
+
});
|
|
265
|
+
}
|
|
266
|
+
throw generationError;
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
async function markReconnectRequired({ reason = "codex-app-server", observed = "", toolHomeSource } = {}) {
|
|
270
|
+
await provider.credentials.markInvalid({ reason, toolHomeSource });
|
|
271
|
+
throw provider.credentials.reconnectError({ modelProviderId: provider.options.modelProviderId, observed });
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
async function readPlanUsage() {
|
|
275
|
+
const client = provider.client;
|
|
276
|
+
if (!client?.isOpen()) return { status: "unavailable", windows: [] };
|
|
277
|
+
if (planUsage && Date.now() - planUsage.checkedAt < 60_000) return planUsage;
|
|
278
|
+
if (planUsagePending) return planUsagePending;
|
|
279
|
+
const previous = planUsage;
|
|
280
|
+
const authGeneration = planUsageAuthGeneration;
|
|
281
|
+
const signal = AbortSignal.timeout(10_000);
|
|
282
|
+
const operation = (async () => {
|
|
283
|
+
try {
|
|
284
|
+
const account = await client.request("account/read", { refreshToken: false }, { signal });
|
|
285
|
+
if (provider.client !== client || planUsageAuthGeneration !== authGeneration) return { status: "unavailable", windows: [] };
|
|
286
|
+
if (account?.account?.type !== "chatgpt") {
|
|
287
|
+
planUsage = { status: "unsupported", windows: [], checkedAt: Date.now() };
|
|
288
|
+
} else {
|
|
289
|
+
const result = await client.request("account/rateLimits/read", {}, { signal });
|
|
290
|
+
if (provider.client !== client || planUsageAuthGeneration !== authGeneration) return { status: "unavailable", windows: [] };
|
|
291
|
+
// A live event received during the read is newer than this request.
|
|
292
|
+
if (planUsage === previous) planUsage = codexPlanUsage(result.rateLimitsByLimitId?.codex || result.rateLimits);
|
|
293
|
+
}
|
|
294
|
+
return planUsage;
|
|
295
|
+
} catch {
|
|
296
|
+
return { status: "unavailable", windows: [] };
|
|
297
|
+
}
|
|
298
|
+
})();
|
|
299
|
+
planUsagePending = operation;
|
|
300
|
+
try { return await operation; }
|
|
301
|
+
finally { if (planUsagePending === operation) planUsagePending = null; }
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
// A new connection reads the account's plan usage afresh.
|
|
305
|
+
function resetPlanUsage() {
|
|
306
|
+
planUsage = null;
|
|
307
|
+
planUsagePending = null;
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
// Account notifications change the plan usage the provider reports.
|
|
311
|
+
function observeAccountNotification(notification) {
|
|
312
|
+
if (notification.method === "account/updated") {
|
|
313
|
+
planUsage = null;
|
|
314
|
+
planUsageAuthGeneration += 1;
|
|
315
|
+
}
|
|
316
|
+
if (notification.method === "account/rateLimits/updated") {
|
|
317
|
+
const limits = notification.params?.rateLimits;
|
|
318
|
+
if (!limits?.limitId || limits.limitId === "codex") planUsage = codexPlanUsage(limits);
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
// A helper runtime that failed to start refuses helper work until it signs in again.
|
|
323
|
+
function blockHelper() {
|
|
324
|
+
helperAuth = null;
|
|
325
|
+
helperAuthBlocked = true;
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
// A closed provider keeps no helper account.
|
|
329
|
+
function forgetHelper() {
|
|
330
|
+
helperAuth = null;
|
|
331
|
+
helperAuthBlocked = false;
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
return Object.freeze({
|
|
335
|
+
selectedHelperAuth,
|
|
336
|
+
assertHelperAccountIdentityCurrent,
|
|
337
|
+
authenticateHelperClient,
|
|
338
|
+
refreshHelperChatgptAuth,
|
|
339
|
+
preflightAuth,
|
|
340
|
+
assertRuntimeAuthReady,
|
|
341
|
+
markReconnectRequired,
|
|
342
|
+
readPlanUsage,
|
|
343
|
+
resetPlanUsage,
|
|
344
|
+
observeAccountNotification,
|
|
345
|
+
blockHelper,
|
|
346
|
+
forgetHelper
|
|
347
|
+
});
|
|
348
|
+
}
|