@openclaw/codex 2026.9.5 → 2026.9.7
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/README.md +2 -0
- package/assets/icon.png +0 -0
- package/dist/.setup/{account-usage-runtime-C2MOIvfq.mjs → account-usage-runtime-DFhbh1zz.mjs} +6 -6
- package/dist/.setup/{apply-CJ0ZfmBG.mjs → apply-D3GcSoSa.mjs} +35 -55
- package/dist/.setup/{attempt-client-cleanup-BpYKdTA0.mjs → attempt-client-cleanup-DOP-cW5j.mjs} +179 -73
- package/dist/.setup/attempt-workspace-context-C5HigshI.mjs +164 -0
- package/dist/.setup/{auth-binding-DhLWa_7K.mjs → auth-binding-BLWz7stm.mjs} +14 -1
- package/dist/.setup/{auth-cache-key-QirmgiCo.mjs → auth-cache-key-Dbvq-QgB.mjs} +41 -111
- package/dist/.setup/{auth-profile-WqZtZfXN.mjs → auth-profile-B0okYl2D.mjs} +1 -2
- package/dist/.setup/auth-profile-health-oHizqgye.mjs +53 -0
- package/dist/.setup/auth-profile-recovery-BREezV0L.mjs +14 -0
- package/dist/.setup/auth-start-options-BPIPeEX8.mjs +44 -0
- package/dist/.setup/{binding-connection-Bm38niE8.mjs → binding-connection-DTtN1KrX.mjs} +2 -2
- package/dist/.setup/{binding-connection.runtime-CnRMC0ta.mjs → binding-connection.runtime-6TpgD1M6.mjs} +5 -5
- package/dist/.setup/{bounded-turn-BtlZcivC.mjs → bounded-turn-CbjoN2OW.mjs} +140 -37
- package/dist/.setup/bounded-turn-isolation-B8K_ylqk.mjs +14 -0
- package/dist/.setup/{build-state-Xx9ybZqa.mjs → build-state-Da1_z0kd.mjs} +1 -1
- package/dist/.setup/{capabilities-_vXcZGSx.mjs → capabilities-B3WEZl4e.mjs} +2 -10
- package/dist/.setup/{client-vXs2929Q.mjs → client-N0JpgSzF.mjs} +635 -872
- package/dist/.setup/client-catalog-response-5HHLdcde.mjs +285 -0
- package/dist/.setup/{command-dispatch-naHIZwwF.mjs → command-dispatch-BeAoaovI.mjs} +9 -8
- package/dist/.setup/{command-formatters-CGEkdawF.mjs → command-formatters-R3ckE3Co.mjs} +36 -64
- package/dist/.setup/{command-handlers-BtAJEW1X.mjs → command-handlers-ylTMS00z.mjs} +301 -488
- package/dist/.setup/{command-rpc-DHFpn4le.mjs → command-rpc-CGJGUQ6Y.mjs} +40 -28
- package/dist/.setup/compact-C2WamavS.mjs +776 -0
- package/dist/.setup/{config-CedDWjM-.mjs → config-DKhXquav.mjs} +26 -28
- package/dist/.setup/{config-options-BsanJ8QG.mjs → config-options-CzyWLTJt.mjs} +68 -65
- package/dist/.setup/{config-parsing-CcB9iPoq.mjs → config-parsing-b088LyhT.mjs} +57 -60
- package/dist/.setup/{config-runtime-CeAhl_h4.mjs → config-runtime-C0NbLms1.mjs} +2 -2
- package/dist/.setup/{config-security-BRQ2mgW9.mjs → config-security-CE-FcGw9.mjs} +51 -215
- package/dist/.setup/{config-utils-DujwEnhg.mjs → config-utils-D0CXecki.mjs} +3 -13
- package/dist/.setup/context-engine-projection-PezSESth.mjs +387 -0
- package/dist/.setup/{conversation-binding-DhzrpTM6.mjs → conversation-binding-3Min8qvP.mjs} +71 -105
- package/dist/.setup/{conversation-binding-data-CrcyZk6O.mjs → conversation-binding-data-C746z5Pn.mjs} +8 -12
- package/dist/.setup/{conversation-control-DN53ns41.mjs → conversation-control-CEP8X5JC.mjs} +30 -69
- package/dist/.setup/{cyber-failover-DYwbmf1o.mjs → cyber-failover-XV0nNRZu.mjs} +1 -1
- package/dist/.setup/{cyber-failover-notice-e9G3J9-e.mjs → cyber-failover-notice-RNpGpTyP.mjs} +1 -1
- package/dist/.setup/{dynamic-tools-D16lOp67.mjs → dynamic-tools-DzlsLUuS.mjs} +3136 -3167
- package/dist/.setup/{effective-mcp-catalog-K6kLCN8X.mjs → effective-mcp-catalog-CxUtC-xG.mjs} +8 -17
- package/dist/.setup/{ephemeral-turn-R1gA8Sn6.mjs → ephemeral-turn-CDsPJOa2.mjs} +9 -6
- package/dist/.setup/event-projector-assistant-message-CigreO4K.mjs +69 -0
- package/dist/.setup/{event-projector-usage-C7Ntzs-f.mjs → event-projector-usage-03R0I2dM.mjs} +4 -26
- package/dist/.setup/event-projector-values-DJSz8BTk.mjs +106 -0
- package/dist/.setup/incognito-session-DWYapfwf.mjs +2 -0
- package/dist/.setup/{inference-context-fulhZuz8.mjs → inference-context-D-9gWlTR.mjs} +16 -18
- package/dist/.setup/inference-dispatch-CMZtjQyz.mjs +359 -0
- package/dist/.setup/inference-metadata-CgIf7sOx.mjs +81 -0
- package/dist/.setup/inference-proxy-DhcXOgUE.mjs +561 -0
- package/dist/.setup/{isolated-completion-B6srt48J.mjs → isolated-completion-Dm3PzxJk.mjs} +15 -11
- package/dist/.setup/launch-args-DbFCehO7.mjs +196 -0
- package/dist/.setup/{managed-binary-DP6Rib3P.mjs → managed-binary-kiWRhNRE.mjs} +16 -9
- package/dist/.setup/{model-catalog-DkvUuBey.mjs → model-catalog-PAuZgJC6.mjs} +14 -14
- package/dist/.setup/model-runtime-BdqzOMkU.mjs +11 -0
- package/dist/.setup/{models-BDFgm_G-.mjs → models-DHXZtVVk.mjs} +9 -18
- package/dist/.setup/{native-auth-BLZGqFjw.mjs → native-auth-CuG53tu4.mjs} +5 -5
- package/dist/.setup/{native-execution-policy-YBMHSzC4.mjs → native-execution-policy-BxZJy5mP.mjs} +6 -31
- package/dist/.setup/{native-subagent-monitor-B1hxzIOy.mjs → native-subagent-monitor-Dpsmf2wz.mjs} +4422 -3808
- package/dist/.setup/native-subagent-pending-assignments-DwkCzLvD.mjs +203 -0
- package/dist/.setup/native-task-assignments-DMQ0g3hu.mjs +194 -0
- package/dist/.setup/{node-cli-sessions-Cl8b2ZF3.mjs → node-cli-sessions-HC4W6FLI.mjs} +99 -111
- package/dist/.setup/node-exec-server.runtime-BgBfWQqo.mjs +244 -0
- package/dist/.setup/{plan-xD7WKYTM.mjs → plan-Y-QIvrKB.mjs} +118 -163
- package/dist/.setup/{plugin-activation-r8nq5Jzp.mjs → plugin-activation-cNHRfaxU.mjs} +10 -47
- package/dist/.setup/{plugin-app-cache-key-BOxKP7db.mjs → plugin-app-cache-key-BL9B5H0L.mjs} +9 -42
- package/dist/.setup/{plugin-inventory-DUle8DLz.mjs → plugin-inventory-Cky2XJUw.mjs} +32 -23
- package/dist/.setup/{plugin-marketplace-discovery-P-Vndfqq.mjs → plugin-marketplace-discovery-D_dV9FXa.mjs} +22 -25
- package/dist/.setup/{plugin-metadata-cache-DsS5buNa.mjs → plugin-metadata-cache-DsjsL1dr.mjs} +328 -318
- package/dist/.setup/protocol-CANUwXJ3.mjs +17 -0
- package/dist/.setup/provider-DH8NSzGt.mjs +51 -0
- package/dist/.setup/{provider-capabilities-B8J4Dy-O.mjs → provider-capabilities-CAxoF-X1.mjs} +35 -12
- package/dist/.setup/{rate-limits-DOEGYRNs.mjs → rate-limits-B7-X2TgG.mjs} +123 -166
- package/dist/.setup/{request-BioXJLYa.mjs → request-BHZ1nz8d.mjs} +25 -16
- package/dist/.setup/responses-oauth-twnuTaAa.mjs +93 -0
- package/dist/.setup/rpc-error-BlD2vuzn.mjs +31 -0
- package/dist/.setup/{run-attempt-rlA07pUv.mjs → run-attempt-D8RZUOzY.mjs} +2046 -1454
- package/dist/.setup/{run-attempt-lifecycle-B7JbY4-F.mjs → run-attempt-lifecycle-C-6O3Exn.mjs} +10 -24
- package/dist/.setup/{runtime-artifact-Dy38Z5iU.mjs → runtime-artifact-DDQ-HGXf.mjs} +43 -47
- package/dist/.setup/runtime-artifact-connection-D68qQn1m.mjs +78 -0
- package/dist/.setup/sandbox-guard-DjCz2eOw.mjs +126 -0
- package/dist/.setup/scope-DOC1Xjc8.mjs +6 -0
- package/dist/.setup/session-binding-DGCYAfvD.mjs +443 -0
- package/dist/.setup/{session-binding-record-TH3xA0zj.mjs → session-binding-record-Oe9L-CNY.mjs} +73 -132
- package/dist/.setup/{session-binding-sidecars-CKYEcfNn.mjs → session-binding-sidecars-jo6H8dFr.mjs} +242 -60
- package/dist/.setup/{session-catalog-fUdWDx-U.mjs → session-catalog-4sCdv5qx.mjs} +598 -452
- package/dist/.setup/{session-catalog-adoption-CR_whkEW.mjs → session-catalog-adoption-BU_pHWG7.mjs} +59 -26
- package/dist/.setup/{session-catalog-archive-CwZaPacf.mjs → session-catalog-archive-spHfihri.mjs} +7 -7
- package/dist/.setup/session-catalog-events-DePDzzjc.mjs +139 -0
- package/dist/.setup/session-catalog-home-id-vlih0B_g.mjs +22 -0
- package/dist/.setup/{session-catalog-index-B141u15s.mjs → session-catalog-index-CZvDzC6z.mjs} +286 -182
- package/dist/.setup/{session-catalog-index-order-Cc5BzlQr.mjs → session-catalog-index-order-BcQpHks3.mjs} +2 -2
- package/dist/.setup/{session-catalog-index-state-BAuDztHN.mjs → session-catalog-index-state-TeO7EyO-.mjs} +6 -2
- package/dist/.setup/session-catalog-limits-DDxOsQeC.mjs +14 -0
- package/dist/.setup/session-catalog-list-request-CvtxrYSe.mjs +170 -0
- package/dist/.setup/session-catalog-native-projection-DjhwGL6x.mjs +178 -0
- package/dist/.setup/{session-catalog-node-adoption-BVRsYOSh.mjs → session-catalog-node-adoption-DgXvSGu0.mjs} +30 -35
- package/dist/.setup/{session-catalog-node-continue-Dowv8osw.mjs → session-catalog-node-continue-DjKXHBbi.mjs} +25 -18
- package/dist/.setup/session-catalog-node-lookup-CtAXI5W5.mjs +56 -0
- package/dist/.setup/{session-catalog-native-projection-ChV3cCtm.mjs → session-catalog-parsing-CPGaPYr-.mjs} +14 -180
- package/dist/.setup/{session-catalog-projection-C1Bj9Jl-.mjs → session-catalog-projection-Cr5qP5Dj.mjs} +15 -5
- package/dist/.setup/session-catalog-provenance-DoAvktcj.mjs +95 -0
- package/dist/.setup/{session-cli-DIj-IE-E.mjs → session-cli-Cn_nCqfq.mjs} +11 -24
- package/dist/.setup/{session-history-C--SrLI8.mjs → session-history-D83lJWHG.mjs} +16 -23
- package/dist/.setup/{session-history-import-JHXT5Xfi.mjs → session-history-import-WhX-X33a.mjs} +7 -10
- package/dist/.setup/session-history-read-Ov3StuL4.mjs +133 -0
- package/dist/.setup/{session-history.worker-CpNj7H_P.mjs → session-history.worker-MnPKncqP.mjs} +14 -23
- package/dist/.setup/session-initialization-6aveB9qb.mjs +22 -0
- package/dist/.setup/{session-permission-policy-DhurXY0l.mjs → session-permission-policy-Ci_fVX6y.mjs} +4 -8
- package/dist/.setup/{session-retirement-CU87AOg9.mjs → session-retirement-qMTxkNx2.mjs} +31 -12
- package/dist/.setup/{settled-turn-context-fmwouT5I.mjs → settled-turn-context-D4yj4rxf.mjs} +1 -1
- package/dist/.setup/{settled-turn-finalizer-CiY2bLFK.mjs → settled-turn-finalizer-BsvEabkw.mjs} +17 -13
- package/dist/.setup/{shared-client-BpTtuLQ5.mjs → shared-client-DqyTMYug.mjs} +826 -485
- package/dist/.setup/shared-client-lifecycle-DJIgqgMw.mjs +153 -0
- package/dist/.setup/{side-question-DSCZyoBD.mjs → side-question-C4kCmQy1.mjs} +206 -334
- package/dist/.setup/{source-Bjp4UQij.mjs → source-CS_7GFJZ.mjs} +82 -139
- package/dist/.setup/spawn-error-CL3n6MAa.mjs +57 -0
- package/dist/.setup/{thread-archive-guard-jmecf6OJ.mjs → thread-archive-guard-C9frICzX.mjs} +10 -3
- package/dist/.setup/thread-lifecycle-DPflntEJ.mjs +2362 -0
- package/dist/.setup/{incognito-session-uhrBF6wJ.mjs → thread-ownership-queue-Dp24d7-F.mjs} +1 -2
- package/dist/.setup/{thread-ownership-skomxnIt.mjs → thread-ownership-roNP0l1c.mjs} +47 -10
- package/dist/.setup/thread-policy-DTd-DtkX.mjs +109 -0
- package/dist/.setup/thread-requests-B_bRnMGN.mjs +2102 -0
- package/dist/.setup/{thread-resume-BkNpj9Pz.mjs → thread-resume-CdDaoc7T.mjs} +6 -6
- package/dist/.setup/timeout-CXOfNoaX.mjs +46 -0
- package/dist/.setup/transcript-history-projection-DRSifI-1.mjs +201 -0
- package/dist/.setup/{transcript-mirror-attestation-CzM-94NC.mjs → transcript-mirror-attestation-YSegaktH.mjs} +3 -4
- package/dist/.setup/{transcript-mirror-D4qp_leP.mjs → transcript-mirror-kxmCYsuF.mjs} +224 -206
- package/dist/.setup/{transport-stdio-Cmx94Oiy.mjs → transport-stdio-Bdegpn2V.mjs} +138 -75
- package/dist/.setup/transport-websocket-BTBE-LD9.mjs +211 -0
- package/dist/.setup/{upstream-prompt-provenance-LphB8slG.mjs → upstream-prompt-provenance-fXkKbPVC.mjs} +3 -9
- package/dist/.setup/{upstream-session-fork-D3UKxgVD.mjs → upstream-session-fork-CBeVjBpT.mjs} +48 -40
- package/dist/.setup/{usage-BOgBEKso.mjs → usage-BMzNxeR_.mjs} +5 -4
- package/dist/.setup/{usage-limit-error-C0ow7DOc.mjs → usage-limit-error-QXerDo3i.mjs} +5 -20
- package/dist/.setup/{web-search-provider.runtime-CTGuJt6i.mjs → web-search-provider.runtime-P77OUeoo.mjs} +10 -20
- package/dist/api.js +25 -16
- package/dist/catalog-page-worker-entrypoint.js +12 -0
- package/dist/catalog-page.worker.js +9 -0
- package/dist/cli-metadata.js +1 -1
- package/dist/doctor-contract-api.js +50 -8
- package/dist/harness.js +344 -1
- package/dist/index.js +345 -346
- package/dist/media-understanding-provider.js +9 -22
- package/dist/migration-provider-api.js +1 -1
- package/dist/provider-discovery.js +1 -1
- package/dist/session-history-worker-runtime.js +16 -33
- package/dist/session-history.worker.js +1 -1
- package/openclaw.plugin.json +14 -2
- package/package.json +11 -7
- package/dist/.setup/attempt-context-VXVwTCfS.mjs +0 -636
- package/dist/.setup/compact-C3i3qlzj.mjs +0 -687
- package/dist/.setup/event-projector-assistant-message-DNUR1s0A.mjs +0 -105
- package/dist/.setup/event-projector-items-DyTQ_XqL.mjs +0 -200
- package/dist/.setup/harness-rxaaoN-o.mjs +0 -349
- package/dist/.setup/history-rejection-B4nOXNXF.mjs +0 -13
- package/dist/.setup/image-payload-sanitizer-tupAr-2o.mjs +0 -79
- package/dist/.setup/inference-proxy-CC15HuSi.mjs +0 -311
- package/dist/.setup/launch-args-DnMak49W.mjs +0 -111
- package/dist/.setup/local-runtime-attribution-B_2mnqhb.mjs +0 -19
- package/dist/.setup/native-subagent-history-YXaL6dMd.mjs +0 -135
- package/dist/.setup/native-subagent-task-ids-DsuOonKv.mjs +0 -411
- package/dist/.setup/node-exec-server.runtime-BaViBKNz.mjs +0 -226
- package/dist/.setup/plugin-approval-roundtrip-CjfzafAZ.mjs +0 -122
- package/dist/.setup/provider-fFh_-VR3.mjs +0 -50
- package/dist/.setup/rolldown-runtime-8H4AJuhK.mjs +0 -14
- package/dist/.setup/sandbox-guard-BBP-RbTf.mjs +0 -166
- package/dist/.setup/session-binding-_0W_fHRr.mjs +0 -721
- package/dist/.setup/session-catalog-events-jMcYfQyd.mjs +0 -250
- package/dist/.setup/session-history-read-B3ZfSUbF.mjs +0 -50
- package/dist/.setup/session-initialization-DH1z6fXn.mjs +0 -75
- package/dist/.setup/thread-history-page-BTx-4xsg.mjs +0 -83
- package/dist/.setup/thread-lifecycle-Cik28qWn.mjs +0 -4904
- package/dist/.setup/thread-policy-Cjs4B8xf.mjs +0 -54
- package/dist/.setup/timeout-DZF05XrR.mjs +0 -63
- package/dist/.setup/transcript-history-projection-DHNBDhCU.mjs +0 -243
- package/dist/.setup/version-CoqzXPgK.mjs +0 -12
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { isRecord } from "openclaw/plugin-sdk/string-coerce-runtime";
|
|
2
|
+
//#region extensions/codex/src/app-server/protocol.ts
|
|
3
|
+
/** Namespace Codex keeps directly model-visible without exposing it to Code Mode guests. */
|
|
4
|
+
const CODEX_OPENCLAW_DIRECT_DYNAMIC_TOOL_NAMESPACE = "openclaw_direct";
|
|
5
|
+
function flattenCodexDynamicToolFunctions(tools) {
|
|
6
|
+
return (tools ?? []).flatMap((tool) => tool.type === "namespace" ? tool.tools : [tool]);
|
|
7
|
+
}
|
|
8
|
+
/** Asserts the experimental beforeTurnId request field before it crosses the app-server boundary. */
|
|
9
|
+
function assertCodexThreadForkParams(value) {
|
|
10
|
+
if (!isRecord(value) || typeof value.threadId !== "string" || !value.threadId.trim() || value.beforeTurnId !== void 0 && value.beforeTurnId !== null && typeof value.beforeTurnId !== "string") throw new Error("Invalid Codex app-server thread/fork params");
|
|
11
|
+
return value;
|
|
12
|
+
}
|
|
13
|
+
function isJsonObject(value) {
|
|
14
|
+
return isRecord(value);
|
|
15
|
+
}
|
|
16
|
+
//#endregion
|
|
17
|
+
export { isJsonObject as i, assertCodexThreadForkParams as n, flattenCodexDynamicToolFunctions as r, CODEX_OPENCLAW_DIRECT_DYNAMIC_TOOL_NAMESPACE as t };
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { t as isOnlyMigrationKind } from "./scope-DOC1Xjc8.mjs";
|
|
2
|
+
//#region extensions/codex/src/migration/provider.ts
|
|
3
|
+
function buildCodexMigrationProvider(params = {}) {
|
|
4
|
+
return {
|
|
5
|
+
id: "codex",
|
|
6
|
+
label: "Codex",
|
|
7
|
+
description: [
|
|
8
|
+
"Import consolidated memories, selected Codex and personal AgentSkills, and selected eligible openai-curated plugins.",
|
|
9
|
+
"Auth credentials require separate consent. Sessions and chat history are not imported.",
|
|
10
|
+
"Codex config and hooks are saved for manual review, not activated. Source files are not moved or deleted."
|
|
11
|
+
].join(" "),
|
|
12
|
+
supportedItemKinds: ["memory", "auth"],
|
|
13
|
+
async detect(ctx) {
|
|
14
|
+
const { discoverCodexSource, hasCodexSource } = await import("./source-CS_7GFJZ.mjs").then((n) => n.a);
|
|
15
|
+
const memoryOnly = isOnlyMigrationKind(ctx, "memory");
|
|
16
|
+
const authOnly = isOnlyMigrationKind(ctx, "auth");
|
|
17
|
+
const source = await discoverCodexSource({
|
|
18
|
+
input: ctx.source,
|
|
19
|
+
memoryOnly,
|
|
20
|
+
authOnly
|
|
21
|
+
});
|
|
22
|
+
const found = memoryOnly ? source.memoryFiles.length > 0 : authOnly ? Boolean(source.authPath) : hasCodexSource(source);
|
|
23
|
+
return {
|
|
24
|
+
found,
|
|
25
|
+
source: source.root,
|
|
26
|
+
label: "Codex",
|
|
27
|
+
confidence: found ? source.confidence : "low",
|
|
28
|
+
message: found ? "Codex state found." : "Codex state not found."
|
|
29
|
+
};
|
|
30
|
+
},
|
|
31
|
+
async plan(ctx) {
|
|
32
|
+
const { buildCodexMigrationPlan } = await import("./plan-Y-QIvrKB.mjs");
|
|
33
|
+
return buildCodexMigrationPlan(ctx);
|
|
34
|
+
},
|
|
35
|
+
deferredApply: { retrySafe: true },
|
|
36
|
+
prepareApply(ctx) {
|
|
37
|
+
if (isOnlyMigrationKind(ctx, "memory") || isOnlyMigrationKind(ctx, "auth")) return;
|
|
38
|
+
return import("./apply-D3GcSoSa.mjs").then(({ prepareTargetCodexAppServer }) => prepareTargetCodexAppServer(ctx));
|
|
39
|
+
},
|
|
40
|
+
async apply(ctx, plan) {
|
|
41
|
+
const { applyCodexMigrationPlan } = await import("./apply-D3GcSoSa.mjs");
|
|
42
|
+
return await applyCodexMigrationPlan({
|
|
43
|
+
ctx,
|
|
44
|
+
plan,
|
|
45
|
+
runtime: params.runtime
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
//#endregion
|
|
51
|
+
export { buildCodexMigrationProvider as t };
|
package/dist/.setup/{provider-capabilities-B8J4Dy-O.mjs → provider-capabilities-CAxoF-X1.mjs}
RENAMED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { h as releaseLeasedSharedCodexAppServerClient } from "./shared-client-
|
|
2
|
-
import {
|
|
1
|
+
import { h as releaseLeasedSharedCodexAppServerClient } from "./shared-client-DqyTMYug.mjs";
|
|
2
|
+
import { dt as normalizeCodexDynamicToolName } from "./thread-requests-B_bRnMGN.mjs";
|
|
3
3
|
import { pinExecToolTarget } from "openclaw/plugin-sdk/codex-mcp-projection";
|
|
4
4
|
import { loadNodeExecAvailability } from "openclaw/plugin-sdk/node-selection-runtime";
|
|
5
5
|
//#region extensions/codex/src/app-server/shell-dynamic-tools.ts
|
|
@@ -7,7 +7,6 @@ const CODEX_NODE_EXEC_DYNAMIC_TOOL_NAME = "node_exec";
|
|
|
7
7
|
const CODEX_GATEWAY_EXEC_DYNAMIC_TOOL_NAME = "gateway_exec";
|
|
8
8
|
const CODEX_GATEWAY_PROCESS_DYNAMIC_TOOL_NAME = "gateway_process";
|
|
9
9
|
const PROCESS_FOLLOWUP_TEXT = "Use process (list/poll/log/write/send-keys/submit/paste/kill/clear/remove) for follow-up.";
|
|
10
|
-
/** Returns true when plugin config explicitly removes any named dynamic tool. */
|
|
11
10
|
function isCodexDynamicToolExcluded(config, names) {
|
|
12
11
|
const normalizedNames = new Set(names.map((name) => normalizeCodexDynamicToolName(name)));
|
|
13
12
|
return (config.codexDynamicToolsExclude ?? []).some((name) => normalizedNames.has(normalizeCodexDynamicToolName(name)));
|
|
@@ -21,18 +20,11 @@ async function createNodeExecAliasDynamicTool(execTool, node, discoverySignal, a
|
|
|
21
20
|
host: "node",
|
|
22
21
|
...pinnedNode ? { node: pinnedNode } : {}
|
|
23
22
|
});
|
|
24
|
-
const execute = async (toolCallId, args, signal, onUpdate) => {
|
|
25
|
-
const result = await pinnedTool.execute(toolCallId, args, signal, onUpdate);
|
|
26
|
-
return {
|
|
27
|
-
...result,
|
|
28
|
-
content: result.content.map((item) => item.type === "text" ? Object.assign({}, item, { text: item.text.replace(PROCESS_FOLLOWUP_TEXT, "Remote-node background follow-up is unavailable. Wait for the command to complete.") }) : item)
|
|
29
|
-
};
|
|
30
|
-
};
|
|
31
23
|
return {
|
|
32
24
|
...pinnedTool,
|
|
33
25
|
name: CODEX_NODE_EXEC_DYNAMIC_TOOL_NAME,
|
|
34
26
|
description: pinnedNode ? "Run a shell command to completion on the OpenClaw configured remote node for this session. This tool always uses OpenClaw host=node internally and follows the existing node exec approval and allowlist policy. Remote-node background follow-up is unavailable. Use Codex's native shell for local app-server work when it is available." : "Run a shell command to completion on an OpenClaw remote node. The sole connected node that can execute commands is selected automatically; select by name or id when several can. This tool always uses OpenClaw host=node internally and follows the existing node exec approval and allowlist policy. Remote-node background follow-up is unavailable. Use Codex's native shell for local app-server work when it is available.",
|
|
35
|
-
execute
|
|
27
|
+
execute: withProcessFollowupText(pinnedTool, "Remote-node background follow-up is unavailable. Wait for the command to complete.")
|
|
36
28
|
};
|
|
37
29
|
}
|
|
38
30
|
function createGatewayExecProjection(createProjection, execTool, params) {
|
|
@@ -51,6 +43,30 @@ function createGatewayProcessProjection(createProjection, processTool) {
|
|
|
51
43
|
description: "Manage background shell sessions in the existing per-session OpenClaw process scope: list, poll, log, write, send-keys, submit, paste, kill, clear, or remove. Use for gateway_exec follow-up; use native Codex shell session handling for ordinary local work."
|
|
52
44
|
});
|
|
53
45
|
}
|
|
46
|
+
function createSandboxExecProjection(execTool) {
|
|
47
|
+
return {
|
|
48
|
+
...execTool,
|
|
49
|
+
name: "sandbox_exec",
|
|
50
|
+
description: "Run a shell command through OpenClaw's configured sandbox backend for this session. Use when OpenClaw sandboxing is active or when a command must execute in the sandbox backend, such as an SSH-backed sandbox or Docker container-path bind layout. Use Codex's native shell only when no OpenClaw sandbox is active and native Code Mode is available.",
|
|
51
|
+
execute: withProcessFollowupText(execTool, "Use sandbox_process (list/poll/log/write/send-keys/submit/paste/kill/clear/remove) for follow-up.")
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
function withProcessFollowupText(tool, followupText) {
|
|
55
|
+
return async (toolCallId, args, signal, onUpdate) => {
|
|
56
|
+
const result = await tool.execute(toolCallId, args, signal, onUpdate);
|
|
57
|
+
return {
|
|
58
|
+
...result,
|
|
59
|
+
content: result.content.map((item) => item.type === "text" ? Object.assign({}, item, { text: item.text.replace(PROCESS_FOLLOWUP_TEXT, followupText) }) : item)
|
|
60
|
+
};
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
function createSandboxProcessProjection(processTool) {
|
|
64
|
+
return {
|
|
65
|
+
...processTool,
|
|
66
|
+
name: "sandbox_process",
|
|
67
|
+
description: "Manage background shell sessions through OpenClaw's configured sandbox backend for this session: list, poll, log, write, send-keys, submit, paste, kill, clear, or remove. Use only for sandbox follow-up; use Codex's native shell session handling only when no OpenClaw sandbox is active and native Code Mode is available."
|
|
68
|
+
};
|
|
69
|
+
}
|
|
54
70
|
//#endregion
|
|
55
71
|
//#region extensions/codex/src/app-server/provider-capabilities.ts
|
|
56
72
|
function resolveOverriddenProviderWebSearchSupport(modelProviderOverride) {
|
|
@@ -59,6 +75,12 @@ function resolveOverriddenProviderWebSearchSupport(modelProviderOverride) {
|
|
|
59
75
|
return provider === "openai" ? "supported" : "unsupported";
|
|
60
76
|
}
|
|
61
77
|
async function readConfiguredProviderWebSearchSupport(params) {
|
|
78
|
+
if (params.expectedNativeModelProvider) {
|
|
79
|
+
if (((await params.client.request("config/read", { includeLayers: false }, {
|
|
80
|
+
timeoutMs: params.timeoutMs,
|
|
81
|
+
signal: params.signal
|
|
82
|
+
})).config.model_provider ?? "openai") !== params.expectedNativeModelProvider) return "unknown";
|
|
83
|
+
}
|
|
62
84
|
return (await params.client.request("modelProvider/capabilities/read", {}, {
|
|
63
85
|
timeoutMs: params.timeoutMs,
|
|
64
86
|
signal: params.signal
|
|
@@ -89,6 +111,7 @@ async function resolveCodexProviderWebSearchSupport(params) {
|
|
|
89
111
|
client,
|
|
90
112
|
timeoutMs: params.appServer.requestTimeoutMs,
|
|
91
113
|
modelProviderOverride: params.modelProviderOverride,
|
|
114
|
+
expectedNativeModelProvider: params.expectedNativeModelProvider,
|
|
92
115
|
signal: params.signal
|
|
93
116
|
});
|
|
94
117
|
} catch {
|
|
@@ -98,4 +121,4 @@ async function resolveCodexProviderWebSearchSupport(params) {
|
|
|
98
121
|
}
|
|
99
122
|
}
|
|
100
123
|
//#endregion
|
|
101
|
-
export { CODEX_NODE_EXEC_DYNAMIC_TOOL_NAME as a, createNodeExecAliasDynamicTool as c, CODEX_GATEWAY_PROCESS_DYNAMIC_TOOL_NAME as i,
|
|
124
|
+
export { CODEX_NODE_EXEC_DYNAMIC_TOOL_NAME as a, createNodeExecAliasDynamicTool as c, isCodexDynamicToolExcluded as d, CODEX_GATEWAY_PROCESS_DYNAMIC_TOOL_NAME as i, createSandboxExecProjection as l, resolveCodexProviderWebSearchSupportForClient as n, createGatewayExecProjection as o, CODEX_GATEWAY_EXEC_DYNAMIC_TOOL_NAME as r, createGatewayProcessProjection as s, resolveCodexProviderWebSearchSupport as t, createSandboxProcessProjection as u };
|
|
@@ -1,20 +1,72 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { i as isJsonObject } from "./protocol-CANUwXJ3.mjs";
|
|
2
2
|
import { normalizeOptionalString, parseStrictFiniteNumber } from "openclaw/plugin-sdk/string-coerce-runtime";
|
|
3
3
|
import { z } from "zod";
|
|
4
4
|
import { MAX_DATE_TIMESTAMP_MS, resolveExpiresAtMsFromEpochSeconds } from "openclaw/plugin-sdk/number-runtime";
|
|
5
|
-
import { expectDefined } from "openclaw/plugin-sdk/expect-runtime";
|
|
6
5
|
import { PROVIDER_LABELS, clampPercent } from "openclaw/plugin-sdk/provider-usage";
|
|
7
|
-
//#region extensions/codex/src/app-server/rate-
|
|
8
|
-
/**
|
|
9
|
-
* Parses Codex account rate-limit payloads into user-facing usage summaries,
|
|
10
|
-
* reset hints, and enriched usage-limit error messages.
|
|
11
|
-
*/
|
|
12
|
-
const CODEX_LIMIT_ID = "codex";
|
|
13
|
-
const LIMIT_WINDOW_KEYS = ["primary", "secondary"];
|
|
6
|
+
//#region extensions/codex/src/app-server/rate-limit-time.ts
|
|
7
|
+
/** Human-readable Codex quota reset times; no account or routing decisions. */
|
|
14
8
|
const ONE_SECOND_MS = 1e3;
|
|
15
9
|
const ONE_MINUTE_MS = 6e4;
|
|
16
10
|
const ONE_HOUR_MS = 60 * ONE_MINUTE_MS;
|
|
17
|
-
const ONE_DAY_MS = 24 * ONE_HOUR_MS;
|
|
11
|
+
const ONE_DAY_MS$1 = 24 * ONE_HOUR_MS;
|
|
12
|
+
function formatCalendarResetTime(resetsAtMs, nowMs) {
|
|
13
|
+
const resetDate = new Date(resetsAtMs);
|
|
14
|
+
const resetParts = new Intl.DateTimeFormat("en-US", {
|
|
15
|
+
month: "short",
|
|
16
|
+
day: "numeric",
|
|
17
|
+
...resetDate.getFullYear() === new Date(nowMs).getFullYear() ? {} : { year: "numeric" },
|
|
18
|
+
hour: "numeric",
|
|
19
|
+
minute: "2-digit",
|
|
20
|
+
timeZoneName: "short"
|
|
21
|
+
}).formatToParts(resetDate);
|
|
22
|
+
const part = (type) => resetParts.find((entry) => entry.type === type)?.value;
|
|
23
|
+
const dateParts = [
|
|
24
|
+
part("month"),
|
|
25
|
+
part("day"),
|
|
26
|
+
part("year")
|
|
27
|
+
].filter(Boolean);
|
|
28
|
+
return [
|
|
29
|
+
dateParts.length > 1 ? `${dateParts[0]} ${dateParts.slice(1).join(", ")}` : dateParts[0],
|
|
30
|
+
"at",
|
|
31
|
+
[
|
|
32
|
+
[part("hour"), part("minute")].filter(Boolean).join(":"),
|
|
33
|
+
part("dayPeriod"),
|
|
34
|
+
part("timeZoneName")
|
|
35
|
+
].filter(Boolean).join(" ")
|
|
36
|
+
].filter(Boolean).join(" ");
|
|
37
|
+
}
|
|
38
|
+
function formatRelativeDuration(durationMs) {
|
|
39
|
+
const safeMs = Math.max(1e3, durationMs);
|
|
40
|
+
if (safeMs < ONE_MINUTE_MS) return `${Math.ceil(safeMs / 1e3)} seconds`;
|
|
41
|
+
if (safeMs < ONE_HOUR_MS) {
|
|
42
|
+
const minutes = Math.ceil(safeMs / ONE_MINUTE_MS);
|
|
43
|
+
return `${minutes} ${minutes === 1 ? "minute" : "minutes"}`;
|
|
44
|
+
}
|
|
45
|
+
if (safeMs < ONE_DAY_MS$1) {
|
|
46
|
+
const hours = Math.ceil(safeMs / ONE_HOUR_MS);
|
|
47
|
+
return `${hours} ${hours === 1 ? "hour" : "hours"}`;
|
|
48
|
+
}
|
|
49
|
+
const days = Math.ceil(safeMs / ONE_DAY_MS$1);
|
|
50
|
+
return `${days} ${days === 1 ? "day" : "days"}`;
|
|
51
|
+
}
|
|
52
|
+
function formatResetDuration(resetsAtMs, nowMs) {
|
|
53
|
+
const durationMs = Math.round(Math.max(ONE_SECOND_MS, resetsAtMs - nowMs) / ONE_SECOND_MS) * ONE_SECOND_MS;
|
|
54
|
+
const days = Math.floor(durationMs / ONE_DAY_MS$1);
|
|
55
|
+
const hours = Math.floor(durationMs % ONE_DAY_MS$1 / ONE_HOUR_MS);
|
|
56
|
+
const minutes = Math.floor(durationMs % ONE_HOUR_MS / ONE_MINUTE_MS);
|
|
57
|
+
const seconds = Math.floor(durationMs % ONE_MINUTE_MS / ONE_SECOND_MS);
|
|
58
|
+
if (days > 0) return hours > 0 ? `${days}d ${hours}h` : `${days}d`;
|
|
59
|
+
if (hours > 0) return minutes > 0 ? `${hours}h ${minutes}m` : `${hours}h`;
|
|
60
|
+
if (minutes > 0) return seconds > 0 ? `${minutes}m ${seconds}s` : `${minutes}m`;
|
|
61
|
+
return `${seconds}s`;
|
|
62
|
+
}
|
|
63
|
+
//#endregion
|
|
64
|
+
//#region extensions/codex/src/app-server/rate-limits.ts
|
|
65
|
+
const CODEX_LIMIT_ID = "codex";
|
|
66
|
+
const CODEX_RESERVE_ROUTE = "gpt-reserve";
|
|
67
|
+
const CODEX_RESERVE_USAGE_NOTICE = "Luna Reserve is a separate, backend-authorized route. Ordinary Luna does not use this reserve, even with Fast off. An unused reserve does not establish eligibility or per-request billing. Ordinary usage may consume credits after included limits are reached.";
|
|
68
|
+
const LIMIT_WINDOW_KEYS = ["primary", "secondary"];
|
|
69
|
+
const ONE_DAY_MS = 864e5;
|
|
18
70
|
const DAY_WINDOW_MINUTES = 1440;
|
|
19
71
|
const WEEKLY_WINDOW_MINUTES = 7 * DAY_WINDOW_MINUTES;
|
|
20
72
|
const WEEKLY_RESET_GAP_MS = 3 * ONE_DAY_MS;
|
|
@@ -24,32 +76,18 @@ const optionalNumber = z.number().optional().catch(void 0);
|
|
|
24
76
|
const optionalBoolean = z.boolean().optional().catch(void 0);
|
|
25
77
|
const rateLimitWindowSchema = z.object({
|
|
26
78
|
usedPercent: optionalNumber,
|
|
27
|
-
used_percent: optionalNumber,
|
|
28
79
|
resetsAt: optionalNumber,
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
}).
|
|
35
|
-
const resetsAt = window.resetsAt ?? window.resets_at;
|
|
36
|
-
return {
|
|
37
|
-
usedPercent: window.usedPercent ?? window.used_percent,
|
|
38
|
-
resetsAt,
|
|
39
|
-
resetsAtMs: resolveExpiresAtMsFromEpochSeconds(resetsAt, { maxMs: MAX_DATE_TIMESTAMP_MS }) ?? 0,
|
|
40
|
-
windowDurationMins: window.windowDurationMins ?? window.window_duration_mins ?? window.windowMinutes ?? window.window_minutes
|
|
41
|
-
};
|
|
42
|
-
}).optional().catch(void 0);
|
|
80
|
+
windowDurationMins: optionalNumber
|
|
81
|
+
}).transform((window) => ({
|
|
82
|
+
usedPercent: window.usedPercent,
|
|
83
|
+
resetsAtMs: resolveExpiresAtMsFromEpochSeconds(window.resetsAt, { maxMs: MAX_DATE_TIMESTAMP_MS }) ?? 0,
|
|
84
|
+
windowDurationMins: window.windowDurationMins
|
|
85
|
+
})).optional().catch(void 0);
|
|
43
86
|
const creditsSchema = z.object({
|
|
44
87
|
hasCredits: optionalBoolean,
|
|
45
|
-
has_credits: optionalBoolean,
|
|
46
88
|
unlimited: optionalBoolean,
|
|
47
89
|
balance: z.preprocess(parseStrictFiniteNumber, optionalNumber)
|
|
48
|
-
}).
|
|
49
|
-
hasCredits: credits.hasCredits ?? credits.has_credits,
|
|
50
|
-
unlimited: credits.unlimited,
|
|
51
|
-
balance: credits.balance
|
|
52
|
-
})).optional().catch(void 0);
|
|
90
|
+
}).optional().catch(void 0);
|
|
53
91
|
const rateLimitSnapshotSchema = z.looseObject({
|
|
54
92
|
primary: rateLimitWindowSchema,
|
|
55
93
|
secondary: rateLimitWindowSchema,
|
|
@@ -58,19 +96,22 @@ const rateLimitSnapshotSchema = z.looseObject({
|
|
|
58
96
|
primary: snapshot.primary,
|
|
59
97
|
secondary: snapshot.secondary,
|
|
60
98
|
credits: snapshot.credits,
|
|
61
|
-
limitId: normalizeOptionalString(snapshot.limitId)
|
|
62
|
-
limitName: normalizeOptionalString(snapshot.limitName)
|
|
63
|
-
planType: normalizeOptionalString(snapshot.planType)
|
|
64
|
-
rateLimitReachedType: normalizeOptionalString(snapshot.rateLimitReachedType)
|
|
99
|
+
limitId: normalizeOptionalString(snapshot.limitId),
|
|
100
|
+
limitName: normalizeOptionalString(snapshot.limitName),
|
|
101
|
+
planType: normalizeOptionalString(snapshot.planType),
|
|
102
|
+
rateLimitReachedType: normalizeOptionalString(snapshot.rateLimitReachedType)
|
|
65
103
|
}));
|
|
66
|
-
/** Enriches Codex usage-limit failures with reset timing and recovery guidance. */
|
|
67
104
|
function formatCodexUsageLimitErrorMessage(params) {
|
|
68
105
|
const message = normalizeOptionalString(params.message);
|
|
69
|
-
if (
|
|
106
|
+
if (params.codexErrorInfo !== "usageLimitExceeded") return;
|
|
70
107
|
const nowMs = params.nowMs ?? Date.now();
|
|
71
|
-
const
|
|
72
|
-
|
|
73
|
-
const
|
|
108
|
+
const ordinaryUsageAllowed = readOrdinaryUsageAllowed(params.rateLimits);
|
|
109
|
+
const snapshots = collectCodexRateLimitSnapshots(params.rateLimits).filter(snapshotHasDisplayableData);
|
|
110
|
+
const usageSnapshot = snapshots.find(isCodexLimitSnapshot) ?? snapshots[0];
|
|
111
|
+
const blockingSnapshot = selectBlockingRateLimitSnapshot(snapshots, ordinaryUsageAllowed);
|
|
112
|
+
const usageSummary = usageSnapshot ? summarizeRateLimitUsage(usageSnapshot, blockingSnapshot, nowMs) : void 0;
|
|
113
|
+
if (params.rateLimitsAuthoritative && (ordinaryUsageAllowed === true && !blockingSnapshot || ordinaryUsageAllowed === void 0 && usageSummary?.blocked === false)) return [CODEX_USAGE_LIMIT_STATE_MISMATCH_MESSAGE, "Retry the request, use another Codex account if available, or switch to another configured model/provider."].join(" ");
|
|
114
|
+
const nextReset = (blockingSnapshot ? selectSnapshotBlockingReset(blockingSnapshot, nowMs) : void 0) ?? (ordinaryUsageAllowed === void 0 && !usageSummary?.blocked ? selectNextRateLimitReset(params.rateLimits, nowMs) : void 0);
|
|
74
115
|
const parts = [CODEX_USAGE_LIMIT_MESSAGE_PREFIX];
|
|
75
116
|
let recoveryAction = "Wait until Codex becomes available";
|
|
76
117
|
if (nextReset) {
|
|
@@ -89,40 +130,42 @@ function formatCodexUsageLimitErrorMessage(params) {
|
|
|
89
130
|
parts.push(`${recoveryAction}, use another Codex account if available, or switch to another configured model/provider.`);
|
|
90
131
|
return parts.join(" ");
|
|
91
132
|
}
|
|
92
|
-
/** Detects usage-limit messages that need a fresh rate-limit query before display. */
|
|
93
133
|
function shouldRefreshCodexRateLimitsForUsageLimitMessage(message) {
|
|
94
134
|
const text = normalizeOptionalString(message);
|
|
95
135
|
return Boolean(text?.startsWith(CODEX_USAGE_LIMIT_MESSAGE_PREFIX) && !text.includes("Next reset "));
|
|
96
136
|
}
|
|
97
|
-
/** Formats compact summaries for raw Codex rate-limit snapshot payloads. */
|
|
98
137
|
function summarizeCodexRateLimits(value, nowMs = Date.now()) {
|
|
99
138
|
const snapshots = collectCodexRateLimitSnapshots(value).filter(snapshotHasDisplayableData);
|
|
100
139
|
if (snapshots.length === 0) return;
|
|
101
140
|
const summaries = snapshots.slice(0, 4).map((snapshot) => summarizeRateLimitSnapshot(snapshot, nowMs)).filter((summary) => summary !== void 0);
|
|
102
|
-
|
|
141
|
+
if (summaries.length === 0) return;
|
|
142
|
+
return [summaries.join("; "), reserveUsageNotice(snapshots)].filter(Boolean).join(". ");
|
|
103
143
|
}
|
|
104
|
-
/** Returns true when a value contains any recognizable Codex rate-limit snapshots. */
|
|
105
144
|
function hasCodexRateLimitSnapshots(value) {
|
|
106
145
|
return collectCodexRateLimitSnapshots(value).length > 0;
|
|
107
146
|
}
|
|
108
|
-
/** Builds short account availability lines suitable for status surfaces. */
|
|
109
147
|
function summarizeCodexAccountRateLimits(value, nowMs = Date.now()) {
|
|
110
148
|
const summary = summarizeCodexAccountUsage(value, nowMs);
|
|
111
149
|
if (!summary) return;
|
|
112
150
|
if (!summary.blocked) return ["Codex is available."];
|
|
113
151
|
return [summary.blockedUntilText ? `Codex is paused until ${summary.blockedUntilText}.` : "Codex is paused by a usage limit.", summary.blockingReason ? `Your ${summary.blockingReason}.` : "Your Codex usage limit is reached."];
|
|
114
152
|
}
|
|
115
|
-
/** Returns the reset timestamp for the currently blocking Codex usage limit. */
|
|
116
153
|
function resolveCodexUsageLimitResetAtMs(value, nowMs = Date.now()) {
|
|
117
|
-
|
|
154
|
+
const blockingSnapshot = selectBlockingRateLimitSnapshot(collectCodexRateLimitSnapshots(value), readOrdinaryUsageAllowed(value));
|
|
155
|
+
return blockingSnapshot ? selectSnapshotBlockingReset(blockingSnapshot, nowMs)?.resetsAtMs : void 0;
|
|
118
156
|
}
|
|
119
|
-
/** Summarizes account availability, blocking reason, and reset time from rate-limit data. */
|
|
120
157
|
function summarizeCodexAccountUsage(value, nowMs = Date.now()) {
|
|
121
|
-
const
|
|
122
|
-
if (
|
|
123
|
-
const
|
|
124
|
-
|
|
125
|
-
|
|
158
|
+
const ordinaryUsageAllowed = readOrdinaryUsageAllowed(value);
|
|
159
|
+
if (ordinaryUsageAllowed === null) return;
|
|
160
|
+
const snapshot = collectCodexRateLimitSnapshots(value).find(isCodexLimitSnapshot);
|
|
161
|
+
if (ordinaryUsageAllowed !== void 0) return {
|
|
162
|
+
usageLine: snapshot ? formatUsageLine(snapshot) : void 0,
|
|
163
|
+
blocked: !ordinaryUsageAllowed,
|
|
164
|
+
...!ordinaryUsageAllowed ? { blockingReason: "Codex usage limit is reached" } : {}
|
|
165
|
+
};
|
|
166
|
+
return snapshot && snapshotHasDisplayableData(snapshot) ? summarizeRateLimitUsage(snapshot, snapshotHasLimitBlock(snapshot) ? snapshot : void 0, nowMs) : void 0;
|
|
167
|
+
}
|
|
168
|
+
function summarizeRateLimitUsage(usageSnapshot, blockingSnapshot, nowMs) {
|
|
126
169
|
const blockingEntries = blockingSnapshot ? readWindowEntries(blockingSnapshot) : [];
|
|
127
170
|
const blockingWindowEntry = selectBlockingWindowEntry(blockingEntries, nowMs);
|
|
128
171
|
const blockingWindow = blockingWindowEntry?.window;
|
|
@@ -141,13 +184,14 @@ function summarizeCodexAccountUsage(value, nowMs = Date.now()) {
|
|
|
141
184
|
...blockingReason ? { blockingReason } : {}
|
|
142
185
|
};
|
|
143
186
|
}
|
|
144
|
-
/** Converts Codex app-server rate-limit payloads into OpenAI/Codex usage windows. */
|
|
145
187
|
function buildCodexAppServerUsageSnapshot(value, options = {}) {
|
|
146
188
|
const snapshots = collectCodexRateLimitSnapshots(value);
|
|
147
189
|
const snapshot = snapshots.find(isCodexLimitSnapshot) ?? snapshots[0];
|
|
148
190
|
const entries = snapshot ? readWindowEntries(snapshot) : [];
|
|
149
191
|
const windows = entries.map((entry) => readProviderUsageWindow(entry, entries)).filter((window) => Boolean(window));
|
|
192
|
+
const summary = reserveUsageNotice(snapshots);
|
|
150
193
|
const result = {
|
|
194
|
+
...summary ? { summary } : {},
|
|
151
195
|
provider: "openai",
|
|
152
196
|
displayName: PROVIDER_LABELS.openai,
|
|
153
197
|
windows,
|
|
@@ -176,29 +220,21 @@ function buildCodexAppServerUsageSnapshot(value, options = {}) {
|
|
|
176
220
|
}
|
|
177
221
|
return result;
|
|
178
222
|
}
|
|
179
|
-
function isCodexUsageLimitError(codexErrorInfo) {
|
|
180
|
-
if (codexErrorInfo === "usageLimitExceeded") return true;
|
|
181
|
-
if (typeof codexErrorInfo === "string") {
|
|
182
|
-
if (codexErrorInfo.replace(/[_\s-]/gu, "").toLowerCase() === "usagelimitexceeded") return true;
|
|
183
|
-
}
|
|
184
|
-
return false;
|
|
185
|
-
}
|
|
186
223
|
function selectNextRateLimitReset(value, nowMs) {
|
|
187
224
|
const futureWindows = collectCodexRateLimitSnapshots(value).flatMap((snapshot) => LIMIT_WINDOW_KEYS.flatMap((key) => snapshot[key] ?? [])).filter((window) => window.resetsAtMs > nowMs);
|
|
188
225
|
if (futureWindows.length === 0) return;
|
|
189
226
|
const exhaustedWindows = futureWindows.filter((window) => window.usedPercent !== void 0 && window.usedPercent >= 100);
|
|
190
227
|
return (exhaustedWindows.length > 0 ? exhaustedWindows : futureWindows).toSorted((left, right) => left.resetsAtMs - right.resetsAtMs)[0];
|
|
191
228
|
}
|
|
192
|
-
function
|
|
193
|
-
const blockedSnapshots =
|
|
194
|
-
|
|
195
|
-
return blockingSnapshot ? selectSnapshotBlockingReset(blockingSnapshot, nowMs) : void 0;
|
|
229
|
+
function selectBlockingRateLimitSnapshot(snapshots, ordinaryUsageAllowed) {
|
|
230
|
+
const blockedSnapshots = snapshots.filter((snapshot) => snapshotHasLimitBlock(snapshot) && (ordinaryUsageAllowed !== true && ordinaryUsageAllowed !== null || !isCodexLimitSnapshot(snapshot)));
|
|
231
|
+
return blockedSnapshots.find(isCodexLimitSnapshot) ?? blockedSnapshots[0];
|
|
196
232
|
}
|
|
197
233
|
function summarizeRateLimitSnapshot(snapshot, nowMs) {
|
|
198
234
|
const label = formatLimitLabel(snapshot);
|
|
199
235
|
const windows = LIMIT_WINDOW_KEYS.flatMap((key) => {
|
|
200
236
|
const window = snapshot[key];
|
|
201
|
-
return window ? [
|
|
237
|
+
return window ? [`${key} ${formatRateLimitWindowDetails(window, nowMs)}`] : [];
|
|
202
238
|
});
|
|
203
239
|
const reachedType = snapshot.rateLimitReachedType;
|
|
204
240
|
const suffix = reachedType ? ` (${formatReachedType(reachedType)})` : "";
|
|
@@ -206,28 +242,14 @@ function summarizeRateLimitSnapshot(snapshot, nowMs) {
|
|
|
206
242
|
if (reachedType) return `${label}: ${formatReachedType(reachedType)}`;
|
|
207
243
|
}
|
|
208
244
|
function collectCodexRateLimitSnapshots(value) {
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
return snapshots;
|
|
212
|
-
}
|
|
213
|
-
function collectRateLimitSnapshots(value, snapshots, seen) {
|
|
214
|
-
if (Array.isArray(value)) {
|
|
215
|
-
for (const entry of value) collectRateLimitSnapshots(entry, snapshots, seen);
|
|
216
|
-
return;
|
|
217
|
-
}
|
|
218
|
-
if (!isJsonObject(value)) return;
|
|
219
|
-
if (isRateLimitSnapshot(value)) {
|
|
220
|
-
addRateLimitSnapshot(rateLimitSnapshotSchema.parse(value), snapshots, seen);
|
|
221
|
-
return;
|
|
222
|
-
}
|
|
245
|
+
if (!isJsonObject(value)) return [];
|
|
246
|
+
if (isRateLimitSnapshot(value)) return [rateLimitSnapshotSchema.parse(value)];
|
|
223
247
|
const byLimitId = value.rateLimitsByLimitId;
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
collectRateLimitSnapshots(value.data, snapshots, seen);
|
|
230
|
-
collectRateLimitSnapshots(value.items, snapshots, seen);
|
|
248
|
+
return (isJsonObject(byLimitId) ? sortedRateLimitKeys(Object.keys(byLimitId)).map((key) => byLimitId[key]) : [value.rateLimits]).filter(isJsonObject).filter(isRateLimitSnapshot).map((snapshot) => rateLimitSnapshotSchema.parse(snapshot));
|
|
249
|
+
}
|
|
250
|
+
function readOrdinaryUsageAllowed(value) {
|
|
251
|
+
const allowed = isJsonObject(value) ? value.ordinaryUsageAllowed : void 0;
|
|
252
|
+
return allowed === null || typeof allowed === "boolean" ? allowed : void 0;
|
|
231
253
|
}
|
|
232
254
|
function sortedRateLimitKeys(keys) {
|
|
233
255
|
return keys.toSorted((left, right) => {
|
|
@@ -236,33 +258,26 @@ function sortedRateLimitKeys(keys) {
|
|
|
236
258
|
return left.localeCompare(right);
|
|
237
259
|
});
|
|
238
260
|
}
|
|
239
|
-
function addRateLimitSnapshot(snapshot, snapshots, seen) {
|
|
240
|
-
const signature = [
|
|
241
|
-
snapshot.limitId ?? "",
|
|
242
|
-
snapshot.limitName ?? "",
|
|
243
|
-
formatWindowSignature(snapshot.primary),
|
|
244
|
-
formatWindowSignature(snapshot.secondary)
|
|
245
|
-
].join("|");
|
|
246
|
-
if (seen.has(signature)) return;
|
|
247
|
-
seen.add(signature);
|
|
248
|
-
snapshots.push(snapshot);
|
|
249
|
-
}
|
|
250
261
|
function isRateLimitSnapshot(value) {
|
|
251
|
-
return isJsonObject(value.primary) || isJsonObject(value.secondary) || value.rateLimitReachedType !== void 0 || value.
|
|
262
|
+
return isJsonObject(value.primary) || isJsonObject(value.secondary) || value.rateLimitReachedType !== void 0 || value.limitId !== void 0 || value.limitName !== void 0;
|
|
252
263
|
}
|
|
253
264
|
function snapshotHasDisplayableData(snapshot) {
|
|
254
265
|
return Boolean(snapshot.rateLimitReachedType) || readWindowEntries(snapshot).some((entry) => entry.window.usedPercent !== void 0 || entry.window.resetsAtMs > 0);
|
|
255
266
|
}
|
|
256
|
-
function formatRateLimitWindow(key, window, nowMs) {
|
|
257
|
-
return `${key} ${formatRateLimitWindowDetails(window, nowMs)}`;
|
|
258
|
-
}
|
|
259
267
|
function formatRateLimitWindowDetails(window, nowMs) {
|
|
260
268
|
return `${window.usedPercent === void 0 ? "usage unknown" : `${Math.max(0, 100 - Math.round(window.usedPercent))}% left`}${window.resetsAtMs > nowMs ? ` ⏱${formatResetDuration(window.resetsAtMs, nowMs)}` : ""}`;
|
|
261
269
|
}
|
|
270
|
+
function reserveUsageNotice(snapshots) {
|
|
271
|
+
return snapshots.some(isReserveSnapshot) ? CODEX_RESERVE_USAGE_NOTICE : void 0;
|
|
272
|
+
}
|
|
273
|
+
function isReserveSnapshot(snapshot) {
|
|
274
|
+
return snapshot.limitName === CODEX_RESERVE_ROUTE || snapshot.limitId === CODEX_RESERVE_ROUTE;
|
|
275
|
+
}
|
|
262
276
|
function formatLimitLabel(snapshot) {
|
|
277
|
+
if (isReserveSnapshot(snapshot)) return "Luna Reserve (separate route)";
|
|
263
278
|
const label = snapshot.limitName ?? snapshot.limitId;
|
|
264
279
|
if (!label || label === CODEX_LIMIT_ID) return "Codex";
|
|
265
|
-
return label
|
|
280
|
+
return formatReachedType(label);
|
|
266
281
|
}
|
|
267
282
|
function formatReachedType(value) {
|
|
268
283
|
return value.replace(/[_-]+/gu, " ").replace(/\s+/gu, " ").trim();
|
|
@@ -312,11 +327,8 @@ function formatCodexCreditSummary(credits) {
|
|
|
312
327
|
return roundedBalance > 0 ? `${roundedBalance} credits` : void 0;
|
|
313
328
|
}
|
|
314
329
|
function selectSnapshotBlockingReset(snapshot, nowMs) {
|
|
315
|
-
const
|
|
316
|
-
|
|
317
|
-
const candidates = exhaustedWindows.length > 0 ? exhaustedWindows : futureWindows;
|
|
318
|
-
const resetSort = exhaustedWindows.length > 0 ? (left, right) => right.resetsAtMs - left.resetsAtMs : (left, right) => left.resetsAtMs - right.resetsAtMs;
|
|
319
|
-
return candidates.toSorted(resetSort)[0];
|
|
330
|
+
const window = selectBlockingWindowEntry(readWindowEntries(snapshot), nowMs)?.window;
|
|
331
|
+
return window && window.resetsAtMs > nowMs ? window : void 0;
|
|
320
332
|
}
|
|
321
333
|
function selectBlockingWindowEntry(entries, nowMs) {
|
|
322
334
|
const futureEntries = entries.filter((entry) => entry.window.resetsAtMs > nowMs);
|
|
@@ -351,10 +363,9 @@ function formatUsageLine(snapshot) {
|
|
|
351
363
|
return windows.length > 0 ? windows.join(" · ") : void 0;
|
|
352
364
|
}
|
|
353
365
|
function formatUsageWindowLabel(entry, entries) {
|
|
366
|
+
const period = formatBlockingLimitPeriod(entry, entries);
|
|
367
|
+
if (period) return period;
|
|
354
368
|
const minutes = entry.window.windowDurationMins;
|
|
355
|
-
if (minutes === WEEKLY_WINDOW_MINUTES || hasWeeklySecondaryResetCadence(entry, entries)) return "weekly";
|
|
356
|
-
if (minutes === DAY_WINDOW_MINUTES) return "daily";
|
|
357
|
-
if (minutes !== void 0 && minutes > 0 && minutes < DAY_WINDOW_MINUTES) return "short-term";
|
|
358
369
|
if (minutes !== void 0 && minutes > 0 && minutes % DAY_WINDOW_MINUTES === 0) return `${minutes / DAY_WINDOW_MINUTES}-day`;
|
|
359
370
|
if (minutes !== void 0 && minutes > 0 && minutes % 60 === 0) return `${minutes / 60}-hour`;
|
|
360
371
|
return "usage";
|
|
@@ -364,60 +375,6 @@ function hasWeeklySecondaryResetCadence(entry, entries) {
|
|
|
364
375
|
const primaryResetMs = entries.find((candidate) => candidate.key === "primary")?.window.resetsAtMs;
|
|
365
376
|
return typeof primaryResetMs === "number" && primaryResetMs > 0 && entry.window.resetsAtMs > 0 && entry.window.resetsAtMs - primaryResetMs >= WEEKLY_RESET_GAP_MS;
|
|
366
377
|
}
|
|
367
|
-
function formatCalendarResetTime(resetsAtMs, nowMs) {
|
|
368
|
-
const resetDate = new Date(resetsAtMs);
|
|
369
|
-
const resetParts = new Intl.DateTimeFormat("en-US", {
|
|
370
|
-
month: "short",
|
|
371
|
-
day: "numeric",
|
|
372
|
-
...resetDate.getFullYear() === new Date(nowMs).getFullYear() ? {} : { year: "numeric" },
|
|
373
|
-
hour: "numeric",
|
|
374
|
-
minute: "2-digit",
|
|
375
|
-
timeZoneName: "short"
|
|
376
|
-
}).formatToParts(resetDate);
|
|
377
|
-
const part = (type) => resetParts.find((entry) => entry.type === type)?.value;
|
|
378
|
-
const dateParts = [
|
|
379
|
-
part("month"),
|
|
380
|
-
part("day"),
|
|
381
|
-
part("year")
|
|
382
|
-
].filter(Boolean);
|
|
383
|
-
return [
|
|
384
|
-
dateParts.length > 1 ? `${dateParts[0]} ${dateParts.slice(1).join(", ")}` : dateParts[0],
|
|
385
|
-
"at",
|
|
386
|
-
[
|
|
387
|
-
[part("hour"), part("minute")].filter(Boolean).join(":"),
|
|
388
|
-
part("dayPeriod"),
|
|
389
|
-
part("timeZoneName")
|
|
390
|
-
].filter(Boolean).join(" ")
|
|
391
|
-
].filter(Boolean).join(" ");
|
|
392
|
-
}
|
|
393
|
-
function formatRelativeDuration(durationMs) {
|
|
394
|
-
const safeMs = Math.max(1e3, durationMs);
|
|
395
|
-
if (safeMs < ONE_MINUTE_MS) return `${Math.ceil(safeMs / 1e3)} seconds`;
|
|
396
|
-
if (safeMs < ONE_HOUR_MS) {
|
|
397
|
-
const minutes = Math.ceil(safeMs / ONE_MINUTE_MS);
|
|
398
|
-
return `${minutes} ${minutes === 1 ? "minute" : "minutes"}`;
|
|
399
|
-
}
|
|
400
|
-
if (safeMs < ONE_DAY_MS) {
|
|
401
|
-
const hours = Math.ceil(safeMs / ONE_HOUR_MS);
|
|
402
|
-
return `${hours} ${hours === 1 ? "hour" : "hours"}`;
|
|
403
|
-
}
|
|
404
|
-
const days = Math.ceil(safeMs / ONE_DAY_MS);
|
|
405
|
-
return `${days} ${days === 1 ? "day" : "days"}`;
|
|
406
|
-
}
|
|
407
|
-
function formatResetDuration(resetsAtMs, nowMs) {
|
|
408
|
-
const durationMs = Math.round(Math.max(ONE_SECOND_MS, resetsAtMs - nowMs) / ONE_SECOND_MS) * ONE_SECOND_MS;
|
|
409
|
-
const days = Math.floor(durationMs / ONE_DAY_MS);
|
|
410
|
-
const hours = Math.floor(durationMs % ONE_DAY_MS / ONE_HOUR_MS);
|
|
411
|
-
const minutes = Math.floor(durationMs % ONE_HOUR_MS / ONE_MINUTE_MS);
|
|
412
|
-
const seconds = Math.floor(durationMs % ONE_MINUTE_MS / ONE_SECOND_MS);
|
|
413
|
-
if (days > 0) return hours > 0 ? `${days}d ${hours}h` : `${days}d`;
|
|
414
|
-
if (hours > 0) return minutes > 0 ? `${hours}h ${minutes}m` : `${hours}h`;
|
|
415
|
-
if (minutes > 0) return seconds > 0 ? `${minutes}m ${seconds}s` : `${minutes}m`;
|
|
416
|
-
return `${seconds}s`;
|
|
417
|
-
}
|
|
418
|
-
function formatWindowSignature(window) {
|
|
419
|
-
return window ? `${window.usedPercent ?? ""}:${window.resetsAt ?? ""}` : "";
|
|
420
|
-
}
|
|
421
378
|
function extractCodexRetryHint(message) {
|
|
422
379
|
if (!message) return;
|
|
423
380
|
const tryAgainAt = /\btry again\s+(at\s+[^.!?\n]+)(?:[.!?]|$)/iu.exec(message);
|
|
@@ -425,4 +382,4 @@ function extractCodexRetryHint(message) {
|
|
|
425
382
|
return /\btry again\s+((?:tomorrow|in\s+[^.!?\n]+)[^.!?\n]*)(?:[.!?]|$)/iu.exec(message)?.[1]?.trim();
|
|
426
383
|
}
|
|
427
384
|
//#endregion
|
|
428
|
-
export { shouldRefreshCodexRateLimitsForUsageLimitMessage as a, summarizeCodexRateLimits as c, resolveCodexUsageLimitResetAtMs as i, formatCodexUsageLimitErrorMessage as n, summarizeCodexAccountRateLimits as o, hasCodexRateLimitSnapshots as r, summarizeCodexAccountUsage as s, buildCodexAppServerUsageSnapshot as t };
|
|
385
|
+
export { shouldRefreshCodexRateLimitsForUsageLimitMessage as a, summarizeCodexRateLimits as c, resolveCodexUsageLimitResetAtMs as i, formatRelativeDuration as l, formatCodexUsageLimitErrorMessage as n, summarizeCodexAccountRateLimits as o, hasCodexRateLimitSnapshots as r, summarizeCodexAccountUsage as s, buildCodexAppServerUsageSnapshot as t };
|