dsh-lcx-codex 0.4.2 → 0.4.3-pre.12
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 +89 -205
- package/cordis.patch.yml +3 -20
- package/lib/client.js +309 -146
- package/lib/compact-v2.js +218 -199
- package/lib/dsh-compat.js +232 -100
- package/lib/dsh-responses.js +452 -277
- package/lib/grok-native-search.js +254 -0
- package/lib/index.js +1013 -757
- package/lib/json-store.js +50 -31
- package/lib/native-checkpoint.js +520 -194
- package/lib/responses-request.js +109 -121
- package/lib/responses-stream.js +1249 -447
- package/lib/route.js +411 -369
- package/lib/service-mutex.js +73 -64
- package/lib/token-budget.js +176 -108
- package/lib/transport.js +280 -68
- package/lib/types/client/index.d.ts +6 -0
- package/lib/types/compact-v2.d.ts +104 -0
- package/lib/types/dsh-compat.d.ts +78 -0
- package/lib/types/dsh-responses.d.ts +82 -0
- package/lib/types/grok-native-search.d.ts +34 -0
- package/lib/types/index.d.ts +83 -0
- package/lib/types/json-store.d.ts +10 -0
- package/lib/types/native-checkpoint.d.ts +213 -0
- package/lib/types/responses-request.d.ts +59 -0
- package/lib/types/responses-stream.d.ts +64 -0
- package/lib/types/route.d.ts +153 -0
- package/lib/types/service-mutex.d.ts +14 -0
- package/lib/types/token-budget.d.ts +50 -0
- package/lib/types/transport.d.ts +21 -0
- package/lib/types/web-run-output.d.ts +29 -0
- package/lib/types/web-search-alpha.d.ts +286 -0
- package/lib/types/web-search-capability.d.ts +26 -0
- package/lib/types/web-search-hosted.d.ts +246 -0
- package/lib/types/web-search-ref-store.d.ts +22 -0
- package/lib/web-run-output.js +167 -18
- package/lib/web-search-alpha.js +865 -163
- package/lib/web-search-capability.js +55 -65
- package/lib/web-search-hosted.js +210 -32
- package/lib/web-search-ref-store.js +63 -59
- package/package.json +89 -29
- package/ARCHITECTURE.md +0 -117
- package/CHANGELOG.md +0 -224
- package/README_EN.md +0 -277
- package/assets/dsh-lcx-codex-banner.jpg +0 -0
- package/lib/legacy-v3.js +0 -20
- package/lib/responses-replay.js +0 -68
- package/scripts/probe-alpha.mjs +0 -43
- package/scripts/validate-dsh-schema.mjs +0 -31
package/lib/index.js
CHANGED
|
@@ -1,798 +1,1054 @@
|
|
|
1
|
-
import z from
|
|
2
|
-
import {
|
|
3
|
-
import
|
|
4
|
-
import
|
|
5
|
-
import
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
export const name = 'lcx-codex'
|
|
93
|
-
export const inject = ['llm', 'web', 'sessions']
|
|
94
|
-
const SETTINGS_NS = settingsNamespace('lcx-codex')
|
|
95
|
-
const ADVANCED_HOSTED_TOOL = 'websearch_gpt_advanced'
|
|
96
|
-
const ALPHA_TOOL = 'websearch_alpha'
|
|
97
|
-
const COMPACTION_DIRECTIVE = 'You are now acting as a compaction engine'
|
|
98
|
-
const hostedSearchRouteContext = new AsyncLocalStorage()
|
|
99
|
-
|
|
100
|
-
function dshHome() { return process.env.DSH_HOME ?? join(homedir(), '.dsh') }
|
|
101
|
-
function defaultLegacyCheckpointPath() { return join(dshHome(), 'storages', 'lcx-codex', 'checkpoints-v3.json') }
|
|
102
|
-
function defaultAlphaCapabilityPath() { return join(dshHome(), 'storages', 'lcx-codex', 'web-alpha-capabilities.json') }
|
|
103
|
-
function defaultAlphaRefPath() { return join(dshHome(), 'storages', 'lcx-codex', 'web-alpha-refs.json') }
|
|
104
|
-
|
|
1
|
+
import z from "@deepseek-ai/schemastery";
|
|
2
|
+
import { WEB_SEARCH_MAX_QUERIES, applyWebSearchTool, } from "@deepseek-ai/dsh-tool-web";
|
|
3
|
+
import "@deepseek-ai/dsh-agent";
|
|
4
|
+
import "@deepseek-ai/dsh-tools";
|
|
5
|
+
import "@deepseek-ai/dsh-web";
|
|
6
|
+
import { randomUUID } from "node:crypto";
|
|
7
|
+
import { homedir } from "node:os";
|
|
8
|
+
import { join } from "node:path";
|
|
9
|
+
import { AsyncLocalStorage } from "node:async_hooks";
|
|
10
|
+
import { getSupportedThinkingLevels } from "@earendil-works/pi-ai";
|
|
11
|
+
import { fetchJsonWithRetry } from "./transport.js";
|
|
12
|
+
import { agentSessionId, agentUsesSession, compactionConfigState, compactionPatchCandidate, installCompactionPatch, patchCompactionConfig, patchToolResultPruner, readAgentRouteState, resolveAgentService, resolveContextService, resolveScopedService, restoreCompactionConfig, restoreCompactionPatches, restoreToolResultPruner, sessionFor, sessionFromAgent, scopedToolRuntime, tokenMeterTotal, toolResultPrunerState, } from "./dsh-compat.js";
|
|
13
|
+
import { authenticatedGrokHeaders, authenticatedHeaders, currentRoute, generationControlsFromSession, grokPromptCacheSessionId, promptCacheKey, promptCacheRetention, promptCacheSessionId, resolveGrokResponsesRouteConfig, resolveResponsesRouteConfig, routeFingerprint, } from "./route.js";
|
|
14
|
+
import { DEFAULT_MAX_REQUEST_IMAGE_BYTES, DEFAULT_REQUEST_IMAGE_PIXEL_BUDGET, DEFAULT_REQUEST_IMAGE_MAX_BYTES, hydrateNativeImageReferences, resolveModelImageSupport, responseInputItems, serializeDshMessages, } from "./dsh-responses.js";
|
|
15
|
+
import { mergeFeatureHeader, requestNativeCompaction } from "./compact-v2.js";
|
|
16
|
+
import { buildResponsesBody } from "./responses-request.js";
|
|
17
|
+
import { managedFailureChunk, streamResponsesRequest, } from "./responses-stream.js";
|
|
18
|
+
import { assertSupportedCheckpointMessage, checkpointStateForMessage, compactCheckpointId, createNativeCheckpointBlock, nativeCheckpointChunks, portableMessagesForCheckpoint, stateRouteCompatible, } from "./native-checkpoint.js";
|
|
19
|
+
import { HOSTED_SEARCH_OUTPUT, HOSTED_SEARCH_PARAMETERS, buildHostedSearchBody, normalizeHostedSearchArgs, parseHostedSearchResponse, renderHostedSearchResult, } from "./web-search-hosted.js";
|
|
20
|
+
import { ALPHA_SCHEMA_FINGERPRINT, alphaRefRequiresStore, isAlphaContinuationUrl, isAlphaHttpUrl, ALPHA_SEARCH_OUTPUT, ALPHA_SEARCH_PARAMETERS, buildAlphaSearchBody, normalizeAlphaSearchArgs, parseAlphaSearchResponse, renderAlphaSearchResult, } from "./web-search-alpha.js";
|
|
21
|
+
import { AlphaCapabilityStore, alphaCapabilityFingerprint, alphaCapabilityUsable, } from "./web-search-capability.js";
|
|
22
|
+
import { AlphaRefStore } from "./web-search-ref-store.js";
|
|
23
|
+
import { ServiceMutex } from "./service-mutex.js";
|
|
24
|
+
import { GROK_NATIVE_SERVER_TOOL_TYPES, grokNativeSearchEnabled, grokVisibleFunctionTools, grokWireTools, restoreGrokNativeReplay, } from "./grok-native-search.js";
|
|
25
|
+
export const name = "lcx-codex";
|
|
26
|
+
export const inject = ["llm", "web", "sessions", "tools", "settings", "credentials", "attachments", "fs"];
|
|
27
|
+
const SETTINGS_NS = "lcx-codex";
|
|
28
|
+
const ADVANCED_HOSTED_TOOL = "websearch_gpt_advanced";
|
|
29
|
+
const ALPHA_TOOL = "websearch_alpha";
|
|
30
|
+
const hostedSearchRouteContext = new AsyncLocalStorage();
|
|
31
|
+
const WEB_SEARCH_TIMEOUT_MS = 240_000;
|
|
32
|
+
const AUTO_COMPACTION_THRESHOLD_PERCENT = 90;
|
|
33
|
+
const EMERGENCY_PRUNE_THRESHOLD_PERCENT = 95;
|
|
34
|
+
function positiveInteger(value, fallback, maximum) {
|
|
35
|
+
if (typeof value !== "number" || !Number.isSafeInteger(value) || value <= 0)
|
|
36
|
+
return fallback;
|
|
37
|
+
return maximum === undefined ? value : Math.min(value, maximum);
|
|
38
|
+
}
|
|
39
|
+
function stringValue(value, fallback) {
|
|
40
|
+
return typeof value === "string" && value.trim() ? value : fallback;
|
|
41
|
+
}
|
|
42
|
+
function routeWithPolicies(route, config) {
|
|
43
|
+
return {
|
|
44
|
+
...route,
|
|
45
|
+
alphaProfile: config.alphaProfile,
|
|
46
|
+
alphaGroup: config.alphaGroup,
|
|
47
|
+
alphaMaxOutputTokens: config.alphaMaxOutputTokens,
|
|
48
|
+
assistantRetentionPerMessageTokenCap: config.assistantRetentionPerMessageTokenCap,
|
|
49
|
+
assistantRetentionTokenReserve: config.assistantRetentionTokenReserve,
|
|
50
|
+
maxRequestImageBytes: route.maxRequestImageBytes ?? config.maxRequestImageBytes,
|
|
51
|
+
maxResponseBytes: config.maxResponseBytes,
|
|
52
|
+
nativeRetentionTokenBudget: config.nativeRetentionTokenBudget,
|
|
53
|
+
portableReplayMaxChars: config.portableReplayMaxChars,
|
|
54
|
+
requestImageMaxBytes: route.requestImageMaxBytes ?? config.requestImageMaxBytes,
|
|
55
|
+
requestImagePixelBudget: route.requestImagePixelBudget ?? config.requestImagePixelBudget,
|
|
56
|
+
webMaxResults: config.webMaxResults,
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
function grokReplayRoute(route, config) {
|
|
60
|
+
return {
|
|
61
|
+
...route,
|
|
62
|
+
apiKeyEnv: config.apiKeyEnv,
|
|
63
|
+
headers: config.headers,
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
function isRecord(value) {
|
|
67
|
+
return value !== null && typeof value === "object";
|
|
68
|
+
}
|
|
69
|
+
function asAbortSignal(value) {
|
|
70
|
+
return value instanceof AbortSignal ? value : undefined;
|
|
71
|
+
}
|
|
72
|
+
function errorDetails(value) {
|
|
73
|
+
return isRecord(value)
|
|
74
|
+
? {
|
|
75
|
+
name: value.name,
|
|
76
|
+
code: value.code,
|
|
77
|
+
status: value.status,
|
|
78
|
+
message: value.message,
|
|
79
|
+
}
|
|
80
|
+
: {};
|
|
81
|
+
}
|
|
82
|
+
function dshHome() {
|
|
83
|
+
return process.env.DSH_HOME ?? join(homedir(), ".dsh");
|
|
84
|
+
}
|
|
85
|
+
function defaultAlphaCapabilityPath() {
|
|
86
|
+
return join(dshHome(), "storages", "lcx-codex", "web-alpha-capabilities.json");
|
|
87
|
+
}
|
|
88
|
+
function defaultAlphaRefPath() {
|
|
89
|
+
return join(dshHome(), "storages", "lcx-codex", "web-alpha-refs.json");
|
|
90
|
+
}
|
|
105
91
|
export const Config = z.object({
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
assistantRetentionTokenReserve: z.number().default(24_000),
|
|
129
|
-
assistantRetentionPerMessageTokenCap: z.number().default(3_000),
|
|
130
|
-
webSearchTimeoutMs: z.number().default(240_000),
|
|
131
|
-
autoCompactionThresholdPercent: z.number().default(90),
|
|
132
|
-
emergencyPruneThresholdPercent: z.number().default(95),
|
|
133
|
-
})
|
|
134
|
-
|
|
92
|
+
supportsLongCacheRetention: z.boolean().default(false),
|
|
93
|
+
supportsExplicitPromptCacheMode: z.boolean().default(false),
|
|
94
|
+
alphaCapabilityPath: z.string().default(""),
|
|
95
|
+
alphaRefPath: z.string().default(""),
|
|
96
|
+
alphaProfile: z.string().default(""),
|
|
97
|
+
alphaGroup: z.string().default(""),
|
|
98
|
+
alphaMaxOutputTokens: z.number().default(2500),
|
|
99
|
+
webSearchProvider: z.string().default("lcx-responses"),
|
|
100
|
+
webMaxResults: z.number().default(8),
|
|
101
|
+
timeoutMs: z.number().default(300000),
|
|
102
|
+
maxResponseBytes: z.number().default(8 * 1024 * 1024),
|
|
103
|
+
maxAttempts: z.number().default(3),
|
|
104
|
+
maxRequestImageBytes: z.number().default(DEFAULT_MAX_REQUEST_IMAGE_BYTES),
|
|
105
|
+
requestImagePixelBudget: z
|
|
106
|
+
.number()
|
|
107
|
+
.default(DEFAULT_REQUEST_IMAGE_PIXEL_BUDGET),
|
|
108
|
+
requestImageMaxBytes: z.number().default(DEFAULT_REQUEST_IMAGE_MAX_BYTES),
|
|
109
|
+
portableReplayMaxChars: z.number().default(80_000),
|
|
110
|
+
nativeRetentionTokenBudget: z.number().default(64_000),
|
|
111
|
+
assistantRetentionTokenReserve: z.number().default(24_000),
|
|
112
|
+
assistantRetentionPerMessageTokenCap: z.number().default(3_000),
|
|
113
|
+
});
|
|
135
114
|
const SettingsSchema = z.object({
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
webSearchTimeoutSeconds: z.number().default(240),
|
|
144
|
-
autoCompactionThresholdPercent: z.number().default(90),
|
|
145
|
-
emergencyPruneThresholdPercent: z.number().default(95),
|
|
146
|
-
provider: z.string().default('lcx'),
|
|
147
|
-
baseURL: z.string().default('https://api.lcxbot.com/v1'),
|
|
148
|
-
apiKeyEnv: z.string().default('LCX_API_KEY'),
|
|
149
|
-
model: z.string().default('gpt-5.6-sol'),
|
|
150
|
-
})
|
|
151
|
-
|
|
115
|
+
enabled: z.boolean().default(false),
|
|
116
|
+
webSearch: z.boolean().default(false),
|
|
117
|
+
advancedHostedSearch: z.boolean().default(false),
|
|
118
|
+
alphaSearch: z.boolean().default(false),
|
|
119
|
+
grokNativeWebSearch: z.boolean().default(false),
|
|
120
|
+
grokNativeXSearch: z.boolean().default(false),
|
|
121
|
+
});
|
|
152
122
|
function normalizeConfig(input = {}) {
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
webSearchTimeoutMs: Number.isSafeInteger(input.webSearchTimeoutMs) && input.webSearchTimeoutMs >= 30_000 ? Math.min(input.webSearchTimeoutMs, 600_000) : 240_000,
|
|
180
|
-
autoCompactionThresholdPercent: Number.isFinite(input.autoCompactionThresholdPercent) ? Math.min(95, Math.max(85, Number(input.autoCompactionThresholdPercent))) : 90,
|
|
181
|
-
emergencyPruneThresholdPercent: Number.isFinite(input.emergencyPruneThresholdPercent) ? Math.min(99, Math.max(90, Number(input.emergencyPruneThresholdPercent))) : 95,
|
|
182
|
-
}
|
|
183
|
-
}
|
|
184
|
-
|
|
123
|
+
return {
|
|
124
|
+
supportsLongCacheRetention: input.supportsLongCacheRetention === true,
|
|
125
|
+
supportsExplicitPromptCacheMode: input.supportsExplicitPromptCacheMode === true,
|
|
126
|
+
alphaCapabilityPath: stringValue(input.alphaCapabilityPath, defaultAlphaCapabilityPath()),
|
|
127
|
+
alphaRefPath: stringValue(input.alphaRefPath, defaultAlphaRefPath()),
|
|
128
|
+
alphaProfile: String(input.alphaProfile ?? ""),
|
|
129
|
+
alphaGroup: String(input.alphaGroup ?? ""),
|
|
130
|
+
alphaMaxOutputTokens: positiveInteger(input.alphaMaxOutputTokens, 2500, 32_000),
|
|
131
|
+
webSearchProvider: stringValue(input.webSearchProvider, "lcx-responses"),
|
|
132
|
+
webMaxResults: positiveInteger(input.webMaxResults, 8),
|
|
133
|
+
timeoutMs: positiveInteger(input.timeoutMs, 300000),
|
|
134
|
+
maxResponseBytes: positiveInteger(input.maxResponseBytes, 8 * 1024 * 1024),
|
|
135
|
+
maxAttempts: positiveInteger(input.maxAttempts, 3, 6),
|
|
136
|
+
maxRequestImageBytes: positiveInteger(input.maxRequestImageBytes, DEFAULT_MAX_REQUEST_IMAGE_BYTES),
|
|
137
|
+
requestImagePixelBudget: positiveInteger(input.requestImagePixelBudget, DEFAULT_REQUEST_IMAGE_PIXEL_BUDGET),
|
|
138
|
+
requestImageMaxBytes: positiveInteger(input.requestImageMaxBytes, DEFAULT_REQUEST_IMAGE_MAX_BYTES),
|
|
139
|
+
portableReplayMaxChars: positiveInteger(input.portableReplayMaxChars, 80_000),
|
|
140
|
+
nativeRetentionTokenBudget: positiveInteger(input.nativeRetentionTokenBudget, 64_000),
|
|
141
|
+
assistantRetentionTokenReserve: typeof input.assistantRetentionTokenReserve === "number" &&
|
|
142
|
+
Number.isSafeInteger(input.assistantRetentionTokenReserve) &&
|
|
143
|
+
input.assistantRetentionTokenReserve >= 0
|
|
144
|
+
? input.assistantRetentionTokenReserve
|
|
145
|
+
: 24_000,
|
|
146
|
+
assistantRetentionPerMessageTokenCap: positiveInteger(input.assistantRetentionPerMessageTokenCap, 3_000),
|
|
147
|
+
};
|
|
148
|
+
}
|
|
185
149
|
function webError(message, code, cause) {
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
150
|
+
const error = new Error(message, cause === undefined ? undefined : { cause });
|
|
151
|
+
error.name = "WebError";
|
|
152
|
+
error.code = code;
|
|
153
|
+
return error;
|
|
154
|
+
}
|
|
155
|
+
function routeConfigValue(value, name) {
|
|
156
|
+
return isRecord(value) ? value[name] : undefined;
|
|
157
|
+
}
|
|
158
|
+
function activeAgentRoute(exec) {
|
|
159
|
+
const route = readAgentRouteState(exec.agent);
|
|
160
|
+
return {
|
|
161
|
+
provider: stringValue(routeConfigValue(route.requestConfig, "provider") ??
|
|
162
|
+
routeConfigValue(route.options, "provider"), ""),
|
|
163
|
+
model: stringValue(routeConfigValue(route.requestConfig, "model") ??
|
|
164
|
+
routeConfigValue(route.options, "model"), ""),
|
|
165
|
+
sessionId: route.sessionId,
|
|
166
|
+
};
|
|
167
|
+
}
|
|
168
|
+
function selectedAgentRoute(agent) {
|
|
169
|
+
const route = readAgentRouteState(agent);
|
|
170
|
+
return {
|
|
171
|
+
provider: stringValue(routeConfigValue(route.requestConfig, "provider") ??
|
|
172
|
+
routeConfigValue(route.options, "provider"), ""),
|
|
173
|
+
model: stringValue(routeConfigValue(route.requestConfig, "model") ??
|
|
174
|
+
routeConfigValue(route.options, "model"), ""),
|
|
175
|
+
sessionId: route.sessionId,
|
|
176
|
+
};
|
|
177
|
+
}
|
|
208
178
|
function requestImageOptions(routeConfig, imageSupport, signal, imageMap, extra = {}) {
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
179
|
+
return {
|
|
180
|
+
imageSupport,
|
|
181
|
+
signal,
|
|
182
|
+
imageMap,
|
|
183
|
+
maxRequestImageBytes: routeConfig.maxRequestImageBytes,
|
|
184
|
+
requestImagePixelBudget: routeConfig.requestImagePixelBudget,
|
|
185
|
+
requestImageMaxBytes: routeConfig.requestImageMaxBytes,
|
|
186
|
+
...extra,
|
|
187
|
+
};
|
|
188
|
+
}
|
|
189
|
+
async function executeHostedSearch(ctx, routeConfig, args, signal, sessionId = "") {
|
|
190
|
+
const normalized = normalizeHostedSearchArgs(args);
|
|
191
|
+
const requestId = randomUUID();
|
|
192
|
+
const route = currentRoute({ provider: routeConfig.provider, model: routeConfig.model, sessionId }, routeConfig);
|
|
193
|
+
const headers = await authenticatedHeaders(ctx, routeConfig, sessionId, requestId);
|
|
194
|
+
const searchCacheKey = sessionId
|
|
195
|
+
? `dsh-lcx-search:${routeFingerprint(route)}`
|
|
196
|
+
: undefined;
|
|
197
|
+
const body = buildHostedSearchBody(normalized, routeConfig.model, {
|
|
198
|
+
promptCacheKey: searchCacheKey,
|
|
199
|
+
});
|
|
200
|
+
const response = await fetchJsonWithRetry(`${routeConfig.baseURL}/responses`, body, headers, signal, routeConfig.timeoutMs, {
|
|
201
|
+
maxAttempts: routeConfig.maxAttempts,
|
|
202
|
+
maxResponseBytes: routeConfig.maxResponseBytes,
|
|
203
|
+
});
|
|
204
|
+
return parseHostedSearchResponse(response, requestId, routeConfig.webMaxResults);
|
|
205
|
+
}
|
|
229
206
|
class LcxResponsesSearchProvider {
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
207
|
+
ctx;
|
|
208
|
+
getConfig;
|
|
209
|
+
enabled;
|
|
210
|
+
id;
|
|
211
|
+
constructor(ctx, getConfig, enabled) {
|
|
212
|
+
this.ctx = ctx;
|
|
213
|
+
this.getConfig = getConfig;
|
|
214
|
+
this.enabled = enabled;
|
|
215
|
+
this.id = getConfig().webSearchProvider;
|
|
216
|
+
}
|
|
217
|
+
available() {
|
|
218
|
+
const active = hostedSearchRouteContext.getStore();
|
|
219
|
+
if (!active)
|
|
220
|
+
return false;
|
|
221
|
+
const config = this.getConfig();
|
|
222
|
+
const route = resolveResponsesRouteConfig(this.ctx, active, config);
|
|
223
|
+
return this.enabled() && Boolean(route);
|
|
245
224
|
}
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
225
|
+
async search(request, signal) {
|
|
226
|
+
const config = this.getConfig();
|
|
227
|
+
const active = hostedSearchRouteContext.getStore();
|
|
228
|
+
const route = active && resolveResponsesRouteConfig(this.ctx, active, config);
|
|
229
|
+
const routeConfig = route && routeWithPolicies(route, config);
|
|
230
|
+
if (!routeConfig)
|
|
231
|
+
throw webError("LCX Hosted Search requires a configured GPT openai-responses route", "LCX_WEB_ROUTE_UNAVAILABLE");
|
|
232
|
+
const sessionId = active?.sessionId ?? "";
|
|
233
|
+
this.ctx.logger?.info?.(`[lcx-codex] web_search route: ${routeConfig.provider}/${routeConfig.model} (active-agent)`);
|
|
234
|
+
const result = await executeHostedSearch(this.ctx, routeConfig, { query: request.query }, signal, sessionId);
|
|
235
|
+
const max = request.maxResults ?? routeConfig.webMaxResults;
|
|
236
|
+
return {
|
|
237
|
+
content: result.content || undefined,
|
|
238
|
+
sources: result.sources.slice(0, max),
|
|
239
|
+
truncated: result.truncated || result.sources.length > max,
|
|
240
|
+
};
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
function createScopedGptWebSearchTool(ctx, state, getConfig, provider, fetchEnabled) {
|
|
244
|
+
let definition;
|
|
245
|
+
const composition = {
|
|
246
|
+
web: {
|
|
247
|
+
search: (request, signal) => provider.search(request, signal),
|
|
248
|
+
},
|
|
249
|
+
tools: {
|
|
250
|
+
register(candidate) {
|
|
251
|
+
definition = candidate;
|
|
252
|
+
return () => { };
|
|
253
|
+
},
|
|
254
|
+
},
|
|
255
|
+
systemPrompt: {
|
|
256
|
+
getSectionOrder: () => 0,
|
|
257
|
+
section: () => () => { },
|
|
258
|
+
},
|
|
259
|
+
};
|
|
260
|
+
applyWebSearchTool(composition, getConfig().webMaxResults, WEB_SEARCH_MAX_QUERIES, WEB_SEARCH_TIMEOUT_MS, fetchEnabled);
|
|
261
|
+
if (!definition)
|
|
262
|
+
throw new Error("DSH web_search composition did not register a tool");
|
|
263
|
+
const execute = definition.execute.bind(definition);
|
|
264
|
+
return {
|
|
265
|
+
...definition,
|
|
266
|
+
async execute(args, exec) {
|
|
267
|
+
if (!state.enabled || !state.webSearch)
|
|
268
|
+
throw webError("web_search GPT Hosted Search is disabled", "LCX_WEB_DISABLED");
|
|
269
|
+
const active = activeAgentRoute(exec);
|
|
270
|
+
const route = resolveResponsesRouteConfig(ctx, active, getConfig());
|
|
271
|
+
if (!route)
|
|
272
|
+
throw webError("GPT Hosted Search requires the active GPT openai-responses route", "LCX_WEB_ROUTE_UNAVAILABLE");
|
|
273
|
+
return hostedSearchRouteContext.run(active, () => execute(args, exec));
|
|
274
|
+
},
|
|
275
|
+
};
|
|
276
|
+
}
|
|
255
277
|
function createAdvancedHostedTool(ctx, state, getConfig) {
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
278
|
+
return {
|
|
279
|
+
name: ADVANCED_HOSTED_TOOL,
|
|
280
|
+
description: "Advanced GPT Responses Hosted Search. Use DSH web_search for ordinary lookup. Call this only when you need domain allow/block filters, approximate user location, search-context size, image search, external-web-access or return-token-budget controls. It is one-shot and has no open/find/click state.",
|
|
281
|
+
parameters: HOSTED_SEARCH_PARAMETERS,
|
|
282
|
+
output: {
|
|
283
|
+
schema: HOSTED_SEARCH_OUTPUT,
|
|
284
|
+
render: (_args, value) => renderHostedSearchResult(value),
|
|
285
|
+
},
|
|
286
|
+
async execute(args, exec) {
|
|
287
|
+
if (!state.enabled || !state.webSearch || !state.advancedHostedSearch)
|
|
288
|
+
throw webError(`${ADVANCED_HOSTED_TOOL} is disabled`, "LCX_WEB_DISABLED");
|
|
289
|
+
const config = getConfig();
|
|
290
|
+
const active = activeAgentRoute(exec);
|
|
291
|
+
const route = resolveResponsesRouteConfig(ctx, active, config);
|
|
292
|
+
if (!route)
|
|
293
|
+
throw webError("Advanced Hosted Search requires the active GPT openai-responses route", "LCX_WEB_ROUTE_UNAVAILABLE");
|
|
294
|
+
return executeHostedSearch(ctx, routeWithPolicies(route, config), args, exec.signal, active.sessionId);
|
|
295
|
+
},
|
|
296
|
+
};
|
|
297
|
+
}
|
|
298
|
+
function disposeGptToolsForAgent(agent, registrations) {
|
|
299
|
+
const registration = registrations.get(agent);
|
|
300
|
+
if (!registration)
|
|
301
|
+
return;
|
|
302
|
+
registration.dispose();
|
|
303
|
+
registrations.delete(agent);
|
|
304
|
+
}
|
|
305
|
+
function syncGptToolsForAgent(ctx, agent, state, getConfig, provider, registrations) {
|
|
306
|
+
const config = getConfig();
|
|
307
|
+
const active = selectedAgentRoute(agent);
|
|
308
|
+
const route = resolveResponsesRouteConfig(ctx, active, config);
|
|
309
|
+
const webSearch = state.enabled && state.webSearch && Boolean(route);
|
|
310
|
+
const advanced = webSearch && state.advancedHostedSearch;
|
|
311
|
+
if (!webSearch && !advanced) {
|
|
312
|
+
disposeGptToolsForAgent(agent, registrations);
|
|
313
|
+
return false;
|
|
314
|
+
}
|
|
315
|
+
const fingerprint = JSON.stringify({
|
|
316
|
+
provider: route?.provider,
|
|
317
|
+
model: route?.model,
|
|
318
|
+
baseURL: route?.baseURL,
|
|
319
|
+
webSearch,
|
|
320
|
+
advanced,
|
|
321
|
+
webMaxResults: config.webMaxResults,
|
|
322
|
+
});
|
|
323
|
+
if (registrations.get(agent)?.fingerprint === fingerprint)
|
|
324
|
+
return true;
|
|
325
|
+
disposeGptToolsForAgent(agent, registrations);
|
|
326
|
+
const scopedTools = scopedToolRuntime(agent);
|
|
327
|
+
if (!scopedTools)
|
|
328
|
+
return false;
|
|
329
|
+
const disposers = [];
|
|
330
|
+
try {
|
|
331
|
+
if (webSearch) {
|
|
332
|
+
const fetchEnabled = Boolean(scopedTools.get?.("web_fetch", agent));
|
|
333
|
+
disposers.push(scopedTools.register(createScopedGptWebSearchTool(ctx, state, getConfig, provider, fetchEnabled)));
|
|
334
|
+
}
|
|
335
|
+
if (advanced)
|
|
336
|
+
disposers.push(scopedTools.register(createAdvancedHostedTool(ctx, state, getConfig)));
|
|
337
|
+
registrations.set(agent, {
|
|
338
|
+
fingerprint,
|
|
339
|
+
dispose() {
|
|
340
|
+
for (const dispose of disposers.reverse())
|
|
341
|
+
dispose();
|
|
342
|
+
},
|
|
343
|
+
});
|
|
344
|
+
return true;
|
|
345
|
+
}
|
|
346
|
+
catch (error) {
|
|
347
|
+
for (const dispose of disposers.reverse())
|
|
348
|
+
dispose();
|
|
349
|
+
ctx.logger?.warn?.(`[lcx-codex] GPT search tool composition unavailable: ${errorDetails(error).message ?? String(error)}`);
|
|
350
|
+
return false;
|
|
351
|
+
}
|
|
352
|
+
}
|
|
271
353
|
function alphaCapabilityFor(config, store) {
|
|
272
|
-
|
|
273
|
-
|
|
354
|
+
const fingerprint = alphaCapabilityFingerprint({
|
|
355
|
+
baseURL: config.baseURL,
|
|
356
|
+
provider: config.provider,
|
|
357
|
+
model: config.model,
|
|
358
|
+
profile: config.alphaProfile,
|
|
359
|
+
group: config.alphaGroup,
|
|
360
|
+
schemaFingerprint: ALPHA_SCHEMA_FINGERPRINT,
|
|
361
|
+
});
|
|
362
|
+
return { fingerprint, record: store.get(fingerprint) };
|
|
274
363
|
}
|
|
275
|
-
|
|
276
364
|
function verifiedAlphaCapabilityForRoute(ctx, active, config, store) {
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
365
|
+
const resolvedRoute = resolveResponsesRouteConfig(ctx, active, config);
|
|
366
|
+
if (!resolvedRoute)
|
|
367
|
+
return { route: undefined, usable: false };
|
|
368
|
+
const route = routeWithPolicies(resolvedRoute, config);
|
|
369
|
+
const { fingerprint, record } = alphaCapabilityFor(route, store);
|
|
370
|
+
return {
|
|
371
|
+
route,
|
|
372
|
+
fingerprint,
|
|
373
|
+
record,
|
|
374
|
+
usable: alphaCapabilityUsable(record) &&
|
|
375
|
+
record?.schemaFingerprint === ALPHA_SCHEMA_FINGERPRINT,
|
|
376
|
+
};
|
|
281
377
|
}
|
|
282
|
-
|
|
283
378
|
async function executeAlpha(ctx, routeConfig, capability, refStore, args, exec) {
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
379
|
+
const normalized = normalizeAlphaSearchArgs(args);
|
|
380
|
+
if (["open", "find", "screenshot"].includes(normalized.action) &&
|
|
381
|
+
isAlphaHttpUrl(normalized.refId) &&
|
|
382
|
+
!isAlphaContinuationUrl(normalized.refId)) {
|
|
383
|
+
throw webError("Alpha Search direct URLs must be public HTTP(S) targets", "LCX_ALPHA_URL_UNAVAILABLE");
|
|
384
|
+
}
|
|
385
|
+
const sessionId = agentSessionId(exec?.agent);
|
|
386
|
+
if (!sessionId)
|
|
387
|
+
throw webError("Alpha Search requires a DSH session", "LCX_ALPHA_SESSION_REQUIRED");
|
|
388
|
+
const routeFp = routeFingerprint({
|
|
389
|
+
provider: routeConfig.provider,
|
|
390
|
+
model: routeConfig.model,
|
|
391
|
+
baseURL: routeConfig.baseURL,
|
|
392
|
+
sessionId,
|
|
393
|
+
});
|
|
394
|
+
if (alphaRefRequiresStore(normalized.action, normalized.refId))
|
|
395
|
+
refStore.assertUsable(sessionId, routeFp, normalized.refId);
|
|
396
|
+
const requestId = randomUUID();
|
|
397
|
+
const headers = await authenticatedHeaders(ctx, routeConfig, sessionId, requestId);
|
|
398
|
+
let response;
|
|
399
|
+
try {
|
|
400
|
+
response = await fetchJsonWithRetry(`${routeConfig.baseURL}/alpha/search`, buildAlphaSearchBody(normalized, routeConfig.model, sessionId, true, routeConfig.alphaMaxOutputTokens), headers, exec?.signal, routeConfig.timeoutMs, {
|
|
401
|
+
maxAttempts: routeConfig.maxAttempts,
|
|
402
|
+
maxResponseBytes: routeConfig.maxResponseBytes,
|
|
403
|
+
});
|
|
404
|
+
}
|
|
405
|
+
catch (error) {
|
|
406
|
+
const details = errorDetails(error);
|
|
407
|
+
if ([404, 405].includes(Number(details.status)) ||
|
|
408
|
+
/channel does not support/iu.test(String(details.message ?? "")))
|
|
409
|
+
throw webError("Alpha Search is not supported by this route", "LCX_ALPHA_UNAVAILABLE", error);
|
|
410
|
+
throw webError("Alpha Search provider request failed", "LCX_ALPHA_PROVIDER_ERROR", error);
|
|
411
|
+
}
|
|
412
|
+
const { refRecords, ...result } = parseAlphaSearchResponse(response, {
|
|
413
|
+
action: normalized.action,
|
|
414
|
+
capability: capability.classification,
|
|
415
|
+
requestId,
|
|
416
|
+
});
|
|
417
|
+
refStore.record(sessionId, routeFp, refRecords);
|
|
418
|
+
return result;
|
|
419
|
+
}
|
|
306
420
|
function createAlphaTool(ctx, state, getConfig, capabilityStore, refStore) {
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
421
|
+
return {
|
|
422
|
+
name: ALPHA_TOOL,
|
|
423
|
+
description: "Stateful Codex/Alpha web command tool. Use it for search/open/find/click/PDF screenshot and the structured image/finance/weather/sports/time actions. Use DSH web_search for ordinary search, and websearch_gpt_advanced only for Hosted Search controls.",
|
|
424
|
+
parameters: ALPHA_SEARCH_PARAMETERS,
|
|
425
|
+
output: {
|
|
426
|
+
schema: ALPHA_SEARCH_OUTPUT,
|
|
427
|
+
render: (_args, value) => renderAlphaSearchResult(value),
|
|
428
|
+
},
|
|
429
|
+
async execute(args, exec) {
|
|
430
|
+
if (!state.enabled || !state.alphaSearch)
|
|
431
|
+
throw webError(`${ALPHA_TOOL} is disabled`, "LCX_ALPHA_DISABLED");
|
|
432
|
+
const config = getConfig();
|
|
433
|
+
const active = activeAgentRoute(exec);
|
|
434
|
+
const route = resolveResponsesRouteConfig(ctx, active, config);
|
|
435
|
+
if (!route)
|
|
436
|
+
throw webError("Alpha Search requires the active GPT openai-responses route", "LCX_ALPHA_ROUTE_UNAVAILABLE");
|
|
437
|
+
const routeConfig = routeWithPolicies(route, config);
|
|
438
|
+
const fingerprint = alphaCapabilityFingerprint({
|
|
439
|
+
baseURL: routeConfig.baseURL,
|
|
440
|
+
provider: routeConfig.provider,
|
|
441
|
+
model: routeConfig.model,
|
|
442
|
+
profile: routeConfig.alphaProfile,
|
|
443
|
+
group: routeConfig.alphaGroup,
|
|
444
|
+
schemaFingerprint: ALPHA_SCHEMA_FINGERPRINT,
|
|
445
|
+
});
|
|
446
|
+
const capability = capabilityStore.get(fingerprint);
|
|
447
|
+
if (!alphaCapabilityUsable(capability) ||
|
|
448
|
+
capability?.schemaFingerprint !== ALPHA_SCHEMA_FINGERPRINT)
|
|
449
|
+
throw webError("Alpha Search capability has not been verified for this exact route/schema", "LCX_ALPHA_CAPABILITY_UNVERIFIED");
|
|
450
|
+
return executeAlpha(ctx, routeConfig, capability, refStore, args, exec);
|
|
451
|
+
},
|
|
452
|
+
};
|
|
453
|
+
}
|
|
324
454
|
function syncAlphaToolForAgent(ctx, agent, state, getConfig, capabilityStore, refStore, registrations) {
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
}
|
|
330
|
-
try {
|
|
331
|
-
const config = getConfig()
|
|
332
|
-
const active = selectedAgentRoute(agent, config)
|
|
333
|
-
const capability = verifiedAlphaCapabilityForRoute(ctx, active, config, capabilityStore)
|
|
334
|
-
if (!capability.usable) {
|
|
335
|
-
disposeAlphaToolForAgent(agent, registrations)
|
|
336
|
-
return false
|
|
455
|
+
const previous = registrations.get(agent);
|
|
456
|
+
if (!state.enabled || !state.alphaSearch) {
|
|
457
|
+
disposeAlphaToolForAgent(agent, registrations);
|
|
458
|
+
return false;
|
|
337
459
|
}
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
460
|
+
try {
|
|
461
|
+
const config = getConfig();
|
|
462
|
+
const active = selectedAgentRoute(agent);
|
|
463
|
+
const capability = verifiedAlphaCapabilityForRoute(ctx, active, config, capabilityStore);
|
|
464
|
+
if (!capability.usable) {
|
|
465
|
+
disposeAlphaToolForAgent(agent, registrations);
|
|
466
|
+
return false;
|
|
467
|
+
}
|
|
468
|
+
if (previous?.fingerprint === capability.fingerprint)
|
|
469
|
+
return true;
|
|
470
|
+
disposeAlphaToolForAgent(agent, registrations);
|
|
471
|
+
const scopedTools = scopedToolRuntime(agent);
|
|
472
|
+
if (!scopedTools)
|
|
473
|
+
return false;
|
|
474
|
+
// Alpha is route-bound; global registration would advertise a static record to other routes.
|
|
475
|
+
registrations.set(agent, {
|
|
476
|
+
fingerprint: capability.fingerprint,
|
|
477
|
+
dispose: scopedTools.register(createAlphaTool(ctx, state, getConfig, capabilityStore, refStore)),
|
|
478
|
+
});
|
|
479
|
+
return true;
|
|
480
|
+
}
|
|
481
|
+
catch (error) {
|
|
482
|
+
disposeAlphaToolForAgent(agent, registrations);
|
|
483
|
+
ctx.logger?.warn?.(`[lcx-codex] Alpha capability store unavailable: ${errorDetails(error).message ?? String(error)}`);
|
|
484
|
+
return false;
|
|
485
|
+
}
|
|
486
|
+
}
|
|
352
487
|
function disposeAlphaToolForAgent(agent, registrations) {
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
488
|
+
const registration = registrations.get(agent);
|
|
489
|
+
if (!registration)
|
|
490
|
+
return;
|
|
491
|
+
registration.dispose();
|
|
492
|
+
registrations.delete(agent);
|
|
357
493
|
}
|
|
358
|
-
|
|
359
494
|
function isDshCompactionDirective(message) {
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
return text.includes(COMPACTION_DIRECTIVE)
|
|
495
|
+
return (message?.role === "user" &&
|
|
496
|
+
message?.source?.kind === "plugin" &&
|
|
497
|
+
message?.source?.plugin === "dsh-compaction-basic");
|
|
364
498
|
}
|
|
365
499
|
function stripCompactionDirective(messages) {
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
500
|
+
if (messages.length === 0)
|
|
501
|
+
return [];
|
|
502
|
+
return isDshCompactionDirective(messages.at(-1))
|
|
503
|
+
? messages.slice(0, -1)
|
|
504
|
+
: [...messages];
|
|
505
|
+
}
|
|
506
|
+
function mergeMap(target, source) {
|
|
507
|
+
for (const [key, value] of source ?? [])
|
|
508
|
+
target.set(key, value);
|
|
509
|
+
}
|
|
510
|
+
async function serializeNativeAware(messages, route, routeConfig, ctx, options) {
|
|
511
|
+
const session = sessionFor(ctx, route.sessionId);
|
|
512
|
+
const imageSupport = await resolveModelImageSupport(ctx, route, options.signal);
|
|
513
|
+
const input = [];
|
|
514
|
+
const imageMap = new Map();
|
|
515
|
+
let nativeTools;
|
|
516
|
+
let nativeModel;
|
|
517
|
+
let grammarToolInputProperties;
|
|
518
|
+
let normal = [];
|
|
519
|
+
const serializeOptions = (imageMapOverride = undefined, extra = {}) => requestImageOptions(routeConfig, imageSupport, options.signal, imageMapOverride, {
|
|
520
|
+
route,
|
|
521
|
+
tools: options.tools,
|
|
522
|
+
responsesCompat: routeConfig.responsesCompat,
|
|
523
|
+
...extra,
|
|
524
|
+
});
|
|
525
|
+
const firstMessage = messages[0];
|
|
526
|
+
const systemHead = firstMessage?.role === "system" ? firstMessage : undefined;
|
|
527
|
+
const surfaceMessages = systemHead ? messages.slice(1) : messages;
|
|
528
|
+
const systemPrompt = systemHead?.content
|
|
529
|
+
.filter((block) => block.type === "text")
|
|
530
|
+
.map((block) => block.text)
|
|
531
|
+
.join("") || undefined;
|
|
532
|
+
const prelude = await serializeDshMessages([], ctx, serializeOptions(undefined, {
|
|
533
|
+
systemPrompt,
|
|
534
|
+
includeSystemPrompt: true,
|
|
535
|
+
}));
|
|
536
|
+
const ephemeralPreludeItemCount = prelude.input.length;
|
|
537
|
+
input.push(...prelude.input);
|
|
538
|
+
nativeTools = prelude.tools;
|
|
539
|
+
nativeModel = prelude.model;
|
|
540
|
+
grammarToolInputProperties = prelude.grammarToolInputProperties;
|
|
541
|
+
const flush = async () => {
|
|
542
|
+
if (!normal.length)
|
|
543
|
+
return;
|
|
544
|
+
const batch = normal;
|
|
545
|
+
normal = [];
|
|
546
|
+
const serialized = await serializeDshMessages(batch, ctx, serializeOptions());
|
|
547
|
+
nativeTools = serialized.tools ?? nativeTools;
|
|
548
|
+
nativeModel = serialized.model ?? nativeModel;
|
|
549
|
+
grammarToolInputProperties =
|
|
550
|
+
serialized.grammarToolInputProperties ?? grammarToolInputProperties;
|
|
551
|
+
input.push(...restoreGrokNativeReplay(serialized.input, batch, options.grokNativeReplayRoute));
|
|
552
|
+
mergeMap(imageMap, serialized.imageMap);
|
|
553
|
+
};
|
|
554
|
+
for (const message of surfaceMessages ?? []) {
|
|
555
|
+
assertSupportedCheckpointMessage(message);
|
|
556
|
+
const state = session
|
|
557
|
+
? checkpointStateForMessage(session, message)
|
|
558
|
+
: undefined;
|
|
559
|
+
if (state && session) {
|
|
560
|
+
const checkpointId = compactCheckpointId(message);
|
|
561
|
+
if (!checkpointId) {
|
|
562
|
+
normal.push(message);
|
|
563
|
+
continue;
|
|
564
|
+
}
|
|
565
|
+
await flush();
|
|
566
|
+
if (stateRouteCompatible(state, route, ctx)) {
|
|
567
|
+
const nativeOutput = state.nativeOutput;
|
|
568
|
+
const hydratedMap = new Map();
|
|
569
|
+
const hydrated = await hydrateNativeImageReferences(nativeOutput, ctx, requestImageOptions(routeConfig, imageSupport, options.signal, hydratedMap));
|
|
570
|
+
input.push(...responseInputItems(hydrated));
|
|
571
|
+
mergeMap(imageMap, hydratedMap);
|
|
412
572
|
}
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
573
|
+
else {
|
|
574
|
+
const portable = portableMessagesForCheckpoint(session, checkpointId, { maxChars: routeConfig.portableReplayMaxChars });
|
|
575
|
+
const serialized = await serializeDshMessages(portable, ctx, serializeOptions());
|
|
576
|
+
input.push(...serialized.input);
|
|
577
|
+
mergeMap(imageMap, serialized.imageMap);
|
|
578
|
+
}
|
|
579
|
+
continue;
|
|
419
580
|
}
|
|
420
|
-
|
|
421
|
-
const hydrated = await hydrateNativeImageReferences(nativeOutput, ctx, requestImageOptions(routeConfig, imageSupport, options.signal, hydratedMap))
|
|
422
|
-
input.push(...hydrated); mergeMap(imageMap, hydratedMap)
|
|
423
|
-
} else {
|
|
424
|
-
const portable = portableMessagesForCheckpoint(session, compactCheckpointId(message), { maxChars: routeConfig.portableReplayMaxChars })
|
|
425
|
-
const serialized = await serializeDshMessages(portable, ctx, serializeOptions())
|
|
426
|
-
input.push(...serialized.input); mergeMap(imageMap, serialized.imageMap)
|
|
427
|
-
}
|
|
428
|
-
continue
|
|
429
|
-
}
|
|
430
|
-
const legacyId = legacyV3Id(message)
|
|
431
|
-
if (legacyId) {
|
|
432
|
-
const legacy = loadLegacyRecord(routeConfig.legacyCheckpointPath, legacyId)
|
|
433
|
-
if (legacy) {
|
|
434
|
-
await flush()
|
|
435
|
-
const legacyItems = legacyRouteCompatible(legacy, route, ctx) ? legacy.nativeOutput : (legacy.portableHistory ?? [])
|
|
436
|
-
const hydratedMap = new Map()
|
|
437
|
-
const hydrated = await hydrateNativeImageReferences(legacyItems, ctx, requestImageOptions(routeConfig, imageSupport, options.signal, hydratedMap))
|
|
438
|
-
input.push(...hydrated); mergeMap(imageMap, hydratedMap)
|
|
439
|
-
continue
|
|
440
|
-
}
|
|
581
|
+
normal.push(message);
|
|
441
582
|
}
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
583
|
+
await flush();
|
|
584
|
+
if (!nativeModel)
|
|
585
|
+
throw Object.assign(new Error("LCX could not resolve the Pi Responses model descriptor"), { code: "LCX_RESPONSES_MODEL_UNAVAILABLE" });
|
|
586
|
+
return {
|
|
587
|
+
input,
|
|
588
|
+
ephemeralPreludeItemCount,
|
|
589
|
+
imageMap,
|
|
590
|
+
imageSupport,
|
|
591
|
+
tools: nativeTools,
|
|
592
|
+
model: nativeModel,
|
|
593
|
+
grammarToolInputProperties,
|
|
594
|
+
};
|
|
447
595
|
}
|
|
448
|
-
|
|
449
596
|
function fallbackEligible(error, signal) {
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
const
|
|
461
|
-
const
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
597
|
+
if (signal?.aborted)
|
|
598
|
+
return false;
|
|
599
|
+
const details = errorDetails(error);
|
|
600
|
+
if (details.name === "AbortError" || details.code === "LCX_ABORTED")
|
|
601
|
+
return false;
|
|
602
|
+
if (details.name === "TimeoutError")
|
|
603
|
+
return true;
|
|
604
|
+
return ["LCX_HTTP_RETRYABLE", "LCX_RETRY_EXHAUSTED"].includes(String(details.code ?? ""));
|
|
605
|
+
}
|
|
606
|
+
async function* remoteCompactionStream(options, routeConfig, ctx, next) {
|
|
607
|
+
const history = stripCompactionDirective(options.messages);
|
|
608
|
+
const route = currentRoute(options, routeConfig);
|
|
609
|
+
try {
|
|
610
|
+
const prepared = await serializeNativeAware(history, route, routeConfig, ctx, { signal: options.signal, tools: options.tools });
|
|
611
|
+
const cacheSessionId = promptCacheSessionId(route, routeConfig, ctx);
|
|
612
|
+
const headers = await authenticatedHeaders(ctx, routeConfig, cacheSessionId, cacheSessionId === undefined ? null : route.sessionId);
|
|
613
|
+
const generation = generationControlsFromSession(sessionFor(ctx, route.sessionId), route);
|
|
614
|
+
const result = await requestNativeCompaction({
|
|
615
|
+
baseURL: routeConfig.baseURL,
|
|
616
|
+
model: route.model,
|
|
617
|
+
modelDescriptor: prepared.model,
|
|
618
|
+
input: prepared.input,
|
|
619
|
+
tools: prepared.tools ?? options.tools,
|
|
620
|
+
promptCacheKey: promptCacheKey(route, routeConfig, ctx),
|
|
621
|
+
promptCacheRetention: promptCacheRetention(routeConfig),
|
|
622
|
+
cacheRetention: routeConfig.cacheRetention,
|
|
623
|
+
reasoningEffort: generation.reasoningEffort,
|
|
624
|
+
temperature: generation.temperature,
|
|
625
|
+
maxTokens: generation.maxTokens,
|
|
626
|
+
idempotencyKey: randomUUID(),
|
|
627
|
+
headers,
|
|
628
|
+
signal: options.signal,
|
|
629
|
+
timeoutMs: routeConfig.timeoutMs,
|
|
630
|
+
maxAttempts: routeConfig.maxAttempts,
|
|
631
|
+
maxResponseBytes: routeConfig.maxResponseBytes,
|
|
632
|
+
});
|
|
633
|
+
const session = sessionFor(ctx, route.sessionId);
|
|
634
|
+
if (session === undefined)
|
|
635
|
+
throw webError("Native compaction requires a live DSH session", "LCX_COMPACT_SESSION_UNAVAILABLE");
|
|
636
|
+
const block = createNativeCheckpointBlock({
|
|
637
|
+
session,
|
|
638
|
+
route,
|
|
639
|
+
result,
|
|
640
|
+
input: prepared.input,
|
|
641
|
+
ephemeralPreludeItemCount: prepared.ephemeralPreludeItemCount,
|
|
642
|
+
imageMap: prepared.imageMap,
|
|
643
|
+
retentionOptions: {
|
|
644
|
+
tokenBudget: routeConfig.nativeRetentionTokenBudget,
|
|
645
|
+
assistantTokenReserve: routeConfig.assistantRetentionTokenReserve,
|
|
646
|
+
assistantPerMessageTokenCap: routeConfig.assistantRetentionPerMessageTokenCap,
|
|
647
|
+
},
|
|
648
|
+
});
|
|
649
|
+
ctx.logger?.info?.(`[lcx-codex] native V2 compaction succeeded; retained ${block.retainedClientCount ?? 0} client + ${block.retainedAssistantCount ?? 0} assistant-visible item(s) (~${block.retainedEstimatedTokens ?? 0} tokens) with the opaque checkpoint`);
|
|
650
|
+
for (const chunk of nativeCheckpointChunks(block, result.usage))
|
|
651
|
+
yield chunk;
|
|
652
|
+
}
|
|
653
|
+
catch (error) {
|
|
654
|
+
const session = sessionFor(ctx, route.sessionId);
|
|
655
|
+
const hasExistingCheckpoint = messagesContainNativeCheckpoint(history, session);
|
|
656
|
+
const details = errorDetails(error);
|
|
657
|
+
const code = details.code ?? details.name ?? "ERROR";
|
|
658
|
+
const status = Number.isInteger(details.status)
|
|
659
|
+
? ` status=${details.status}`
|
|
660
|
+
: "";
|
|
661
|
+
const requestId = isRecord(error) && error.requestId
|
|
662
|
+
? ` requestId=${String(error.requestId)}`
|
|
663
|
+
: "";
|
|
664
|
+
const providerCode = isRecord(error) && error.providerCode
|
|
665
|
+
? ` providerCode=${String(error.providerCode)}`
|
|
666
|
+
: "";
|
|
667
|
+
const providerType = isRecord(error) && error.providerType
|
|
668
|
+
? ` providerType=${String(error.providerType)}`
|
|
669
|
+
: "";
|
|
670
|
+
const providerParam = isRecord(error) && error.providerParam
|
|
671
|
+
? ` providerParam=${String(error.providerParam)}`
|
|
672
|
+
: "";
|
|
673
|
+
ctx.logger?.warn?.(`[lcx-codex] native V2 compaction failed: code=${code}${status}${requestId}${providerCode}${providerType}${providerParam}`);
|
|
674
|
+
if (hasExistingCheckpoint || !fallbackEligible(error, options.signal))
|
|
675
|
+
throw error;
|
|
676
|
+
ctx.logger?.info?.("[lcx-codex] falling back to DSH basic compaction after allowlisted first-checkpoint native failure");
|
|
677
|
+
const stream = await next();
|
|
678
|
+
for await (const chunk of stream)
|
|
679
|
+
yield chunk;
|
|
680
|
+
}
|
|
681
|
+
}
|
|
682
|
+
function routedTargetForAgent(agent) {
|
|
683
|
+
const route = readAgentRouteState(agent);
|
|
684
|
+
const provider = stringValue(routeConfigValue(route.requestConfig, "provider") ??
|
|
685
|
+
routeConfigValue(route.options, "provider"), "");
|
|
686
|
+
const model = stringValue(routeConfigValue(route.requestConfig, "model") ??
|
|
687
|
+
routeConfigValue(route.options, "model"), "");
|
|
688
|
+
return provider && model ? { provider, model } : undefined;
|
|
689
|
+
}
|
|
531
690
|
export function compactionPressureBand(totalTokens, contextWindow, policy) {
|
|
532
|
-
|
|
533
|
-
|
|
691
|
+
const ratioPercent = (totalTokens / contextWindow) * 100;
|
|
692
|
+
return {
|
|
693
|
+
ratioPercent,
|
|
694
|
+
band: ratioPercent < policy.auto
|
|
695
|
+
? "below"
|
|
696
|
+
: ratioPercent < policy.emergency
|
|
697
|
+
? "native"
|
|
698
|
+
: "emergency",
|
|
699
|
+
};
|
|
534
700
|
}
|
|
535
|
-
|
|
536
701
|
function adjustedCompactionConfig(config, target, thresholdRatio) {
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
702
|
+
if (!isRecord(config))
|
|
703
|
+
return config;
|
|
704
|
+
const modelPolicies = Array.isArray(config.modelPolicies)
|
|
705
|
+
? config.modelPolicies.map((policy) => isRecord(policy) &&
|
|
706
|
+
policy.provider === target.provider &&
|
|
707
|
+
policy.model === target.model
|
|
708
|
+
? { ...policy, thresholdRatio }
|
|
709
|
+
: policy)
|
|
710
|
+
: config.modelPolicies;
|
|
711
|
+
return {
|
|
712
|
+
...config,
|
|
713
|
+
thresholdRatio,
|
|
714
|
+
...(modelPolicies === undefined ? {} : { modelPolicies }),
|
|
715
|
+
};
|
|
542
716
|
}
|
|
543
|
-
|
|
544
717
|
function combinedAbortSignal(primary, lifecycle) {
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
}
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
718
|
+
return primary === lifecycle ? primary : AbortSignal.any([primary, lifecycle]);
|
|
719
|
+
}
|
|
720
|
+
function patchCompactionPressureService(compactionValue, state, getConfig, ctx, records) {
|
|
721
|
+
const candidate = compactionPatchCandidate(compactionValue, records);
|
|
722
|
+
if (!candidate)
|
|
723
|
+
return false;
|
|
724
|
+
const mutex = new ServiceMutex();
|
|
725
|
+
const lifecycle = new AbortController();
|
|
726
|
+
return installCompactionPatch(records, candidate, mutex, lifecycle, async (agent, trigger, signal, callOriginal) => {
|
|
727
|
+
const activeSignal = combinedAbortSignal(signal, lifecycle.signal);
|
|
728
|
+
return mutex.run(activeSignal, async () => {
|
|
729
|
+
if (trigger !== "pressure" || !state.enabled)
|
|
730
|
+
return callOriginal(activeSignal);
|
|
731
|
+
const config = getConfig();
|
|
732
|
+
const target = routedTargetForAgent(agent);
|
|
733
|
+
if (!target || !resolveResponsesRouteConfig(ctx, target, config))
|
|
734
|
+
return callOriginal(activeSignal);
|
|
735
|
+
const session = sessionFromAgent(agent);
|
|
736
|
+
const tokenMeter = resolveScopedService(agent, "tokenMeter") ??
|
|
737
|
+
resolveContextService(ctx, "tokenMeter");
|
|
738
|
+
if (!session || tokenMeter === undefined)
|
|
739
|
+
return callOriginal(activeSignal);
|
|
740
|
+
let contextWindow;
|
|
741
|
+
try {
|
|
742
|
+
contextWindow = (await ctx.llm.resolveModelInfo(target.provider, target.model, activeSignal)).context?.contextWindow;
|
|
743
|
+
}
|
|
744
|
+
catch {
|
|
745
|
+
return callOriginal(activeSignal);
|
|
746
|
+
}
|
|
747
|
+
const totalTokens = tokenMeterTotal(tokenMeter, session);
|
|
748
|
+
if (contextWindow === undefined ||
|
|
749
|
+
contextWindow <= 0 ||
|
|
750
|
+
totalTokens === undefined)
|
|
751
|
+
return callOriginal(activeSignal);
|
|
752
|
+
const auto = AUTO_COMPACTION_THRESHOLD_PERCENT;
|
|
753
|
+
const emergency = EMERGENCY_PRUNE_THRESHOLD_PERCENT;
|
|
754
|
+
const pressure = compactionPressureBand(totalTokens, contextWindow, {
|
|
755
|
+
auto,
|
|
756
|
+
emergency,
|
|
757
|
+
});
|
|
758
|
+
if (pressure.band === "below")
|
|
759
|
+
return null;
|
|
760
|
+
const prunerState = toolResultPrunerState(resolveAgentService(ctx, agent, "toolResultPruner"));
|
|
761
|
+
const configState = compactionConfigState(compactionValue);
|
|
762
|
+
const nativeFirst = pressure.band === "native";
|
|
763
|
+
const prunerPatch = nativeFirst
|
|
764
|
+
? patchToolResultPruner(prunerState, () => ({ pruned: [], charsRemoved: 0 }))
|
|
765
|
+
: undefined;
|
|
766
|
+
const configPatch = patchCompactionConfig(configState, (originalConfig) => adjustedCompactionConfig(originalConfig, target, auto / 100));
|
|
767
|
+
ctx.logger?.info?.(`[lcx-codex] auto pressure ${pressure.ratioPercent.toFixed(1)}%: ${nativeFirst ? "Native V2 first" : "emergency DSH prune allowed"} (native ${auto}%, emergency ${emergency}%)`);
|
|
768
|
+
try {
|
|
769
|
+
return await callOriginal(activeSignal);
|
|
770
|
+
}
|
|
771
|
+
finally {
|
|
772
|
+
restoreCompactionConfig(configPatch);
|
|
773
|
+
restoreToolResultPruner(prunerPatch);
|
|
774
|
+
}
|
|
775
|
+
});
|
|
776
|
+
});
|
|
777
|
+
}
|
|
778
|
+
function patchCompactionPressureForAgent(agent, state, getConfig, ctx, records) {
|
|
779
|
+
return patchCompactionPressureService(resolveAgentService(ctx, agent, "compaction"), state, getConfig, ctx, records);
|
|
780
|
+
}
|
|
600
781
|
async function restoreCompactionPressure(records) {
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
function
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
return state.enabled && state.webSearch ? timeoutMs : undefined
|
|
614
|
-
}
|
|
615
|
-
|
|
616
|
-
function messagesContainNativeCheckpoint(messages, session) { return Boolean(session && (messages ?? []).some((message) => checkpointStateForMessage(session, message))) }
|
|
617
|
-
function messagesContainLegacyCheckpoint(messages) { return (messages ?? []).some((message) => Boolean(legacyCheckpointId(message))) }
|
|
618
|
-
|
|
782
|
+
const reason = new Error("lcx-codex pressure coordination is shutting down");
|
|
783
|
+
const entries = [...records.values()];
|
|
784
|
+
for (const record of entries) {
|
|
785
|
+
if (!record.lifecycle.signal.aborted)
|
|
786
|
+
record.lifecycle.abort(reason);
|
|
787
|
+
}
|
|
788
|
+
await Promise.allSettled(entries.map((record) => record.mutex.close(reason)));
|
|
789
|
+
restoreCompactionPatches(records, entries);
|
|
790
|
+
}
|
|
791
|
+
function messagesContainNativeCheckpoint(messages, session) {
|
|
792
|
+
return session !== undefined && messages.some((message) => checkpointStateForMessage(session, message));
|
|
793
|
+
}
|
|
619
794
|
function inputHasNativeState(input) {
|
|
620
|
-
|
|
795
|
+
return input.some((item) => isRecord(item) && item.type === "compaction");
|
|
621
796
|
}
|
|
622
|
-
|
|
623
797
|
async function* managedResponsesStream(options, routeConfig, ctx) {
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
}
|
|
661
|
-
|
|
662
|
-
async function* unavailableManagedRouteStream(options) {
|
|
663
|
-
yield managedFailureChunk(Object.assign(new Error('LCX is enabled but the selected DSH route cannot be resolved as an authenticated OpenAI Responses wire route'), { code: 'LCX_RESPONSES_ROUTE_UNAVAILABLE' }), options.signal)
|
|
664
|
-
}
|
|
665
|
-
|
|
666
|
-
function installInjected(ctx, configInput = {}) {
|
|
667
|
-
const baseConfig = normalizeConfig(configInput)
|
|
668
|
-
let runtimeConfig = baseConfig
|
|
669
|
-
const state = { enabled: false, webSearch: false, advancedHostedSearch: false, alphaSearch: false, remoteCompaction: false, fallbackToBasicCompaction: true, autoCompaction: true, webSearchTimeoutSeconds: baseConfig.webSearchTimeoutMs / 1000, autoCompactionThresholdPercent: baseConfig.autoCompactionThresholdPercent, emergencyPruneThresholdPercent: baseConfig.emergencyPruneThresholdPercent }
|
|
670
|
-
const originalSearchProvider = readWebSearchProvider(ctx)
|
|
671
|
-
let warnedWebSelection = false
|
|
672
|
-
const provider = new LcxResponsesSearchProvider(ctx, () => runtimeConfig, () => state.enabled && state.webSearch)
|
|
673
|
-
ctx.web.registerSearchProvider(provider)
|
|
674
|
-
const tools = contextService(ctx, 'tools')
|
|
675
|
-
let disposeAdvanced
|
|
676
|
-
const capabilityStore = new AlphaCapabilityStore(baseConfig.alphaCapabilityPath)
|
|
677
|
-
const refStore = new AlphaRefStore(baseConfig.alphaRefPath)
|
|
678
|
-
const alphaAgents = new Set()
|
|
679
|
-
const alphaToolRegistrations = new Map()
|
|
680
|
-
const compactionPatchRecords = new Map()
|
|
681
|
-
const patchedWebSearchDefinitions = new Map()
|
|
682
|
-
const requestHeaders = new Map()
|
|
683
|
-
const seedRequestHeader = (session) => updateRequestHeaderCache(requestHeaders, session, { type: 'compaction/start' })
|
|
684
|
-
for (const session of sessionsService(ctx)?.list?.() ?? []) seedRequestHeader(session)
|
|
685
|
-
ctx.on('session/created', (session) => {
|
|
686
|
-
seedRequestHeader(session)
|
|
687
|
-
}, { global: true })
|
|
688
|
-
ctx.on('session/disposed', (session) => {
|
|
689
|
-
requestHeaders.delete(String(session?.id ?? ''))
|
|
690
|
-
for (const agent of alphaAgents) if (agent?.session === session) {
|
|
691
|
-
disposeAlphaToolForAgent(agent, alphaToolRegistrations)
|
|
692
|
-
alphaAgents.delete(agent)
|
|
798
|
+
const route = currentRoute(options, routeConfig);
|
|
799
|
+
try {
|
|
800
|
+
if (options.stop !== undefined)
|
|
801
|
+
throw Object.assign(new Error("LCX Responses does not support GenerateOptions.stop"), { code: "LCX_RESPONSES_UNSUPPORTED_OPTION" });
|
|
802
|
+
const prepared = await serializeNativeAware(options.messages, route, routeConfig, ctx, { signal: options.signal, tools: options.tools });
|
|
803
|
+
const cacheSessionId = promptCacheSessionId(route, routeConfig, ctx);
|
|
804
|
+
const headers = await authenticatedHeaders(ctx, routeConfig, cacheSessionId, cacheSessionId === undefined ? null : route.sessionId);
|
|
805
|
+
const body = buildResponsesBody({
|
|
806
|
+
model: prepared.model,
|
|
807
|
+
input: prepared.input,
|
|
808
|
+
tools: prepared.tools ?? options.tools,
|
|
809
|
+
sessionId: cacheSessionId,
|
|
810
|
+
promptCacheKey: promptCacheKey(route, routeConfig, ctx),
|
|
811
|
+
promptCacheRetention: promptCacheRetention(routeConfig),
|
|
812
|
+
cacheRetention: routeConfig.cacheRetention,
|
|
813
|
+
reasoningEffort: options.reasoningEffort,
|
|
814
|
+
temperature: options.temperature,
|
|
815
|
+
maxTokens: options.maxTokens,
|
|
816
|
+
});
|
|
817
|
+
const nativeReplay = inputHasNativeState(prepared.input);
|
|
818
|
+
if (nativeReplay) {
|
|
819
|
+
body.tool_choice = "auto";
|
|
820
|
+
body.parallel_tool_calls = true;
|
|
821
|
+
}
|
|
822
|
+
yield* streamResponsesRequest({
|
|
823
|
+
baseURL: routeConfig.baseURL,
|
|
824
|
+
provider: route.provider,
|
|
825
|
+
model: route.model,
|
|
826
|
+
piModel: prepared.model,
|
|
827
|
+
body,
|
|
828
|
+
grammarToolInputProperties: prepared.grammarToolInputProperties,
|
|
829
|
+
headers: nativeReplay ? mergeFeatureHeader(headers) : headers,
|
|
830
|
+
signal: options.signal,
|
|
831
|
+
timeoutMs: routeConfig.timeoutMs,
|
|
832
|
+
maxAttempts: 1,
|
|
833
|
+
maxResponseBytes: routeConfig.maxResponseBytes,
|
|
834
|
+
});
|
|
693
835
|
}
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
updateRequestHeaderCache(requestHeaders, session, event)
|
|
697
|
-
if (event?.type === 'request/header') for (const agent of alphaAgents) if (agent?.session === session) {
|
|
698
|
-
syncAlphaToolForAgent(ctx, agent, state, () => runtimeConfig, capabilityStore, refStore, alphaToolRegistrations)
|
|
836
|
+
catch (error) {
|
|
837
|
+
yield managedFailureChunk(error, options.signal);
|
|
699
838
|
}
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
839
|
+
}
|
|
840
|
+
async function* managedGrokNativeSearchStream(options, routeConfig, nativeSearch, ctx) {
|
|
841
|
+
const route = currentRoute(options, routeConfig);
|
|
842
|
+
const nativeReplayRoute = grokReplayRoute(route, routeConfig);
|
|
843
|
+
try {
|
|
844
|
+
if (options.stop !== undefined)
|
|
845
|
+
throw Object.assign(new Error("LCX Responses does not support GenerateOptions.stop"), { code: "LCX_RESPONSES_UNSUPPORTED_OPTION" });
|
|
846
|
+
const visibleTools = grokVisibleFunctionTools(options.tools, nativeSearch);
|
|
847
|
+
const prepared = await serializeNativeAware(options.messages, route, routeConfig, ctx, {
|
|
848
|
+
signal: options.signal,
|
|
849
|
+
tools: visibleTools,
|
|
850
|
+
grokNativeReplayRoute: nativeReplayRoute,
|
|
851
|
+
});
|
|
852
|
+
const cacheSessionId = grokPromptCacheSessionId(route, routeConfig);
|
|
853
|
+
const headers = await authenticatedGrokHeaders(ctx, routeConfig, cacheSessionId);
|
|
854
|
+
const model = {
|
|
855
|
+
...prepared.model,
|
|
856
|
+
...routeConfig.modelDefaults,
|
|
857
|
+
...routeConfig.modelControls,
|
|
858
|
+
id: route.model,
|
|
859
|
+
provider: route.provider,
|
|
860
|
+
baseUrl: routeConfig.baseURL,
|
|
861
|
+
api: "openai-responses",
|
|
862
|
+
};
|
|
863
|
+
const effectiveReasoning = options.reasoningEffort ?? routeConfig.profileReasoning;
|
|
864
|
+
if (effectiveReasoning !== undefined &&
|
|
865
|
+
!getSupportedThinkingLevels(model).some((level) => level === effectiveReasoning))
|
|
866
|
+
throw Object.assign(new Error(`Grok route does not support reasoning effort "${String(effectiveReasoning)}"`), { code: "LCX_RESPONSES_UNSUPPORTED_OPTION" });
|
|
867
|
+
const body = buildResponsesBody({
|
|
868
|
+
model,
|
|
869
|
+
input: prepared.input,
|
|
870
|
+
tools: grokWireTools(prepared.tools ?? visibleTools, nativeSearch),
|
|
871
|
+
sessionId: cacheSessionId,
|
|
872
|
+
promptCacheRetention: promptCacheRetention(routeConfig),
|
|
873
|
+
cacheRetention: routeConfig.cacheRetention,
|
|
874
|
+
reasoningEffort: effectiveReasoning,
|
|
875
|
+
temperature: options.temperature,
|
|
876
|
+
maxTokens: options.maxTokens,
|
|
877
|
+
});
|
|
878
|
+
if (nativeSearch.web) {
|
|
879
|
+
const include = new Set(Array.isArray(body.include) ? body.include : []);
|
|
880
|
+
include.add("web_search_call.action.sources");
|
|
881
|
+
body.include = [...include];
|
|
882
|
+
}
|
|
883
|
+
yield* streamResponsesRequest({
|
|
884
|
+
baseURL: routeConfig.baseURL,
|
|
885
|
+
provider: route.provider,
|
|
886
|
+
model: route.model,
|
|
887
|
+
piModel: model,
|
|
888
|
+
body,
|
|
889
|
+
grammarToolInputProperties: prepared.grammarToolInputProperties,
|
|
890
|
+
headers,
|
|
891
|
+
signal: options.signal,
|
|
892
|
+
timeoutMs: routeConfig.timeoutMs,
|
|
893
|
+
applyDefaultTimeout: false,
|
|
894
|
+
streamIdleTimeoutMs: routeConfig.streamIdleTimeoutMs,
|
|
895
|
+
maxAttempts: 1,
|
|
896
|
+
maxResponseBytes: routeConfig.maxResponseBytes,
|
|
897
|
+
serverToolTypes: GROK_NATIVE_SERVER_TOOL_TYPES,
|
|
898
|
+
nativeReplayRoute,
|
|
899
|
+
onServerToolUsage(usage) {
|
|
900
|
+
ctx.logger?.info?.(`[lcx-codex] Grok native search used ${usage.total} server-side tool call(s) (web=${usage.webSearchCalls}, x=${usage.xSearchCalls})`);
|
|
901
|
+
},
|
|
902
|
+
});
|
|
713
903
|
}
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
let source = () => ({ ...baseConfig, ...state })
|
|
717
|
-
installSettingsSection(ctx, SETTINGS_NS, SettingsSchema, {
|
|
718
|
-
enabled: false, webSearch: false, advancedHostedSearch: false, alphaSearch: false, remoteCompaction: false, fallbackToBasicCompaction: true, autoCompaction: true,
|
|
719
|
-
webSearchTimeoutSeconds: baseConfig.webSearchTimeoutMs / 1000,
|
|
720
|
-
autoCompactionThresholdPercent: baseConfig.autoCompactionThresholdPercent,
|
|
721
|
-
emergencyPruneThresholdPercent: baseConfig.emergencyPruneThresholdPercent,
|
|
722
|
-
provider: baseConfig.provider, baseURL: baseConfig.baseURL, apiKeyEnv: baseConfig.apiKeyEnv, model: baseConfig.model,
|
|
723
|
-
}, {
|
|
724
|
-
setSource: (current) => { source = current },
|
|
725
|
-
onChange: () => {
|
|
726
|
-
const value = source()
|
|
727
|
-
state.enabled = Boolean(value.enabled); state.webSearch = Boolean(value.webSearch); state.advancedHostedSearch = Boolean(value.advancedHostedSearch); state.alphaSearch = Boolean(value.alphaSearch); state.remoteCompaction = Boolean(value.remoteCompaction)
|
|
728
|
-
state.fallbackToBasicCompaction = value.fallbackToBasicCompaction !== false; state.autoCompaction = value.autoCompaction !== false
|
|
729
|
-
state.webSearchTimeoutSeconds = Number.isFinite(value.webSearchTimeoutSeconds) ? value.webSearchTimeoutSeconds : baseConfig.webSearchTimeoutMs / 1000
|
|
730
|
-
state.autoCompactionThresholdPercent = clampPercent(value.autoCompactionThresholdPercent, baseConfig.autoCompactionThresholdPercent, 85, 95)
|
|
731
|
-
state.emergencyPruneThresholdPercent = clampPercent(value.emergencyPruneThresholdPercent, baseConfig.emergencyPruneThresholdPercent, 90, 99)
|
|
732
|
-
runtimeConfig = normalizeConfig({ ...baseConfig, provider: value.provider ?? baseConfig.provider, baseURL: value.baseURL ?? baseConfig.baseURL, apiKeyEnv: value.apiKeyEnv ?? baseConfig.apiKeyEnv, model: value.model ?? baseConfig.model })
|
|
733
|
-
refreshTools(); refreshVisibleWebSearchTimeouts(patchedWebSearchDefinitions, visibleWebSearchTimeout(state, () => runtimeConfig))
|
|
734
|
-
},
|
|
735
|
-
})
|
|
736
|
-
try {
|
|
737
|
-
const value = source()
|
|
738
|
-
Object.assign(state, { enabled: Boolean(value.enabled), webSearch: Boolean(value.webSearch), advancedHostedSearch: Boolean(value.advancedHostedSearch), alphaSearch: Boolean(value.alphaSearch), remoteCompaction: Boolean(value.remoteCompaction), fallbackToBasicCompaction: value.fallbackToBasicCompaction !== false, autoCompaction: value.autoCompaction !== false, webSearchTimeoutSeconds: Number.isFinite(value.webSearchTimeoutSeconds) ? value.webSearchTimeoutSeconds : baseConfig.webSearchTimeoutMs / 1000, autoCompactionThresholdPercent: clampPercent(value.autoCompactionThresholdPercent, baseConfig.autoCompactionThresholdPercent, 85, 95), emergencyPruneThresholdPercent: clampPercent(value.emergencyPruneThresholdPercent, baseConfig.emergencyPruneThresholdPercent, 90, 99) })
|
|
739
|
-
runtimeConfig = normalizeConfig({ ...baseConfig, provider: value.provider ?? baseConfig.provider, baseURL: value.baseURL ?? baseConfig.baseURL, apiKeyEnv: value.apiKeyEnv ?? baseConfig.apiKeyEnv, model: value.model ?? baseConfig.model })
|
|
740
|
-
} catch {}
|
|
741
|
-
refreshTools()
|
|
742
|
-
ctx.inject(['compaction'], compactionCtx => {
|
|
743
|
-
patchCompactionPressureService(resolveContextService(compactionCtx, 'compaction'), state, () => runtimeConfig, ctx, compactionPatchRecords, requestHeaders)
|
|
744
|
-
})
|
|
745
|
-
|
|
746
|
-
ctx.on('tools/execute', async (exec, next) => {
|
|
747
|
-
if (!state.enabled || !state.webSearch || exec?.name !== 'web_search') return next()
|
|
748
|
-
const active = activeAgentRoute(exec, runtimeConfig)
|
|
749
|
-
return hostedSearchRouteContext.run(active, () => next())
|
|
750
|
-
})
|
|
751
|
-
|
|
752
|
-
ctx.on('agent/created', ({ agent }) => {
|
|
753
|
-
if (!agent) return
|
|
754
|
-
alphaAgents.add(agent)
|
|
755
|
-
syncAlphaToolForAgent(ctx, agent, state, () => runtimeConfig, capabilityStore, refStore, alphaToolRegistrations)
|
|
756
|
-
const installed = patchCompactionPressureForAgent(agent, state, () => runtimeConfig, ctx, compactionPatchRecords, requestHeaders)
|
|
757
|
-
if (installed) ctx.logger?.info?.('[lcx-codex] pressure coordination installed through AgentPresets service resolver')
|
|
758
|
-
}, { global: true })
|
|
759
|
-
|
|
760
|
-
ctx.on('agent/status', ({ agent, status }) => {
|
|
761
|
-
if (status !== 'running' || !agent) return
|
|
762
|
-
alphaAgents.add(agent)
|
|
763
|
-
syncAlphaToolForAgent(ctx, agent, state, () => runtimeConfig, capabilityStore, refStore, alphaToolRegistrations)
|
|
764
|
-
const installed = patchCompactionPressureForAgent(agent, state, () => runtimeConfig, ctx, compactionPatchRecords, requestHeaders)
|
|
765
|
-
if (installed) ctx.logger?.info?.('[lcx-codex] pressure coordination installed through AgentPresets service resolver')
|
|
766
|
-
patchVisibleWebSearchTimeout(agent, () => visibleWebSearchTimeout(state, () => runtimeConfig), patchedWebSearchDefinitions)
|
|
767
|
-
}, { global: true })
|
|
768
|
-
|
|
769
|
-
ctx.on('llm/stream', (options, next) => {
|
|
770
|
-
if (!state.enabled || options.purpose === 'session-title') return next()
|
|
771
|
-
const routeConfig = resolveResponsesRouteConfig(ctx, options, runtimeConfig)
|
|
772
|
-
if (options.purpose === 'compaction') {
|
|
773
|
-
if (!routeConfig) return unavailableManagedRouteStream(options)
|
|
774
|
-
return remoteCompactionStream(options, routeConfig, state, ctx, next, requestHeaders)
|
|
904
|
+
catch (error) {
|
|
905
|
+
yield managedFailureChunk(error, options.signal);
|
|
775
906
|
}
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
907
|
+
}
|
|
908
|
+
function isGptLifecycleTarget(options) {
|
|
909
|
+
return /^gpt-/iu.test(String(options.model ?? ""));
|
|
910
|
+
}
|
|
911
|
+
async function* unavailableManagedRouteStream(options) {
|
|
912
|
+
yield managedFailureChunk(Object.assign(new Error("LCX is enabled but the selected DSH route cannot be resolved as an authenticated OpenAI Responses wire route"), { code: "LCX_RESPONSES_ROUTE_UNAVAILABLE" }), options.signal);
|
|
913
|
+
}
|
|
914
|
+
function installInjected(ctx, configInput = {}) {
|
|
915
|
+
const baseConfig = normalizeConfig(configInput);
|
|
916
|
+
let runtimeConfig = baseConfig;
|
|
917
|
+
const state = {
|
|
918
|
+
enabled: false,
|
|
919
|
+
webSearch: false,
|
|
920
|
+
advancedHostedSearch: false,
|
|
921
|
+
alphaSearch: false,
|
|
922
|
+
grokNativeWebSearch: false,
|
|
923
|
+
grokNativeXSearch: false,
|
|
924
|
+
};
|
|
925
|
+
const provider = new LcxResponsesSearchProvider(ctx, () => runtimeConfig, () => state.enabled && state.webSearch);
|
|
926
|
+
const capabilityStore = new AlphaCapabilityStore(baseConfig.alphaCapabilityPath);
|
|
927
|
+
const refStore = new AlphaRefStore(baseConfig.alphaRefPath);
|
|
928
|
+
const managedAgents = new Set();
|
|
929
|
+
const gptToolRegistrations = new Map();
|
|
930
|
+
const alphaToolRegistrations = new Map();
|
|
931
|
+
const compactionPatchRecords = new Map();
|
|
932
|
+
const syncAgentTools = (agent) => {
|
|
933
|
+
syncGptToolsForAgent(ctx, agent, state, () => runtimeConfig, provider, gptToolRegistrations);
|
|
934
|
+
syncAlphaToolForAgent(ctx, agent, state, () => runtimeConfig, capabilityStore, refStore, alphaToolRegistrations);
|
|
935
|
+
};
|
|
936
|
+
const refreshTools = () => {
|
|
937
|
+
for (const agent of managedAgents)
|
|
938
|
+
syncAgentTools(agent);
|
|
939
|
+
};
|
|
940
|
+
ctx.on("session/disposed", (session) => {
|
|
941
|
+
for (const agent of managedAgents)
|
|
942
|
+
if (agentUsesSession(agent, session)) {
|
|
943
|
+
disposeGptToolsForAgent(agent, gptToolRegistrations);
|
|
944
|
+
disposeAlphaToolForAgent(agent, alphaToolRegistrations);
|
|
945
|
+
managedAgents.delete(agent);
|
|
946
|
+
}
|
|
947
|
+
}, { global: true });
|
|
948
|
+
ctx.on("session/event", (session, event) => {
|
|
949
|
+
if (event.type === "request/header")
|
|
950
|
+
for (const agent of managedAgents)
|
|
951
|
+
if (agentUsesSession(agent, session))
|
|
952
|
+
syncAgentTools(agent);
|
|
953
|
+
}, { global: true });
|
|
954
|
+
const settingsEntry = {
|
|
955
|
+
enabled: false,
|
|
956
|
+
webSearch: false,
|
|
957
|
+
advancedHostedSearch: false,
|
|
958
|
+
alphaSearch: false,
|
|
959
|
+
grokNativeWebSearch: false,
|
|
960
|
+
grokNativeXSearch: false,
|
|
961
|
+
};
|
|
962
|
+
let source = () => settingsEntry;
|
|
963
|
+
ctx.settings.installSection(ctx, SETTINGS_NS, SettingsSchema, settingsEntry, {
|
|
964
|
+
setSource(current) {
|
|
965
|
+
source = current;
|
|
966
|
+
},
|
|
967
|
+
onChange() {
|
|
968
|
+
const value = source();
|
|
969
|
+
state.enabled = value.enabled;
|
|
970
|
+
state.webSearch = value.webSearch;
|
|
971
|
+
state.advancedHostedSearch = value.advancedHostedSearch;
|
|
972
|
+
state.alphaSearch = value.alphaSearch;
|
|
973
|
+
state.grokNativeWebSearch = value.grokNativeWebSearch;
|
|
974
|
+
state.grokNativeXSearch = value.grokNativeXSearch;
|
|
975
|
+
runtimeConfig = baseConfig;
|
|
976
|
+
refreshTools();
|
|
977
|
+
},
|
|
978
|
+
});
|
|
979
|
+
try {
|
|
980
|
+
const value = source();
|
|
981
|
+
Object.assign(state, {
|
|
982
|
+
enabled: Boolean(value.enabled),
|
|
983
|
+
webSearch: Boolean(value.webSearch),
|
|
984
|
+
advancedHostedSearch: Boolean(value.advancedHostedSearch),
|
|
985
|
+
alphaSearch: Boolean(value.alphaSearch),
|
|
986
|
+
grokNativeWebSearch: Boolean(value.grokNativeWebSearch),
|
|
987
|
+
grokNativeXSearch: Boolean(value.grokNativeXSearch),
|
|
988
|
+
});
|
|
989
|
+
runtimeConfig = baseConfig;
|
|
990
|
+
}
|
|
991
|
+
catch { }
|
|
992
|
+
refreshTools();
|
|
993
|
+
ctx.inject(["compaction"], (compactionCtx) => {
|
|
994
|
+
patchCompactionPressureService(resolveContextService(compactionCtx, "compaction"), state, () => runtimeConfig, ctx, compactionPatchRecords);
|
|
995
|
+
});
|
|
996
|
+
ctx.on("agent/created", ({ agent }) => {
|
|
997
|
+
if (agent === null || typeof agent !== "object")
|
|
998
|
+
return;
|
|
999
|
+
managedAgents.add(agent);
|
|
1000
|
+
syncAgentTools(agent);
|
|
1001
|
+
const installed = patchCompactionPressureForAgent(agent, state, () => runtimeConfig, ctx, compactionPatchRecords);
|
|
1002
|
+
if (installed)
|
|
1003
|
+
ctx.logger?.info?.("[lcx-codex] pressure coordination installed through AgentPresets service resolver");
|
|
1004
|
+
}, { global: true });
|
|
1005
|
+
ctx.on("agent/status", ({ agent, status }) => {
|
|
1006
|
+
if (status !== "running" ||
|
|
1007
|
+
agent === null ||
|
|
1008
|
+
typeof agent !== "object")
|
|
1009
|
+
return;
|
|
1010
|
+
managedAgents.add(agent);
|
|
1011
|
+
syncAgentTools(agent);
|
|
1012
|
+
const installed = patchCompactionPressureForAgent(agent, state, () => runtimeConfig, ctx, compactionPatchRecords);
|
|
1013
|
+
if (installed)
|
|
1014
|
+
ctx.logger?.info?.("[lcx-codex] pressure coordination installed through AgentPresets service resolver");
|
|
1015
|
+
}, { global: true });
|
|
1016
|
+
ctx.on("llm/stream", (options, next) => {
|
|
1017
|
+
if (options.purpose === "session-title")
|
|
1018
|
+
return next();
|
|
1019
|
+
const grokNativeSearch = {
|
|
1020
|
+
web: state.grokNativeWebSearch,
|
|
1021
|
+
x: state.grokNativeXSearch,
|
|
1022
|
+
};
|
|
1023
|
+
if (options.purpose === undefined && grokNativeSearchEnabled(grokNativeSearch)) {
|
|
1024
|
+
const grokRoute = resolveGrokResponsesRouteConfig(ctx, options, runtimeConfig);
|
|
1025
|
+
if (grokRoute)
|
|
1026
|
+
return managedGrokNativeSearchStream(options, routeWithPolicies(grokRoute, runtimeConfig), grokNativeSearch, ctx);
|
|
1027
|
+
}
|
|
1028
|
+
if (!state.enabled || !isGptLifecycleTarget(options))
|
|
1029
|
+
return next();
|
|
1030
|
+
const routeConfig = resolveResponsesRouteConfig(ctx, options, runtimeConfig);
|
|
1031
|
+
if (options.purpose === "compaction") {
|
|
1032
|
+
if (!routeConfig)
|
|
1033
|
+
return unavailableManagedRouteStream(options);
|
|
1034
|
+
return remoteCompactionStream(options, routeWithPolicies(routeConfig, runtimeConfig), ctx, next);
|
|
1035
|
+
}
|
|
1036
|
+
if (!routeConfig)
|
|
1037
|
+
return unavailableManagedRouteStream(options);
|
|
1038
|
+
return managedResponsesStream(options, routeWithPolicies(routeConfig, runtimeConfig), ctx);
|
|
1039
|
+
});
|
|
1040
|
+
ctx.effect?.(() => async () => {
|
|
1041
|
+
for (const agent of managedAgents) {
|
|
1042
|
+
disposeGptToolsForAgent(agent, gptToolRegistrations);
|
|
1043
|
+
disposeAlphaToolForAgent(agent, alphaToolRegistrations);
|
|
1044
|
+
}
|
|
1045
|
+
managedAgents.clear();
|
|
1046
|
+
await restoreCompactionPressure(compactionPatchRecords);
|
|
1047
|
+
}, "lcx-codex cleanup");
|
|
1048
|
+
}
|
|
791
1049
|
export function apply(ctx, configInput = {}) {
|
|
792
|
-
|
|
1050
|
+
return installInjected(ctx, configInput);
|
|
793
1051
|
}
|
|
794
|
-
|
|
795
|
-
apply.
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
export default apply
|
|
1052
|
+
apply.inject = inject;
|
|
1053
|
+
apply.Config = Config;
|
|
1054
|
+
export default apply;
|