dsh-lcx-codex 0.4.3-pre.4 → 0.4.3
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 +68 -126
- package/THIRD_PARTY_NOTICES.md +64 -0
- package/lib/auxiliary-usage.js +63 -0
- package/lib/client.js +1363 -295
- package/lib/dsh-compat.js +80 -18
- package/lib/dsh-responses.js +75 -8
- package/lib/grok-native-search.js +151 -79
- package/lib/index.js +159 -101
- package/lib/invocation-policy-scope.js +261 -0
- package/lib/json-store.js +11 -4
- package/lib/pi-responses-runtime.js +1571 -0
- package/lib/responses-request.js +1 -1
- package/lib/responses-stream.js +152 -84
- package/lib/route.js +17 -3
- package/lib/search-accounting.js +86 -0
- package/lib/search-usage.js +86 -0
- package/lib/transport.js +38 -10
- package/lib/types/client/index.d.ts +12 -0
- package/lib/types/client/search-media.d.ts +16 -0
- package/lib/web-run-output.js +22 -0
- package/lib/web-search-alpha.js +230 -28
- package/lib/web-search-capability.js +26 -1
- package/lib/web-search-hosted.js +119 -9
- package/lib/web-search-ref-store.js +88 -7
- package/package.json +45 -24
- package/lib/types/compact-v2.d.ts +0 -104
- package/lib/types/dsh-compat.d.ts +0 -78
- package/lib/types/dsh-responses.d.ts +0 -82
- package/lib/types/grok-native-search.d.ts +0 -39
- package/lib/types/json-store.d.ts +0 -10
- package/lib/types/native-checkpoint.d.ts +0 -213
- package/lib/types/responses-request.d.ts +0 -59
- package/lib/types/responses-stream.d.ts +0 -64
- package/lib/types/route.d.ts +0 -153
- package/lib/types/service-mutex.d.ts +0 -14
- package/lib/types/token-budget.d.ts +0 -50
- package/lib/types/transport.d.ts +0 -21
- package/lib/types/web-run-output.d.ts +0 -29
- package/lib/types/web-search-alpha.d.ts +0 -286
- package/lib/types/web-search-capability.d.ts +0 -26
- package/lib/types/web-search-hosted.d.ts +0 -246
- package/lib/types/web-search-ref-store.d.ts +0 -22
package/lib/index.js
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import z from "@deepseek-ai/schemastery";
|
|
2
|
+
import { recordHostedUsage, withAuxiliaryUsage } from "./auxiliary-usage.js";
|
|
3
|
+
import { installSearchUsage } from "./search-usage.js";
|
|
2
4
|
import { WEB_SEARCH_MAX_QUERIES, applyWebSearchTool, } from "@deepseek-ai/dsh-tool-web";
|
|
3
5
|
import "@deepseek-ai/dsh-agent";
|
|
4
6
|
import "@deepseek-ai/dsh-tools";
|
|
@@ -7,21 +9,22 @@ import { randomUUID } from "node:crypto";
|
|
|
7
9
|
import { homedir } from "node:os";
|
|
8
10
|
import { join } from "node:path";
|
|
9
11
|
import { AsyncLocalStorage } from "node:async_hooks";
|
|
10
|
-
import { getSupportedThinkingLevels } from "
|
|
12
|
+
import { getSupportedThinkingLevels } from "./pi-responses-runtime.js";
|
|
11
13
|
import { fetchJsonWithRetry } from "./transport.js";
|
|
12
14
|
import { agentSessionId, agentUsesSession, compactionConfigState, compactionPatchCandidate, installCompactionPatch, patchCompactionConfig, patchToolResultPruner, readAgentRouteState, resolveAgentService, resolveContextService, resolveScopedService, restoreCompactionConfig, restoreCompactionPatches, restoreToolResultPruner, sessionFor, sessionFromAgent, scopedToolRuntime, tokenMeterTotal, toolResultPrunerState, } from "./dsh-compat.js";
|
|
15
|
+
import { InvocationPolicyScope } from "./invocation-policy-scope.js";
|
|
13
16
|
import { authenticatedGrokHeaders, authenticatedHeaders, currentRoute, generationControlsFromSession, grokPromptCacheSessionId, promptCacheKey, promptCacheRetention, promptCacheSessionId, resolveGrokResponsesRouteConfig, resolveResponsesRouteConfig, routeFingerprint, } from "./route.js";
|
|
14
17
|
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
18
|
import { mergeFeatureHeader, requestNativeCompaction } from "./compact-v2.js";
|
|
16
19
|
import { buildResponsesBody } from "./responses-request.js";
|
|
17
20
|
import { managedFailureChunk, streamResponsesRequest, } from "./responses-stream.js";
|
|
18
21
|
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 { HOSTED_SEARCH_OUTPUT, HOSTED_SEARCH_PARAMETERS, buildHostedSearchBody, hostedMediaPresentationMeta, normalizeHostedSearchArgs, parseHostedSearchResponse, renderHostedSearchResult, } from "./web-search-hosted.js";
|
|
23
|
+
import { ALPHA_SCHEMA_FINGERPRINT, alphaRefRequiresStore, isAlphaContinuationUrl, isAlphaHttpUrl, ALPHA_SEARCH_OUTPUT, ALPHA_SEARCH_PARAMETERS, alphaSearchRetryOptions, buildAlphaSearchBody, normalizeAlphaSearchArgs, parseAlphaSearchResponse, renderAlphaSearchResult, runWithAlphaSessionLock, } from "./web-search-alpha.js";
|
|
24
|
+
import { AlphaCapabilityStore, alphaCapabilityFingerprint, alphaCapabilityUsable, alphaSearchParametersFor, assertAlphaActionAllowed, } from "./web-search-capability.js";
|
|
22
25
|
import { AlphaRefStore } from "./web-search-ref-store.js";
|
|
23
26
|
import { ServiceMutex } from "./service-mutex.js";
|
|
24
|
-
import { GROK_NATIVE_SERVER_TOOL_TYPES, grokNativeSearchEnabled, grokVisibleFunctionTools, grokWireTools, restoreGrokNativeReplay, } from "./grok-native-search.js";
|
|
27
|
+
import { GROK_NATIVE_SERVER_TOOL_TYPES, grokNativeSearchEnabled, grokVisibleFunctionTools, isGrokNativeServerToolItem, grokWireTools, restoreGrokNativeReplay, } from "./grok-native-search.js";
|
|
25
28
|
export const name = "lcx-codex";
|
|
26
29
|
export const inject = ["llm", "web", "sessions", "tools", "settings", "credentials", "attachments", "fs"];
|
|
27
30
|
const SETTINGS_NS = "lcx-codex";
|
|
@@ -118,6 +121,7 @@ const SettingsSchema = z.object({
|
|
|
118
121
|
alphaSearch: z.boolean().default(false),
|
|
119
122
|
grokNativeWebSearch: z.boolean().default(false),
|
|
120
123
|
grokNativeXSearch: z.boolean().default(false),
|
|
124
|
+
searchMediaPreview: z.boolean().default(false),
|
|
121
125
|
});
|
|
122
126
|
function normalizeConfig(input = {}) {
|
|
123
127
|
return {
|
|
@@ -201,6 +205,7 @@ async function executeHostedSearch(ctx, routeConfig, args, signal, sessionId = "
|
|
|
201
205
|
maxAttempts: routeConfig.maxAttempts,
|
|
202
206
|
maxResponseBytes: routeConfig.maxResponseBytes,
|
|
203
207
|
});
|
|
208
|
+
recordHostedUsage(response, requestId, routeConfig.provider, routeConfig.model);
|
|
204
209
|
return parseHostedSearchResponse(response, requestId, routeConfig.webMaxResults);
|
|
205
210
|
}
|
|
206
211
|
class LcxResponsesSearchProvider {
|
|
@@ -261,8 +266,15 @@ function createScopedGptWebSearchTool(ctx, state, getConfig, provider, fetchEnab
|
|
|
261
266
|
if (!definition)
|
|
262
267
|
throw new Error("DSH web_search composition did not register a tool");
|
|
263
268
|
const execute = definition.execute.bind(definition);
|
|
264
|
-
|
|
269
|
+
const output = definition.output;
|
|
270
|
+
return withAuxiliaryUsage({
|
|
265
271
|
...definition,
|
|
272
|
+
output: {
|
|
273
|
+
...output,
|
|
274
|
+
presentationMeta(args, value) {
|
|
275
|
+
return hostedMediaPresentationMeta(value, "web_search", output.presentationMeta?.(args, value));
|
|
276
|
+
},
|
|
277
|
+
},
|
|
266
278
|
async execute(args, exec) {
|
|
267
279
|
if (!state.enabled || !state.webSearch)
|
|
268
280
|
throw webError("web_search GPT Hosted Search is disabled", "LCX_WEB_DISABLED");
|
|
@@ -272,16 +284,17 @@ function createScopedGptWebSearchTool(ctx, state, getConfig, provider, fetchEnab
|
|
|
272
284
|
throw webError("GPT Hosted Search requires the active GPT openai-responses route", "LCX_WEB_ROUTE_UNAVAILABLE");
|
|
273
285
|
return hostedSearchRouteContext.run(active, () => execute(args, exec));
|
|
274
286
|
},
|
|
275
|
-
};
|
|
287
|
+
});
|
|
276
288
|
}
|
|
277
289
|
function createAdvancedHostedTool(ctx, state, getConfig) {
|
|
278
|
-
return {
|
|
290
|
+
return withAuxiliaryUsage({
|
|
279
291
|
name: ADVANCED_HOSTED_TOOL,
|
|
280
292
|
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
293
|
parameters: HOSTED_SEARCH_PARAMETERS,
|
|
282
294
|
output: {
|
|
283
295
|
schema: HOSTED_SEARCH_OUTPUT,
|
|
284
296
|
render: (_args, value) => renderHostedSearchResult(value),
|
|
297
|
+
presentationMeta: (_args, value) => hostedMediaPresentationMeta(value, ADVANCED_HOSTED_TOOL),
|
|
285
298
|
},
|
|
286
299
|
async execute(args, exec) {
|
|
287
300
|
if (!state.enabled || !state.webSearch || !state.advancedHostedSearch)
|
|
@@ -293,7 +306,7 @@ function createAdvancedHostedTool(ctx, state, getConfig) {
|
|
|
293
306
|
throw webError("Advanced Hosted Search requires the active GPT openai-responses route", "LCX_WEB_ROUTE_UNAVAILABLE");
|
|
294
307
|
return executeHostedSearch(ctx, routeWithPolicies(route, config), args, exec.signal, active.sessionId);
|
|
295
308
|
},
|
|
296
|
-
};
|
|
309
|
+
});
|
|
297
310
|
}
|
|
298
311
|
function disposeGptToolsForAgent(agent, registrations) {
|
|
299
312
|
const registration = registrations.get(agent);
|
|
@@ -376,52 +389,69 @@ function verifiedAlphaCapabilityForRoute(ctx, active, config, store) {
|
|
|
376
389
|
};
|
|
377
390
|
}
|
|
378
391
|
async function executeAlpha(ctx, routeConfig, capability, refStore, args, exec) {
|
|
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
392
|
const sessionId = agentSessionId(exec?.agent);
|
|
386
393
|
if (!sessionId)
|
|
387
394
|
throw webError("Alpha Search requires a DSH session", "LCX_ALPHA_SESSION_REQUIRED");
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
maxAttempts: routeConfig.maxAttempts,
|
|
402
|
-
maxResponseBytes: routeConfig.maxResponseBytes,
|
|
395
|
+
return runWithAlphaSessionLock(sessionId, exec?.signal, async () => {
|
|
396
|
+
const normalized = normalizeAlphaSearchArgs(args);
|
|
397
|
+
assertAlphaActionAllowed(capability, normalized.action);
|
|
398
|
+
if (["open", "find", "screenshot"].includes(normalized.action) &&
|
|
399
|
+
isAlphaHttpUrl(normalized.refId) &&
|
|
400
|
+
!isAlphaContinuationUrl(normalized.refId)) {
|
|
401
|
+
throw webError("Alpha Search direct URLs must be public HTTP(S) targets", "LCX_ALPHA_URL_UNAVAILABLE");
|
|
402
|
+
}
|
|
403
|
+
const routeFp = routeFingerprint({
|
|
404
|
+
provider: routeConfig.provider,
|
|
405
|
+
model: routeConfig.model,
|
|
406
|
+
baseURL: routeConfig.baseURL,
|
|
407
|
+
sessionId,
|
|
403
408
|
});
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
409
|
+
const continuedRef = alphaRefRequiresStore(normalized.action, normalized.refId)
|
|
410
|
+
? refStore.assertUsable(sessionId, routeFp, normalized.refId)
|
|
411
|
+
: undefined;
|
|
412
|
+
const requestId = randomUUID();
|
|
413
|
+
const headers = await authenticatedHeaders(ctx, routeConfig, sessionId, requestId);
|
|
414
|
+
let response;
|
|
415
|
+
try {
|
|
416
|
+
response = await fetchJsonWithRetry(`${routeConfig.baseURL}/alpha/search`, buildAlphaSearchBody(normalized, routeConfig.model, sessionId, true, routeConfig.alphaMaxOutputTokens), headers, exec?.signal, routeConfig.timeoutMs, alphaSearchRetryOptions(routeConfig.maxResponseBytes));
|
|
417
|
+
}
|
|
418
|
+
catch (error) {
|
|
419
|
+
const details = errorDetails(error);
|
|
420
|
+
if ([404, 405].includes(Number(details.status)) ||
|
|
421
|
+
/channel does not support/iu.test(String(details.message ?? "")))
|
|
422
|
+
throw webError("Alpha Search is not supported by this route", "LCX_ALPHA_UNAVAILABLE", error);
|
|
423
|
+
throw webError("Alpha Search provider request failed", "LCX_ALPHA_PROVIDER_ERROR", error);
|
|
424
|
+
}
|
|
425
|
+
const { refRecords: observedRefs, ...result } = parseAlphaSearchResponse(response, {
|
|
426
|
+
action: normalized.action,
|
|
427
|
+
capability: capability.classification,
|
|
428
|
+
requestId,
|
|
429
|
+
});
|
|
430
|
+
const refRecords = observedRefs.map((observation) => {
|
|
431
|
+
if (observation.refId !== normalized.refId || !continuedRef)
|
|
432
|
+
return observation;
|
|
433
|
+
const observedArtifact = observation.provenance.artifactFingerprint;
|
|
434
|
+
const acceptedArtifact = continuedRef.provenance.artifactFingerprint;
|
|
435
|
+
if (observedArtifact && observedArtifact !== acceptedArtifact)
|
|
436
|
+
return observation;
|
|
437
|
+
// An echoed input ref retains its accepted origin; an omitted URL makes no new claim.
|
|
438
|
+
return {
|
|
439
|
+
...observation,
|
|
440
|
+
...(observation.url === undefined && continuedRef.url ? { url: continuedRef.url } : {}),
|
|
441
|
+
provenance: { ...continuedRef.provenance },
|
|
442
|
+
};
|
|
443
|
+
});
|
|
444
|
+
refStore.record(sessionId, routeFp, refRecords);
|
|
445
|
+
return result;
|
|
416
446
|
});
|
|
417
|
-
refStore.record(sessionId, routeFp, refRecords);
|
|
418
|
-
return result;
|
|
419
447
|
}
|
|
420
|
-
function createAlphaTool(ctx, state, getConfig, capabilityStore, refStore) {
|
|
448
|
+
function createAlphaTool(ctx, state, getConfig, capabilityStore, refStore, advertisedRecord) {
|
|
421
449
|
return {
|
|
422
450
|
name: ALPHA_TOOL,
|
|
423
451
|
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:
|
|
452
|
+
parameters: advertisedRecord
|
|
453
|
+
? alphaSearchParametersFor(advertisedRecord)
|
|
454
|
+
: ALPHA_SEARCH_PARAMETERS,
|
|
425
455
|
output: {
|
|
426
456
|
schema: ALPHA_SEARCH_OUTPUT,
|
|
427
457
|
render: (_args, value) => renderAlphaSearchResult(value),
|
|
@@ -474,7 +504,7 @@ function syncAlphaToolForAgent(ctx, agent, state, getConfig, capabilityStore, re
|
|
|
474
504
|
// Alpha is route-bound; global registration would advertise a static record to other routes.
|
|
475
505
|
registrations.set(agent, {
|
|
476
506
|
fingerprint: capability.fingerprint,
|
|
477
|
-
dispose: scopedTools.register(createAlphaTool(ctx, state, getConfig, capabilityStore, refStore)),
|
|
507
|
+
dispose: scopedTools.register(createAlphaTool(ctx, state, getConfig, capabilityStore, refStore, capability.record)),
|
|
478
508
|
});
|
|
479
509
|
return true;
|
|
480
510
|
}
|
|
@@ -522,8 +552,15 @@ async function serializeNativeAware(messages, route, routeConfig, ctx, options)
|
|
|
522
552
|
responsesCompat: routeConfig.responsesCompat,
|
|
523
553
|
...extra,
|
|
524
554
|
});
|
|
555
|
+
const firstMessage = messages[0];
|
|
556
|
+
const systemHead = firstMessage?.role === "system" ? firstMessage : undefined;
|
|
557
|
+
const surfaceMessages = systemHead ? messages.slice(1) : messages;
|
|
558
|
+
const systemPrompt = systemHead?.content
|
|
559
|
+
.filter((block) => block.type === "text")
|
|
560
|
+
.map((block) => block.text)
|
|
561
|
+
.join("") || undefined;
|
|
525
562
|
const prelude = await serializeDshMessages([], ctx, serializeOptions(undefined, {
|
|
526
|
-
systemPrompt
|
|
563
|
+
systemPrompt,
|
|
527
564
|
includeSystemPrompt: true,
|
|
528
565
|
}));
|
|
529
566
|
const ephemeralPreludeItemCount = prelude.input.length;
|
|
@@ -544,7 +581,7 @@ async function serializeNativeAware(messages, route, routeConfig, ctx, options)
|
|
|
544
581
|
input.push(...restoreGrokNativeReplay(serialized.input, batch, options.grokNativeReplayRoute));
|
|
545
582
|
mergeMap(imageMap, serialized.imageMap);
|
|
546
583
|
};
|
|
547
|
-
for (const message of
|
|
584
|
+
for (const message of surfaceMessages ?? []) {
|
|
548
585
|
assertSupportedCheckpointMessage(message);
|
|
549
586
|
const state = session
|
|
550
587
|
? checkpointStateForMessage(session, message)
|
|
@@ -600,7 +637,7 @@ async function* remoteCompactionStream(options, routeConfig, ctx, next) {
|
|
|
600
637
|
const history = stripCompactionDirective(options.messages);
|
|
601
638
|
const route = currentRoute(options, routeConfig);
|
|
602
639
|
try {
|
|
603
|
-
const prepared = await serializeNativeAware(history, route, routeConfig, ctx, { signal: options.signal,
|
|
640
|
+
const prepared = await serializeNativeAware(history, route, routeConfig, ctx, { signal: options.signal, tools: options.tools });
|
|
604
641
|
const cacheSessionId = promptCacheSessionId(route, routeConfig, ctx);
|
|
605
642
|
const headers = await authenticatedHeaders(ctx, routeConfig, cacheSessionId, cacheSessionId === undefined ? null : route.sessionId);
|
|
606
643
|
const generation = generationControlsFromSession(sessionFor(ctx, route.sessionId), route);
|
|
@@ -715,56 +752,68 @@ function patchCompactionPressureService(compactionValue, state, getConfig, ctx,
|
|
|
715
752
|
if (!candidate)
|
|
716
753
|
return false;
|
|
717
754
|
const mutex = new ServiceMutex();
|
|
755
|
+
const policyScope = new InvocationPolicyScope();
|
|
718
756
|
const lifecycle = new AbortController();
|
|
719
|
-
return installCompactionPatch(records, candidate, mutex, lifecycle, async (agent, trigger, signal, callOriginal) => {
|
|
757
|
+
return installCompactionPatch(records, candidate, mutex, policyScope, lifecycle, async (agent, trigger, signal, callOriginal) => {
|
|
720
758
|
const activeSignal = combinedAbortSignal(signal, lifecycle.signal);
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
contextWindow
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
759
|
+
const configScoped = policyScope.ensure(compactionConfigState(candidate.compaction).service, "config");
|
|
760
|
+
const prunerState = toolResultPrunerState(resolveAgentService(ctx, agent, "toolResultPruner") ??
|
|
761
|
+
resolveScopedService(agent, "toolResultPruner") ??
|
|
762
|
+
resolveContextService(ctx, "toolResultPruner"));
|
|
763
|
+
const prunerScoped = !prunerState.pruner ||
|
|
764
|
+
(typeof prunerState.original === "function" &&
|
|
765
|
+
policyScope.ensure(prunerState.pruner, "pruneSession"));
|
|
766
|
+
const accessMode = configScoped && prunerScoped ? "shared" : "exclusive";
|
|
767
|
+
return policyScope.run(activeSignal, accessMode, async () => {
|
|
768
|
+
const invoke = async () => {
|
|
769
|
+
if (trigger !== "pressure" || !state.enabled)
|
|
770
|
+
return callOriginal(activeSignal);
|
|
771
|
+
const config = getConfig();
|
|
772
|
+
const target = routedTargetForAgent(agent);
|
|
773
|
+
if (!target || !resolveResponsesRouteConfig(ctx, target, config))
|
|
774
|
+
return callOriginal(activeSignal);
|
|
775
|
+
const session = sessionFromAgent(agent);
|
|
776
|
+
const tokenMeter = resolveScopedService(agent, "tokenMeter") ??
|
|
777
|
+
resolveContextService(ctx, "tokenMeter");
|
|
778
|
+
if (!session || tokenMeter === undefined)
|
|
779
|
+
return callOriginal(activeSignal);
|
|
780
|
+
let contextWindow;
|
|
781
|
+
try {
|
|
782
|
+
contextWindow = (await ctx.llm.resolveModelInfo(target.provider, target.model, activeSignal)).context?.contextWindow;
|
|
783
|
+
}
|
|
784
|
+
catch {
|
|
785
|
+
return callOriginal(activeSignal);
|
|
786
|
+
}
|
|
787
|
+
const totalTokens = tokenMeterTotal(tokenMeter, session);
|
|
788
|
+
if (contextWindow === undefined ||
|
|
789
|
+
contextWindow <= 0 ||
|
|
790
|
+
totalTokens === undefined)
|
|
791
|
+
return callOriginal(activeSignal);
|
|
792
|
+
const auto = AUTO_COMPACTION_THRESHOLD_PERCENT;
|
|
793
|
+
const emergency = EMERGENCY_PRUNE_THRESHOLD_PERCENT;
|
|
794
|
+
const pressure = compactionPressureBand(totalTokens, contextWindow, {
|
|
795
|
+
auto,
|
|
796
|
+
emergency,
|
|
797
|
+
});
|
|
798
|
+
if (pressure.band === "below")
|
|
799
|
+
return null;
|
|
800
|
+
const nativeFirst = pressure.band === "native";
|
|
801
|
+
const prunerPatch = nativeFirst
|
|
802
|
+
? patchToolResultPruner(prunerState, () => ({ pruned: [], charsRemoved: 0 }))
|
|
803
|
+
: undefined;
|
|
804
|
+
const configPatch = patchCompactionConfig(compactionConfigState(candidate.compaction), (originalConfig) => adjustedCompactionConfig(originalConfig, target, auto / 100));
|
|
805
|
+
ctx.logger?.info?.(`[lcx-codex] auto pressure ${pressure.ratioPercent.toFixed(1)}%: ${nativeFirst ? "Native V2 first" : "emergency DSH prune allowed"} (native ${auto}%, emergency ${emergency}%)`);
|
|
806
|
+
try {
|
|
807
|
+
return await callOriginal(activeSignal);
|
|
808
|
+
}
|
|
809
|
+
finally {
|
|
810
|
+
restoreCompactionConfig(configPatch);
|
|
811
|
+
restoreToolResultPruner(prunerPatch);
|
|
812
|
+
}
|
|
813
|
+
};
|
|
814
|
+
return accessMode === "shared"
|
|
815
|
+
? invoke()
|
|
816
|
+
: mutex.run(activeSignal, invoke);
|
|
768
817
|
});
|
|
769
818
|
});
|
|
770
819
|
}
|
|
@@ -778,8 +827,13 @@ async function restoreCompactionPressure(records) {
|
|
|
778
827
|
if (!record.lifecycle.signal.aborted)
|
|
779
828
|
record.lifecycle.abort(reason);
|
|
780
829
|
}
|
|
781
|
-
await Promise.allSettled(entries.
|
|
830
|
+
await Promise.allSettled(entries.flatMap((record) => [
|
|
831
|
+
record.policyScope.close(reason),
|
|
832
|
+
record.mutex.close(reason),
|
|
833
|
+
]));
|
|
782
834
|
restoreCompactionPatches(records, entries);
|
|
835
|
+
for (const record of entries)
|
|
836
|
+
record.policyScope.restore();
|
|
783
837
|
}
|
|
784
838
|
function messagesContainNativeCheckpoint(messages, session) {
|
|
785
839
|
return session !== undefined && messages.some((message) => checkpointStateForMessage(session, message));
|
|
@@ -792,7 +846,7 @@ async function* managedResponsesStream(options, routeConfig, ctx) {
|
|
|
792
846
|
try {
|
|
793
847
|
if (options.stop !== undefined)
|
|
794
848
|
throw Object.assign(new Error("LCX Responses does not support GenerateOptions.stop"), { code: "LCX_RESPONSES_UNSUPPORTED_OPTION" });
|
|
795
|
-
const prepared = await serializeNativeAware(options.messages, route, routeConfig, ctx, { signal: options.signal,
|
|
849
|
+
const prepared = await serializeNativeAware(options.messages, route, routeConfig, ctx, { signal: options.signal, tools: options.tools });
|
|
796
850
|
const cacheSessionId = promptCacheSessionId(route, routeConfig, ctx);
|
|
797
851
|
const headers = await authenticatedHeaders(ctx, routeConfig, cacheSessionId, cacheSessionId === undefined ? null : route.sessionId);
|
|
798
852
|
const body = buildResponsesBody({
|
|
@@ -837,9 +891,9 @@ async function* managedGrokNativeSearchStream(options, routeConfig, nativeSearch
|
|
|
837
891
|
if (options.stop !== undefined)
|
|
838
892
|
throw Object.assign(new Error("LCX Responses does not support GenerateOptions.stop"), { code: "LCX_RESPONSES_UNSUPPORTED_OPTION" });
|
|
839
893
|
const visibleTools = grokVisibleFunctionTools(options.tools, nativeSearch);
|
|
894
|
+
const declaredToolNames = new Set(visibleTools?.map((tool) => tool.name) ?? []);
|
|
840
895
|
const prepared = await serializeNativeAware(options.messages, route, routeConfig, ctx, {
|
|
841
896
|
signal: options.signal,
|
|
842
|
-
system: options.system,
|
|
843
897
|
tools: visibleTools,
|
|
844
898
|
grokNativeReplayRoute: nativeReplayRoute,
|
|
845
899
|
});
|
|
@@ -889,6 +943,8 @@ async function* managedGrokNativeSearchStream(options, routeConfig, nativeSearch
|
|
|
889
943
|
maxAttempts: 1,
|
|
890
944
|
maxResponseBytes: routeConfig.maxResponseBytes,
|
|
891
945
|
serverToolTypes: GROK_NATIVE_SERVER_TOOL_TYPES,
|
|
946
|
+
isServerToolItem: (item) => isGrokNativeServerToolItem(item, nativeSearch, declaredToolNames),
|
|
947
|
+
declaredToolNames,
|
|
892
948
|
nativeReplayRoute,
|
|
893
949
|
onServerToolUsage(usage) {
|
|
894
950
|
ctx.logger?.info?.(`[lcx-codex] Grok native search used ${usage.total} server-side tool call(s) (web=${usage.webSearchCalls}, x=${usage.xSearchCalls})`);
|
|
@@ -906,6 +962,7 @@ async function* unavailableManagedRouteStream(options) {
|
|
|
906
962
|
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);
|
|
907
963
|
}
|
|
908
964
|
function installInjected(ctx, configInput = {}) {
|
|
965
|
+
installSearchUsage(ctx);
|
|
909
966
|
const baseConfig = normalizeConfig(configInput);
|
|
910
967
|
let runtimeConfig = baseConfig;
|
|
911
968
|
const state = {
|
|
@@ -952,6 +1009,7 @@ function installInjected(ctx, configInput = {}) {
|
|
|
952
1009
|
alphaSearch: false,
|
|
953
1010
|
grokNativeWebSearch: false,
|
|
954
1011
|
grokNativeXSearch: false,
|
|
1012
|
+
searchMediaPreview: false,
|
|
955
1013
|
};
|
|
956
1014
|
let source = () => settingsEntry;
|
|
957
1015
|
ctx.settings.installSection(ctx, SETTINGS_NS, SettingsSchema, settingsEntry, {
|