pi-openai-toolkit 0.14.5 → 0.14.6
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 +42 -21
- package/package.json +1 -1
- package/src/auto-mode/classifier.ts +165 -165
- package/src/auto-mode/policy.ts +146 -146
- package/src/auto-mode/prompt.ts +279 -279
- package/src/auto-mode/reviewer.ts +325 -325
- package/src/auto-mode/transcript.ts +133 -133
- package/src/auto-mode/types.ts +137 -137
- package/src/codex-astra/effort-planner.ts +175 -175
- package/src/codex-astra/extension.ts +122 -122
- package/src/context-management/codex-provider.ts +20 -20
- package/src/context-management/history-notes.ts +32 -0
- package/src/context-management/messages.ts +112 -106
- package/src/context-management/namespace-tools.ts +426 -426
- package/src/context-management/tool-contract.ts +23 -23
- package/src/context-management/tools.ts +306 -311
- package/src/context-management/types.ts +7 -0
- package/src/context-management/window-budget.ts +83 -83
- package/src/context-management/window-manager.ts +60 -51
- package/src/context-management/window-request.ts +125 -125
- package/src/debug.ts +1 -1
- package/src/extension-runtime.ts +34 -9
- package/src/image-generation/artifacts.ts +237 -237
- package/src/image-generation/client.ts +248 -248
- package/src/image-generation/eligibility.ts +18 -18
- package/src/image-generation/references.ts +194 -194
- package/src/image-generation/render.ts +252 -252
- package/src/model-scope.ts +17 -17
- package/src/provider-headers.ts +23 -23
- package/src/responses-headers.ts +76 -11
- package/src/runtime.ts +37 -1
- package/src/web-search/extension.ts +80 -80
- package/src/web-search/payload.ts +96 -96
- package/src/web-search/prompt.ts +20 -20
- package/src/web-search/types.ts +45 -45
package/src/auto-mode/policy.ts
CHANGED
|
@@ -1,146 +1,146 @@
|
|
|
1
|
-
import { isExactModelAllowed } from "../model-scope";
|
|
2
|
-
import type { AutoModeCircuitBreakerConfig, AutoModeConfig } from "../types";
|
|
3
|
-
import {
|
|
4
|
-
SIDE_EFFECT_TOOLS,
|
|
5
|
-
type AutoModeGateSource,
|
|
6
|
-
type AutoModeModelRef,
|
|
7
|
-
} from "./types";
|
|
8
|
-
|
|
9
|
-
export type AutoModeRuntimeState = {
|
|
10
|
-
engaged: boolean;
|
|
11
|
-
/** Gate currently in force: either the configured value or a session override. */
|
|
12
|
-
gate: AutoModeGateSource;
|
|
13
|
-
/** Session override from `/auto all` or `/auto side`; cleared on session start. */
|
|
14
|
-
gateOverride?: AutoModeGateSource;
|
|
15
|
-
extraTools: string[];
|
|
16
|
-
};
|
|
17
|
-
|
|
18
|
-
/**
|
|
19
|
-
* Per-turn denial accounting, modelled on Codex's rejection circuit breaker. Without
|
|
20
|
-
* it a denied action just becomes an infinite negotiation between the agent and the
|
|
21
|
-
* reviewer, which is both expensive and the exact behaviour the anti-circumvention
|
|
22
|
-
* clause is trying to stop.
|
|
23
|
-
*/
|
|
24
|
-
export type RejectionBreakerState = {
|
|
25
|
-
consecutiveDenials: number;
|
|
26
|
-
recentDenials: boolean[];
|
|
27
|
-
deniedTools: Set<string>;
|
|
28
|
-
interrupted: boolean;
|
|
29
|
-
};
|
|
30
|
-
|
|
31
|
-
export function createRejectionBreaker(): RejectionBreakerState {
|
|
32
|
-
return { consecutiveDenials: 0, recentDenials: [], deniedTools: new Set(), interrupted: false };
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
/** Clear at turn start: the breaker judges one turn's pattern, not the whole session. */
|
|
36
|
-
export function resetRejectionBreaker(state: RejectionBreakerState): void {
|
|
37
|
-
state.consecutiveDenials = 0;
|
|
38
|
-
state.recentDenials = [];
|
|
39
|
-
state.deniedTools.clear();
|
|
40
|
-
state.interrupted = false;
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
function normalizeToolNames(names: readonly string[]): string[] {
|
|
44
|
-
return [...new Set(names.map((name) => name.trim()).filter(Boolean))];
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
/**
|
|
48
|
-
* Auto mode needs an allowlisted active model plus a configured reviewer. The
|
|
49
|
-
* reviewer model itself is resolved later, so an unknown spec degrades through the
|
|
50
|
-
* normal review-unavailable path instead of silently disabling the gate.
|
|
51
|
-
*/
|
|
52
|
-
export function isAutoModeEligible(
|
|
53
|
-
model: AutoModeModelRef | undefined,
|
|
54
|
-
config: AutoModeConfig,
|
|
55
|
-
): boolean {
|
|
56
|
-
if (!config.enabled) return false;
|
|
57
|
-
if (!config.reviewerModel) return false;
|
|
58
|
-
return isExactModelAllowed(model, config.models);
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
export function shouldReviewTool(toolName: string, state: AutoModeRuntimeState): boolean {
|
|
62
|
-
if (state.gate === "all") return true;
|
|
63
|
-
if ((SIDE_EFFECT_TOOLS as readonly string[]).includes(toolName)) return true;
|
|
64
|
-
return normalizeToolNames(state.extraTools).includes(toolName);
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
export function describeGate(state: Pick<AutoModeRuntimeState, "gate" | "extraTools">): string {
|
|
68
|
-
if (state.gate === "all") return "all tools";
|
|
69
|
-
return [...new Set([...SIDE_EFFECT_TOOLS, ...normalizeToolNames(state.extraTools)])].join(", ");
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
export function createRuntimeState(config: AutoModeConfig): AutoModeRuntimeState {
|
|
73
|
-
return {
|
|
74
|
-
engaged: false,
|
|
75
|
-
gate: config.gate,
|
|
76
|
-
extraTools: normalizeToolNames(config.extraTools),
|
|
77
|
-
};
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
/**
|
|
81
|
-
* Refresh the configured gate and tool list without touching engagement: editing
|
|
82
|
-
* config changes what gets reviewed, it never silently turns auto mode on or off.
|
|
83
|
-
* An explicit `/auto` scope override wins until the next session start.
|
|
84
|
-
*/
|
|
85
|
-
export function applyConfiguredGate(
|
|
86
|
-
state: AutoModeRuntimeState,
|
|
87
|
-
config: AutoModeConfig,
|
|
88
|
-
): AutoModeRuntimeState {
|
|
89
|
-
state.gate = state.gateOverride ?? config.gate;
|
|
90
|
-
state.extraTools = normalizeToolNames(config.extraTools);
|
|
91
|
-
return state;
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
export function setGateOverride(
|
|
95
|
-
state: AutoModeRuntimeState,
|
|
96
|
-
config: AutoModeConfig,
|
|
97
|
-
gate: AutoModeGateSource | undefined,
|
|
98
|
-
): AutoModeRuntimeState {
|
|
99
|
-
state.gateOverride = gate;
|
|
100
|
-
state.gate = gate ?? config.gate;
|
|
101
|
-
return state;
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
/**
|
|
105
|
-
* Record one genuine reviewer denial and report whether the turn should stop.
|
|
106
|
-
*
|
|
107
|
-
* Two independent triggers, matching Codex: a short run of consecutive denials
|
|
108
|
-
* means the agent cannot get past the reviewer, and a high denial rate inside a
|
|
109
|
-
* sliding window means it keeps trying different unsafe things.
|
|
110
|
-
*/
|
|
111
|
-
export function recordDenial(
|
|
112
|
-
state: RejectionBreakerState,
|
|
113
|
-
config: AutoModeCircuitBreakerConfig,
|
|
114
|
-
toolName: string,
|
|
115
|
-
): "continue" | "interrupt" {
|
|
116
|
-
state.consecutiveDenials += 1;
|
|
117
|
-
state.deniedTools.add(toolName);
|
|
118
|
-
state.recentDenials.push(true);
|
|
119
|
-
if (state.recentDenials.length > Math.max(1, config.windowSize)) {
|
|
120
|
-
state.recentDenials.splice(0, state.recentDenials.length - config.windowSize);
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
const recentDenials = state.recentDenials.filter(Boolean).length;
|
|
124
|
-
const consecutiveTripped = config.consecutiveDenials > 0 && state.consecutiveDenials >= config.consecutiveDenials;
|
|
125
|
-
const rateTripped = config.recentDenials > 0 && recentDenials >= config.recentDenials;
|
|
126
|
-
if (consecutiveTripped || rateTripped) {
|
|
127
|
-
state.interrupted = true;
|
|
128
|
-
return "interrupt";
|
|
129
|
-
}
|
|
130
|
-
return "continue";
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
/** Any allowed action resets the consecutive run, so one approval breaks a streak. */
|
|
134
|
-
export function recordNonDenial(state: RejectionBreakerState): void {
|
|
135
|
-
state.consecutiveDenials = 0;
|
|
136
|
-
state.recentDenials.push(false);
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
/**
|
|
140
|
-
* A repeat request for a tool that was already denied in this turn is the shape of
|
|
141
|
-
* a workaround attempt, so it must be judged by the blocking reviewer rather than
|
|
142
|
-
* accepted on the strength of an earlier low-risk classification.
|
|
143
|
-
*/
|
|
144
|
-
export function wasDeniedThisTurn(state: RejectionBreakerState, toolName: string): boolean {
|
|
145
|
-
return state.deniedTools.has(toolName);
|
|
146
|
-
}
|
|
1
|
+
import { isExactModelAllowed } from "../model-scope";
|
|
2
|
+
import type { AutoModeCircuitBreakerConfig, AutoModeConfig } from "../types";
|
|
3
|
+
import {
|
|
4
|
+
SIDE_EFFECT_TOOLS,
|
|
5
|
+
type AutoModeGateSource,
|
|
6
|
+
type AutoModeModelRef,
|
|
7
|
+
} from "./types";
|
|
8
|
+
|
|
9
|
+
export type AutoModeRuntimeState = {
|
|
10
|
+
engaged: boolean;
|
|
11
|
+
/** Gate currently in force: either the configured value or a session override. */
|
|
12
|
+
gate: AutoModeGateSource;
|
|
13
|
+
/** Session override from `/auto all` or `/auto side`; cleared on session start. */
|
|
14
|
+
gateOverride?: AutoModeGateSource;
|
|
15
|
+
extraTools: string[];
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Per-turn denial accounting, modelled on Codex's rejection circuit breaker. Without
|
|
20
|
+
* it a denied action just becomes an infinite negotiation between the agent and the
|
|
21
|
+
* reviewer, which is both expensive and the exact behaviour the anti-circumvention
|
|
22
|
+
* clause is trying to stop.
|
|
23
|
+
*/
|
|
24
|
+
export type RejectionBreakerState = {
|
|
25
|
+
consecutiveDenials: number;
|
|
26
|
+
recentDenials: boolean[];
|
|
27
|
+
deniedTools: Set<string>;
|
|
28
|
+
interrupted: boolean;
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
export function createRejectionBreaker(): RejectionBreakerState {
|
|
32
|
+
return { consecutiveDenials: 0, recentDenials: [], deniedTools: new Set(), interrupted: false };
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/** Clear at turn start: the breaker judges one turn's pattern, not the whole session. */
|
|
36
|
+
export function resetRejectionBreaker(state: RejectionBreakerState): void {
|
|
37
|
+
state.consecutiveDenials = 0;
|
|
38
|
+
state.recentDenials = [];
|
|
39
|
+
state.deniedTools.clear();
|
|
40
|
+
state.interrupted = false;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function normalizeToolNames(names: readonly string[]): string[] {
|
|
44
|
+
return [...new Set(names.map((name) => name.trim()).filter(Boolean))];
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Auto mode needs an allowlisted active model plus a configured reviewer. The
|
|
49
|
+
* reviewer model itself is resolved later, so an unknown spec degrades through the
|
|
50
|
+
* normal review-unavailable path instead of silently disabling the gate.
|
|
51
|
+
*/
|
|
52
|
+
export function isAutoModeEligible(
|
|
53
|
+
model: AutoModeModelRef | undefined,
|
|
54
|
+
config: AutoModeConfig,
|
|
55
|
+
): boolean {
|
|
56
|
+
if (!config.enabled) return false;
|
|
57
|
+
if (!config.reviewerModel) return false;
|
|
58
|
+
return isExactModelAllowed(model, config.models);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export function shouldReviewTool(toolName: string, state: AutoModeRuntimeState): boolean {
|
|
62
|
+
if (state.gate === "all") return true;
|
|
63
|
+
if ((SIDE_EFFECT_TOOLS as readonly string[]).includes(toolName)) return true;
|
|
64
|
+
return normalizeToolNames(state.extraTools).includes(toolName);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
export function describeGate(state: Pick<AutoModeRuntimeState, "gate" | "extraTools">): string {
|
|
68
|
+
if (state.gate === "all") return "all tools";
|
|
69
|
+
return [...new Set([...SIDE_EFFECT_TOOLS, ...normalizeToolNames(state.extraTools)])].join(", ");
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
export function createRuntimeState(config: AutoModeConfig): AutoModeRuntimeState {
|
|
73
|
+
return {
|
|
74
|
+
engaged: false,
|
|
75
|
+
gate: config.gate,
|
|
76
|
+
extraTools: normalizeToolNames(config.extraTools),
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Refresh the configured gate and tool list without touching engagement: editing
|
|
82
|
+
* config changes what gets reviewed, it never silently turns auto mode on or off.
|
|
83
|
+
* An explicit `/auto` scope override wins until the next session start.
|
|
84
|
+
*/
|
|
85
|
+
export function applyConfiguredGate(
|
|
86
|
+
state: AutoModeRuntimeState,
|
|
87
|
+
config: AutoModeConfig,
|
|
88
|
+
): AutoModeRuntimeState {
|
|
89
|
+
state.gate = state.gateOverride ?? config.gate;
|
|
90
|
+
state.extraTools = normalizeToolNames(config.extraTools);
|
|
91
|
+
return state;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
export function setGateOverride(
|
|
95
|
+
state: AutoModeRuntimeState,
|
|
96
|
+
config: AutoModeConfig,
|
|
97
|
+
gate: AutoModeGateSource | undefined,
|
|
98
|
+
): AutoModeRuntimeState {
|
|
99
|
+
state.gateOverride = gate;
|
|
100
|
+
state.gate = gate ?? config.gate;
|
|
101
|
+
return state;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Record one genuine reviewer denial and report whether the turn should stop.
|
|
106
|
+
*
|
|
107
|
+
* Two independent triggers, matching Codex: a short run of consecutive denials
|
|
108
|
+
* means the agent cannot get past the reviewer, and a high denial rate inside a
|
|
109
|
+
* sliding window means it keeps trying different unsafe things.
|
|
110
|
+
*/
|
|
111
|
+
export function recordDenial(
|
|
112
|
+
state: RejectionBreakerState,
|
|
113
|
+
config: AutoModeCircuitBreakerConfig,
|
|
114
|
+
toolName: string,
|
|
115
|
+
): "continue" | "interrupt" {
|
|
116
|
+
state.consecutiveDenials += 1;
|
|
117
|
+
state.deniedTools.add(toolName);
|
|
118
|
+
state.recentDenials.push(true);
|
|
119
|
+
if (state.recentDenials.length > Math.max(1, config.windowSize)) {
|
|
120
|
+
state.recentDenials.splice(0, state.recentDenials.length - config.windowSize);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
const recentDenials = state.recentDenials.filter(Boolean).length;
|
|
124
|
+
const consecutiveTripped = config.consecutiveDenials > 0 && state.consecutiveDenials >= config.consecutiveDenials;
|
|
125
|
+
const rateTripped = config.recentDenials > 0 && recentDenials >= config.recentDenials;
|
|
126
|
+
if (consecutiveTripped || rateTripped) {
|
|
127
|
+
state.interrupted = true;
|
|
128
|
+
return "interrupt";
|
|
129
|
+
}
|
|
130
|
+
return "continue";
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/** Any allowed action resets the consecutive run, so one approval breaks a streak. */
|
|
134
|
+
export function recordNonDenial(state: RejectionBreakerState): void {
|
|
135
|
+
state.consecutiveDenials = 0;
|
|
136
|
+
state.recentDenials.push(false);
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* A repeat request for a tool that was already denied in this turn is the shape of
|
|
141
|
+
* a workaround attempt, so it must be judged by the blocking reviewer rather than
|
|
142
|
+
* accepted on the strength of an earlier low-risk classification.
|
|
143
|
+
*/
|
|
144
|
+
export function wasDeniedThisTurn(state: RejectionBreakerState, toolName: string): boolean {
|
|
145
|
+
return state.deniedTools.has(toolName);
|
|
146
|
+
}
|