pi-openai-toolkit 0.20.2 → 0.20.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/docs/internals.md
CHANGED
|
@@ -45,6 +45,16 @@ Coverage is never inferred from model names. A native session uses provider `ope
|
|
|
45
45
|
|
|
46
46
|
---
|
|
47
47
|
|
|
48
|
+
### Tool-selection boundary and unavailable Context Management
|
|
49
|
+
|
|
50
|
+
The four Toolkit context tools are `new_context`, `get_context_remaining`, `history`, and `notes`. The canonical names live in [src/context-management/tool-contract.ts](../src/context-management/tool-contract.ts). A launcher that creates a Pi session for an exact `compaction.gatewayContextModels` model should union those names into an explicit `tools` allowlist before `createAgentSession`, unless the caller selected `noTools`/`--no-tools`; an explicit `excludeTools` entry remains authoritative and is never re-added. This package does not contain the `pi-subagent` or child-session launcher source, so the helper and contract here do not claim to modify that external layer.
|
|
51
|
+
|
|
52
|
+
After registration, Pi's published registry is authoritative. Toolkit distinguishes `verified` (all four owned definitions), `excluded` (a readable registry contains none of them), `unverified` (a transient read or partial publication), and `conflict` (registration/API/ownership failure). Only `excluded` is a live-turn downgrade: `context_with_system` strips internal window markers, provider payload/header hooks return no-op results, and the lifecycle artifact records `context-tools-excluded`. Conflicts, unreadable/partial registries, malformed window state and missing gateway identity remain fail-closed for live provider requests.
|
|
53
|
+
|
|
54
|
+
If a covered Remote Context session reaches `session_before_compact` without an active context runtime, the first compaction path is the configured `compaction.remoteCompactModel` through Remote V2. The active session model remains the checkpoint consumer; the configured remote model is only the compactor. If that model is missing/unusable, only an explicitly configured/enabled `nativeFallback.model` may run. Otherwise the hook cancels rather than silently invoking the active model or Pi's default compaction. This compaction fallback does not weaken the live-provider safety rules above.
|
|
55
|
+
|
|
56
|
+
---
|
|
57
|
+
|
|
48
58
|
### Rollover lifecycle
|
|
49
59
|
|
|
50
60
|
The `new_context` happy path, end to end:
|
package/package.json
CHANGED
|
@@ -13,8 +13,47 @@ export const NOTES_ACTIONS = [
|
|
|
13
13
|
"write_file",
|
|
14
14
|
] as const;
|
|
15
15
|
|
|
16
|
+
/** Stable names shared by Toolkit registration and an external Pi launcher. */
|
|
17
|
+
export const CONTEXT_MANAGEMENT_TOOL_NAMES = [
|
|
18
|
+
"new_context",
|
|
19
|
+
"get_context_remaining",
|
|
20
|
+
"history",
|
|
21
|
+
"notes",
|
|
22
|
+
] as const;
|
|
23
|
+
|
|
16
24
|
export type HistoryAction = (typeof HISTORY_ACTIONS)[number];
|
|
17
25
|
export type NotesAction = (typeof NOTES_ACTIONS)[number];
|
|
26
|
+
export type ContextManagementToolName = (typeof CONTEXT_MANAGEMENT_TOOL_NAMES)[number];
|
|
27
|
+
|
|
28
|
+
export type ContextToolSelection = {
|
|
29
|
+
/** Pi's explicit tool allowlist. Omitted means use Pi's default selection. */
|
|
30
|
+
tools?: readonly string[];
|
|
31
|
+
/** Pi's default suppression mode. Both values are explicit host policy. */
|
|
32
|
+
noTools?: "all" | "builtin";
|
|
33
|
+
/** Pi applies this denylist after the allowlist. */
|
|
34
|
+
excludeTools?: readonly string[];
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Add Toolkit context tools to a host-provided allowlist without overriding an
|
|
39
|
+
* explicit no-tools or exclude-tools decision. The launcher owns model eligibility;
|
|
40
|
+
* this helper only owns the shared selection contract.
|
|
41
|
+
*/
|
|
42
|
+
export function ensureContextManagementToolsInAllowlist(
|
|
43
|
+
selection: ContextToolSelection,
|
|
44
|
+
eligible: boolean,
|
|
45
|
+
): string[] | undefined {
|
|
46
|
+
if (!eligible || selection.noTools !== undefined || selection.tools === undefined) {
|
|
47
|
+
return selection.tools === undefined ? undefined : [...selection.tools];
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
const excluded = new Set(selection.excludeTools ?? []);
|
|
51
|
+
const names = [...selection.tools];
|
|
52
|
+
for (const name of CONTEXT_MANAGEMENT_TOOL_NAMES) {
|
|
53
|
+
if (!excluded.has(name) && !names.includes(name)) names.push(name);
|
|
54
|
+
}
|
|
55
|
+
return names;
|
|
56
|
+
}
|
|
18
57
|
|
|
19
58
|
export const HISTORY_DESCRIPTION =
|
|
20
59
|
"Prior-window detail. Pass IDs unchanged. Search, never browse.";
|
|
@@ -223,7 +223,7 @@ export function createContextManagementTools(
|
|
|
223
223
|
return { newContext, getContextRemaining, history, notes };
|
|
224
224
|
}
|
|
225
225
|
|
|
226
|
-
export type ContextToolRegistrationState = "verified" | "conflict" | "unverified";
|
|
226
|
+
export type ContextToolRegistrationState = "verified" | "excluded" | "conflict" | "unverified";
|
|
227
227
|
|
|
228
228
|
export type ContextToolSyncResult = {
|
|
229
229
|
synced: boolean;
|
|
@@ -300,6 +300,7 @@ export class ContextManagementToolController {
|
|
|
300
300
|
const byName = new Map(available.map((tool) => [tool.name, tool]));
|
|
301
301
|
let missing = false;
|
|
302
302
|
let conflict = false;
|
|
303
|
+
let published = 0;
|
|
303
304
|
for (const name of this.registeredNames) {
|
|
304
305
|
const actual = byName.get(name);
|
|
305
306
|
const expected = this.definitions.get(name);
|
|
@@ -307,9 +308,13 @@ export class ContextManagementToolController {
|
|
|
307
308
|
missing = true;
|
|
308
309
|
continue;
|
|
309
310
|
}
|
|
311
|
+
published += 1;
|
|
310
312
|
if (!isOurTool(actual, expected)) conflict = true;
|
|
311
313
|
}
|
|
312
314
|
if (conflict) return "conflict";
|
|
315
|
+
// A readable registry with no Toolkit-owned definitions is the positive
|
|
316
|
+
// host-filtering signal used by --no-tools/restricted child sessions.
|
|
317
|
+
if (published === 0) return "excluded";
|
|
313
318
|
if (missing) return "unverified";
|
|
314
319
|
this.verifiedOnce = true;
|
|
315
320
|
return "verified";
|
package/src/extension-runtime.ts
CHANGED
|
@@ -126,6 +126,7 @@ type RemoteContextActive = (
|
|
|
126
126
|
config: CompactionConfig,
|
|
127
127
|
model?: ExtensionContext["model"],
|
|
128
128
|
) => Promise<boolean>;
|
|
129
|
+
type ContextToolRegistrationStateReader = () => ContextToolRegistrationState;
|
|
129
130
|
|
|
130
131
|
type ContextToolSyncOutcome = {
|
|
131
132
|
eligible: boolean;
|
|
@@ -211,6 +212,27 @@ function isCodexContextModel(
|
|
|
211
212
|
&& (isNativeCodexModel(model) || isCodexGatewayModel(model, config.gatewayContextModels));
|
|
212
213
|
}
|
|
213
214
|
|
|
215
|
+
function isExcludedGatewayContext(
|
|
216
|
+
model: ExtensionContext["model"] | undefined,
|
|
217
|
+
config: CompactionConfig,
|
|
218
|
+
registrationState: ContextToolRegistrationState,
|
|
219
|
+
): boolean {
|
|
220
|
+
return registrationState === "excluded" && isCodexGatewayModel(model, config.gatewayContextModels);
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
function contextManagementFailureReason(registrationState: ContextToolRegistrationState): string {
|
|
224
|
+
switch (registrationState) {
|
|
225
|
+
case "excluded":
|
|
226
|
+
return "context-tools-excluded";
|
|
227
|
+
case "conflict":
|
|
228
|
+
return "tool-name-conflict";
|
|
229
|
+
case "unverified":
|
|
230
|
+
return "tool-registration-pending";
|
|
231
|
+
case "verified":
|
|
232
|
+
return "context-management-unavailable";
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
|
|
214
236
|
function notifyRemoteContextFailure(ctx: ExtensionContext, reason: string): void {
|
|
215
237
|
if (ctx.hasUI) {
|
|
216
238
|
ctx.ui.notify(`${COMPACTION_EXTENSION_ID}: Remote Context management inactive (${reason})`, "warning");
|
|
@@ -567,11 +589,140 @@ async function runResponsesNativeCompact(
|
|
|
567
589
|
return { outcome: "success", compaction };
|
|
568
590
|
}
|
|
569
591
|
|
|
592
|
+
type ContextUnavailableCompactionResult =
|
|
593
|
+
| { compaction: CompactionResult<unknown> }
|
|
594
|
+
| { cancel: true };
|
|
595
|
+
|
|
596
|
+
async function runUnavailableContextCompaction(
|
|
597
|
+
event: SessionBeforeCompactEvent,
|
|
598
|
+
ctx: ExtensionContext,
|
|
599
|
+
dependencies: CompactionDependencies,
|
|
600
|
+
resolved: ResolvedToolkitConfig,
|
|
601
|
+
config: CompactionConfig,
|
|
602
|
+
registrationState: ContextToolRegistrationState,
|
|
603
|
+
): Promise<ContextUnavailableCompactionResult> {
|
|
604
|
+
const contextReason = contextManagementFailureReason(registrationState);
|
|
605
|
+
const remoteModelSpec = config.remoteCompactModel?.trim();
|
|
606
|
+
let remoteFailure: string | undefined;
|
|
607
|
+
|
|
608
|
+
if (remoteModelSpec) {
|
|
609
|
+
const resolution = await resolveRemoteCompactionExecution(
|
|
610
|
+
ctx,
|
|
611
|
+
{
|
|
612
|
+
enabled: config.enabled,
|
|
613
|
+
responsesApis: config.responsesApis,
|
|
614
|
+
codexGatewayModels: compactGatewayModels(resolved),
|
|
615
|
+
},
|
|
616
|
+
remoteModelSpec,
|
|
617
|
+
);
|
|
618
|
+
if (resolution.ok) {
|
|
619
|
+
const outcome = await runResponsesNativeCompact(
|
|
620
|
+
event,
|
|
621
|
+
ctx,
|
|
622
|
+
config,
|
|
623
|
+
resolution.execution,
|
|
624
|
+
dependencies.remoteCompact,
|
|
625
|
+
dependencies.projectCompactionContext,
|
|
626
|
+
);
|
|
627
|
+
if (outcome.outcome === "success") {
|
|
628
|
+
writeDebugArtifact(
|
|
629
|
+
"compaction-event",
|
|
630
|
+
{
|
|
631
|
+
event: "session_before_compact.context-fallback-success",
|
|
632
|
+
contextReason,
|
|
633
|
+
registrationState,
|
|
634
|
+
compactor: remoteModelSpec,
|
|
635
|
+
},
|
|
636
|
+
config,
|
|
637
|
+
ctx,
|
|
638
|
+
);
|
|
639
|
+
return { compaction: outcome.compaction };
|
|
640
|
+
}
|
|
641
|
+
if (outcome.outcome === "aborted" || outcome.outcome === "unprojected-input") {
|
|
642
|
+
return { cancel: true };
|
|
643
|
+
}
|
|
644
|
+
remoteFailure = "remote-v2-failed";
|
|
645
|
+
} else {
|
|
646
|
+
remoteFailure = resolution.reason;
|
|
647
|
+
writeDebugArtifact(
|
|
648
|
+
"compaction-event",
|
|
649
|
+
{
|
|
650
|
+
event: "session_before_compact.context-fallback-unavailable",
|
|
651
|
+
contextReason,
|
|
652
|
+
registrationState,
|
|
653
|
+
reason: resolution.reason,
|
|
654
|
+
modelSpec: remoteModelSpec,
|
|
655
|
+
errorMessage: resolution.errorMessage,
|
|
656
|
+
},
|
|
657
|
+
config,
|
|
658
|
+
ctx,
|
|
659
|
+
);
|
|
660
|
+
}
|
|
661
|
+
} else {
|
|
662
|
+
remoteFailure = "missing-remote-compaction-model";
|
|
663
|
+
}
|
|
664
|
+
|
|
665
|
+
const nativeModelSpec = config.nativeFallback.model?.trim();
|
|
666
|
+
if (config.nativeFallback.enabled && nativeModelSpec) {
|
|
667
|
+
const fallback = await dependencies.nativeFallback({
|
|
668
|
+
ctx,
|
|
669
|
+
event,
|
|
670
|
+
config,
|
|
671
|
+
modelSpec: nativeModelSpec,
|
|
672
|
+
});
|
|
673
|
+
if (fallback.ok) {
|
|
674
|
+
writeDebugArtifact(
|
|
675
|
+
"compaction-event",
|
|
676
|
+
{
|
|
677
|
+
event: "session_before_compact.context-fallback-native-success",
|
|
678
|
+
contextReason,
|
|
679
|
+
registrationState,
|
|
680
|
+
remoteFailure,
|
|
681
|
+
fallbackModel: nativeModelSpec,
|
|
682
|
+
},
|
|
683
|
+
config,
|
|
684
|
+
ctx,
|
|
685
|
+
);
|
|
686
|
+
return { compaction: fallback.result };
|
|
687
|
+
}
|
|
688
|
+
writeDebugArtifact(
|
|
689
|
+
"compaction-event",
|
|
690
|
+
{
|
|
691
|
+
event: "session_before_compact.context-fallback-native-failure",
|
|
692
|
+
contextReason,
|
|
693
|
+
registrationState,
|
|
694
|
+
remoteFailure,
|
|
695
|
+
fallbackReason: fallback.reason,
|
|
696
|
+
fallbackModel: nativeModelSpec,
|
|
697
|
+
errorMessage: fallback.errorMessage,
|
|
698
|
+
},
|
|
699
|
+
config,
|
|
700
|
+
ctx,
|
|
701
|
+
);
|
|
702
|
+
} else {
|
|
703
|
+
writeDebugArtifact(
|
|
704
|
+
"compaction-event",
|
|
705
|
+
{
|
|
706
|
+
event: "session_before_compact.context-fallback-cancelled",
|
|
707
|
+
contextReason,
|
|
708
|
+
registrationState,
|
|
709
|
+
remoteFailure,
|
|
710
|
+
reason: config.nativeFallback.enabled ? "missing-native-fallback-model" : "native-fallback-disabled",
|
|
711
|
+
},
|
|
712
|
+
config,
|
|
713
|
+
ctx,
|
|
714
|
+
);
|
|
715
|
+
}
|
|
716
|
+
|
|
717
|
+
return { cancel: true };
|
|
718
|
+
}
|
|
719
|
+
|
|
570
720
|
async function handleSessionBeforeCompact(
|
|
571
721
|
event: SessionBeforeCompactEvent,
|
|
572
722
|
ctx: ExtensionContext,
|
|
573
723
|
dependencies: CompactionDependencies,
|
|
574
724
|
remoteContextActive: RemoteContextActive,
|
|
725
|
+
getContextToolRegistrationState: ContextToolRegistrationStateReader,
|
|
575
726
|
) {
|
|
576
727
|
const resolved = contextOperation(dependencies.loadConfig, ctx);
|
|
577
728
|
if (resolved.invalidFeatures.some((feature) => ["context", "compatibility", "diagnostics"].includes(feature))) return { cancel: true };
|
|
@@ -602,7 +753,8 @@ async function handleSessionBeforeCompact(
|
|
|
602
753
|
}
|
|
603
754
|
|
|
604
755
|
// Remote Context management owns this eligible Codex session. It persists a
|
|
605
|
-
// no-summary boundary
|
|
756
|
+
// no-summary boundary while active; an unavailable runtime uses the configured
|
|
757
|
+
// Remote V2 compactor instead of silently returning to Pi's active-model path.
|
|
606
758
|
const contextModel = await resolveContextCapabilityModel(ctx);
|
|
607
759
|
if (isCodexContextModel(contextModel, config)) {
|
|
608
760
|
if (await remoteContextActive(ctx, config, contextModel)) {
|
|
@@ -618,14 +770,20 @@ async function handleSessionBeforeCompact(
|
|
|
618
770
|
return { cancel: true };
|
|
619
771
|
}
|
|
620
772
|
}
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
773
|
+
|
|
774
|
+
const registrationState = getContextToolRegistrationState();
|
|
775
|
+
const failureReason = contextManagementFailureReason(registrationState);
|
|
776
|
+
if (failureReason !== "context-tools-excluded") {
|
|
777
|
+
notifyRemoteContextFailure(ctx, failureReason);
|
|
778
|
+
}
|
|
779
|
+
return runUnavailableContextCompaction(
|
|
780
|
+
event,
|
|
781
|
+
ctx,
|
|
782
|
+
dependencies,
|
|
783
|
+
resolved,
|
|
784
|
+
config,
|
|
785
|
+
registrationState,
|
|
786
|
+
);
|
|
629
787
|
}
|
|
630
788
|
|
|
631
789
|
// Resolve producer protocol policy from this operation's document, not a later disk read.
|
|
@@ -865,6 +1023,7 @@ async function handleContextInternal(
|
|
|
865
1023
|
loadConfig: typeof loadToolkitConfig,
|
|
866
1024
|
contextWindows: CodexContextWindowManager,
|
|
867
1025
|
remoteContextActive: RemoteContextActive,
|
|
1026
|
+
getContextToolRegistrationState: ContextToolRegistrationStateReader,
|
|
868
1027
|
) {
|
|
869
1028
|
const resolved = contextOperation(loadConfig, ctx);
|
|
870
1029
|
requireContextPolicy(resolved, ctx);
|
|
@@ -913,13 +1072,21 @@ async function handleContextInternal(
|
|
|
913
1072
|
}
|
|
914
1073
|
|
|
915
1074
|
// An eligible Codex Remote session is never allowed to fall through to the
|
|
916
|
-
// older compaction-replay path.
|
|
917
|
-
//
|
|
918
|
-
//
|
|
1075
|
+
// older compaction-replay path. An explicit host exclusion is the one
|
|
1076
|
+
// intentional downgrade: strip internal markers and let the ordinary request
|
|
1077
|
+
// proceed without Remote Context affinity.
|
|
919
1078
|
if (isCodexContextModel(contextModel, config)) {
|
|
1079
|
+
const registrationState = getContextToolRegistrationState();
|
|
1080
|
+
if (isExcludedGatewayContext(contextModel, config, registrationState)) {
|
|
1081
|
+
const visibleMessages = contextWindows.project(event.messages, "off");
|
|
1082
|
+
return visibleMessages.length === event.messages.length && visibleMessages.every((message, index) => message === event.messages[index])
|
|
1083
|
+
? undefined
|
|
1084
|
+
: { messages: visibleMessages };
|
|
1085
|
+
}
|
|
920
1086
|
if (isCodexGatewayModel(contextModel, config.gatewayContextModels)) {
|
|
921
|
-
|
|
922
|
-
|
|
1087
|
+
const reason = contextManagementFailureReason(registrationState);
|
|
1088
|
+
notifyRemoteContextFailure(ctx, reason);
|
|
1089
|
+
reportPiContextHookFailure(ctx, reason);
|
|
923
1090
|
ctx.abort();
|
|
924
1091
|
return undefined;
|
|
925
1092
|
}
|
|
@@ -972,9 +1139,10 @@ async function handleContext(
|
|
|
972
1139
|
loadConfig: typeof loadToolkitConfig,
|
|
973
1140
|
contextWindows: CodexContextWindowManager,
|
|
974
1141
|
remoteContextActive: RemoteContextActive,
|
|
1142
|
+
getContextToolRegistrationState: ContextToolRegistrationStateReader,
|
|
975
1143
|
) {
|
|
976
1144
|
try {
|
|
977
|
-
return await handleContextInternal(event, ctx, pi, loadConfig, contextWindows, remoteContextActive);
|
|
1145
|
+
return await handleContextInternal(event, ctx, pi, loadConfig, contextWindows, remoteContextActive, getContextToolRegistrationState);
|
|
978
1146
|
} catch (error) {
|
|
979
1147
|
reportPiContextHookFailure(ctx, error instanceof Error ? error.message : String(error));
|
|
980
1148
|
throw error;
|
|
@@ -987,6 +1155,7 @@ async function handleBeforeProviderRequest(
|
|
|
987
1155
|
loadConfig: typeof loadToolkitConfig,
|
|
988
1156
|
contextWindows: CodexContextWindowManager,
|
|
989
1157
|
remoteContextActive: RemoteContextActive,
|
|
1158
|
+
getContextToolRegistrationState: ContextToolRegistrationStateReader,
|
|
990
1159
|
) {
|
|
991
1160
|
const resolved = contextOperation(loadConfig, ctx);
|
|
992
1161
|
requireContextPolicy(resolved, ctx);
|
|
@@ -1018,12 +1187,17 @@ async function handleBeforeProviderRequest(
|
|
|
1018
1187
|
}
|
|
1019
1188
|
}
|
|
1020
1189
|
if (isCodexContextModel(contextModel, config)) {
|
|
1190
|
+
const registrationState = getContextToolRegistrationState();
|
|
1191
|
+
// A readable empty registry is an intentional host exclusion. Do not
|
|
1192
|
+
// rewrite gateway identity or abort an ordinary child-session request.
|
|
1193
|
+
if (isExcludedGatewayContext(contextModel, config, registrationState)) return undefined;
|
|
1021
1194
|
// Keep Codex Remote mutually exclusive with the legacy replay pipeline
|
|
1022
1195
|
// when authentication or tool ownership is unavailable. Gateway traffic
|
|
1023
1196
|
// cannot continue as an ordinary Responses request because that would
|
|
1024
1197
|
// silently lose the required CPA session/account selection.
|
|
1025
1198
|
if (isCodexGatewayModel(contextModel, config.gatewayContextModels)) {
|
|
1026
|
-
|
|
1199
|
+
const reason = contextManagementFailureReason(registrationState);
|
|
1200
|
+
notifyRemoteContextFailure(ctx, reason);
|
|
1027
1201
|
ctx.abort();
|
|
1028
1202
|
}
|
|
1029
1203
|
return undefined;
|
|
@@ -1278,7 +1452,9 @@ export default function registerCompactionExtension(
|
|
|
1278
1452
|
// Only models the built-in Remote Context coverage targets may activate or
|
|
1279
1453
|
// warn; everything else silently runs Pi's normal compaction path.
|
|
1280
1454
|
if (config.contextManagement === "remote" && isCodexContextModel(contextModel, config) && !active) {
|
|
1281
|
-
if (syncOutcome.registrationState === "
|
|
1455
|
+
if (syncOutcome.registrationState === "excluded") {
|
|
1456
|
+
activationReason = "context-tools-excluded";
|
|
1457
|
+
} else if (syncOutcome.registrationState === "conflict") {
|
|
1282
1458
|
activationReason = "tool-name-conflict";
|
|
1283
1459
|
notifyRemoteContextFailure(ctx, activationReason);
|
|
1284
1460
|
} else if (syncOutcome.registrationState === "unverified" || !syncOutcome.toolsSynced) {
|
|
@@ -1325,11 +1501,12 @@ export default function registerCompactionExtension(
|
|
|
1325
1501
|
}
|
|
1326
1502
|
});
|
|
1327
1503
|
|
|
1504
|
+
const getContextToolRegistrationState: ContextToolRegistrationStateReader = () => tools.registrationState;
|
|
1328
1505
|
pi.on("context_with_system", (event, ctx) => {
|
|
1329
1506
|
manualCompact.guardRequest(ctx);
|
|
1330
|
-
return handleContext(event, ctx, pi, dependencies.loadConfig, contextWindows, remoteContextActive);
|
|
1507
|
+
return handleContext(event, ctx, pi, dependencies.loadConfig, contextWindows, remoteContextActive, getContextToolRegistrationState);
|
|
1331
1508
|
});
|
|
1332
|
-
pi.on("session_before_compact", (event, ctx) => handleSessionBeforeCompact(event, ctx, dependencies, remoteContextActive));
|
|
1509
|
+
pi.on("session_before_compact", (event, ctx) => handleSessionBeforeCompact(event, ctx, dependencies, remoteContextActive, getContextToolRegistrationState));
|
|
1333
1510
|
pi.on("session_compact", (event, _ctx) => contextWindows.recordCompaction(event.compactionEntry.details));
|
|
1334
1511
|
pi.on("session_compact_failed", async (event, ctx) => {
|
|
1335
1512
|
if (event.reason === "manual" && !manualCompact.isMaintenance) await manualCompact.compactFailed(ctx);
|
|
@@ -1373,7 +1550,7 @@ export default function registerCompactionExtension(
|
|
|
1373
1550
|
});
|
|
1374
1551
|
pi.on("before_provider_request", (event, ctx) => {
|
|
1375
1552
|
manualCompact.guardRequest(ctx);
|
|
1376
|
-
return handleBeforeProviderRequest(event, ctx, dependencies.loadConfig, contextWindows, remoteContextActive);
|
|
1553
|
+
return handleBeforeProviderRequest(event, ctx, dependencies.loadConfig, contextWindows, remoteContextActive, getContextToolRegistrationState);
|
|
1377
1554
|
});
|
|
1378
1555
|
pi.on("before_provider_headers", async (event, ctx) => {
|
|
1379
1556
|
const resolved = contextOperation(dependencies.loadConfig, ctx);
|
|
@@ -1383,8 +1560,11 @@ export default function registerCompactionExtension(
|
|
|
1383
1560
|
if (!isCodexContextModel(contextModel, config)) return;
|
|
1384
1561
|
const active = await remoteContextActive(ctx, config, contextModel);
|
|
1385
1562
|
if (!active) {
|
|
1563
|
+
const registrationState = getContextToolRegistrationState();
|
|
1564
|
+
if (isExcludedGatewayContext(contextModel, config, registrationState)) return;
|
|
1386
1565
|
if (isCodexGatewayModel(contextModel, config.gatewayContextModels)) {
|
|
1387
|
-
|
|
1566
|
+
const reason = contextManagementFailureReason(registrationState);
|
|
1567
|
+
notifyRemoteContextFailure(ctx, reason);
|
|
1388
1568
|
ctx.abort();
|
|
1389
1569
|
}
|
|
1390
1570
|
return;
|