pi-openai-toolkit 0.19.0 → 0.20.0
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 +156 -242
- package/README.zh.md +156 -242
- package/config.schema.json +13 -0
- package/docs/configuration.md +128 -0
- package/package.json +5 -2
- package/src/config/policy.ts +4 -2
- package/src/config/v2.ts +36 -3
- package/src/config.ts +1 -0
- package/src/responses-websocket/extension.ts +32 -0
- package/src/responses-websocket/transport.ts +577 -0
- package/tsconfig.check.json +2 -0
package/src/config/v2.ts
CHANGED
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
* {
|
|
14
14
|
* "schemaVersion": 2,
|
|
15
15
|
* "$schema": "…metadata only…",
|
|
16
|
-
* "defaults": { "context": …, "webSearch": …, "imageGeneration": …, "autoMode": … },
|
|
16
|
+
* "defaults": { "context": …, "webSearch": …, "imageGeneration": …, "responsesWebSocket": …, "autoMode": … },
|
|
17
17
|
* "models": { "provider/model-id": { "context": …, "webSearch": …, "autoMode": …, "compatibility": … } },
|
|
18
18
|
* "diagnostics": { … }
|
|
19
19
|
* }
|
|
@@ -29,7 +29,8 @@
|
|
|
29
29
|
* raw values and unknown subtrees are never copied into diagnostics.
|
|
30
30
|
* - `defaults.compatibility` is not a recognized scope: the standard transport is internal and
|
|
31
31
|
* the Codex gateway transport stays an exact-model opt-in.
|
|
32
|
-
* - Image output settings (`defaults.imageGeneration`)
|
|
32
|
+
* - Image output settings (`defaults.imageGeneration`), Responses WebSocket transport
|
|
33
|
+
* (`defaults.responsesWebSocket`), and `diagnostics` are global only.
|
|
33
34
|
* - Exact model keys and model references use the legacy `provider/model-id` grammar: no
|
|
34
35
|
* whitespace, globs or bracket patterns. Keys are trimmed like the legacy decoder, and two
|
|
35
36
|
* raw keys that normalize to the same key are rejected instead of resolved last-wins.
|
|
@@ -120,7 +121,7 @@ const DIAGNOSTIC_LEVELS = ["error", "warn", "info", "debug"] as const;
|
|
|
120
121
|
const LEGACY_ROOT_KEYS = ["compaction", "webSearch", "imageGeneration", "autoMode"] as const;
|
|
121
122
|
|
|
122
123
|
const ROOT_KEYS = new Set(["$schema", "schemaVersion", "defaults", "models", "diagnostics"]);
|
|
123
|
-
const DEFAULTS_KEYS = new Set(["context", "webSearch", "imageGeneration", "autoMode"]);
|
|
124
|
+
const DEFAULTS_KEYS = new Set(["context", "webSearch", "imageGeneration", "responsesWebSocket", "autoMode"]);
|
|
124
125
|
const MODEL_OVERRIDE_KEYS = new Set(["context", "webSearch", "autoMode", "compatibility"]);
|
|
125
126
|
const CONTEXT_KEYS = new Set(["mode", "remoteCompaction", "nativeFallback", "remoteWindows"]);
|
|
126
127
|
const REMOTE_COMPACTION_KEYS = new Set(["model", "inputSource", "allowContinuityBreak", "apis"]);
|
|
@@ -128,6 +129,7 @@ const NATIVE_FALLBACK_KEYS = new Set(["enabled", "model", "thinkingLevel"]);
|
|
|
128
129
|
const REMOTE_WINDOWS_KEYS = new Set(["leaveManagedMode", "reminderThresholdPercent"]);
|
|
129
130
|
const WEB_SEARCH_KEYS = new Set(["route"]);
|
|
130
131
|
const IMAGE_GENERATION_KEYS = new Set(["enabled", "defaultModel", "allowedModels"]);
|
|
132
|
+
const RESPONSES_WEBSOCKET_KEYS = new Set(["enabled"]);
|
|
131
133
|
const AUTO_MODE_KEYS = new Set([
|
|
132
134
|
"available",
|
|
133
135
|
"reviewerModel",
|
|
@@ -170,6 +172,7 @@ const FEATURE_NAMES: ReadonlyMap<string, ConfigFeature> = new Map<string, Config
|
|
|
170
172
|
["compaction", "context"],
|
|
171
173
|
["webSearch", "webSearch"],
|
|
172
174
|
["imageGeneration", "imageGeneration"],
|
|
175
|
+
["responsesWebSocket", "responsesWebSocket"],
|
|
173
176
|
["autoMode", "autoMode"],
|
|
174
177
|
["compatibility", "compatibility"],
|
|
175
178
|
["diagnostics", "diagnostics"],
|
|
@@ -194,6 +197,7 @@ const POLICY_LEAVES: readonly { leaf: string; feature: ConfigFeature }[] = [
|
|
|
194
197
|
{ leaf: "imageGeneration.enabled", feature: "imageGeneration" },
|
|
195
198
|
{ leaf: "imageGeneration.defaultModel", feature: "imageGeneration" },
|
|
196
199
|
{ leaf: "imageGeneration.allowedModels", feature: "imageGeneration" },
|
|
200
|
+
{ leaf: "responsesWebSocket.enabled", feature: "responsesWebSocket" },
|
|
197
201
|
{ leaf: "autoMode.available", feature: "autoMode" },
|
|
198
202
|
{ leaf: "autoMode.reviewerModel", feature: "autoMode" },
|
|
199
203
|
{ leaf: "autoMode.gate", feature: "autoMode" },
|
|
@@ -841,6 +845,25 @@ function applyImageGenerationSettings(
|
|
|
841
845
|
);
|
|
842
846
|
}
|
|
843
847
|
|
|
848
|
+
function applyResponsesWebSocketSettings(
|
|
849
|
+
raw: Record<string, unknown>,
|
|
850
|
+
scope: Scope,
|
|
851
|
+
state: ResolutionState,
|
|
852
|
+
): void {
|
|
853
|
+
reportUnknownKeys(raw, RESPONSES_WEBSOCKET_KEYS, scope, state, "responsesWebSocket");
|
|
854
|
+
|
|
855
|
+
applyField(
|
|
856
|
+
raw,
|
|
857
|
+
{ key: "enabled", leaf: "responsesWebSocket.enabled", feature: "responsesWebSocket" },
|
|
858
|
+
scope,
|
|
859
|
+
state,
|
|
860
|
+
readBoolean,
|
|
861
|
+
(value) => {
|
|
862
|
+
state.policy.responsesWebSocket.enabled = value;
|
|
863
|
+
},
|
|
864
|
+
);
|
|
865
|
+
}
|
|
866
|
+
|
|
844
867
|
function applyAutoModeSettings(
|
|
845
868
|
raw: Record<string, unknown>,
|
|
846
869
|
scope: Scope,
|
|
@@ -1149,6 +1172,15 @@ function applyImageGenerationScope(
|
|
|
1149
1172
|
if (group) applyImageGenerationSettings(group.raw, group.scope, state);
|
|
1150
1173
|
}
|
|
1151
1174
|
|
|
1175
|
+
function applyResponsesWebSocketScope(
|
|
1176
|
+
container: Record<string, unknown>,
|
|
1177
|
+
scope: Scope,
|
|
1178
|
+
state: ResolutionState,
|
|
1179
|
+
): void {
|
|
1180
|
+
const group = openGroup(container, "responsesWebSocket", scope, state, "responsesWebSocket");
|
|
1181
|
+
if (group) applyResponsesWebSocketSettings(group.raw, group.scope, state);
|
|
1182
|
+
}
|
|
1183
|
+
|
|
1152
1184
|
function applyAutoModeScope(
|
|
1153
1185
|
container: Record<string, unknown>,
|
|
1154
1186
|
scope: Scope,
|
|
@@ -1190,6 +1222,7 @@ function applyDefaults(doc: Record<string, unknown>, state: ResolutionState): vo
|
|
|
1190
1222
|
applyContextScope(raw, scope, state);
|
|
1191
1223
|
applyWebSearchScope(raw, scope, state);
|
|
1192
1224
|
applyImageGenerationScope(raw, scope, state);
|
|
1225
|
+
applyResponsesWebSocketScope(raw, scope, state);
|
|
1193
1226
|
applyAutoModeScope(raw, scope, state);
|
|
1194
1227
|
}
|
|
1195
1228
|
|
package/src/config.ts
CHANGED
|
@@ -208,6 +208,7 @@ function fromLegacy(loaded: LoadedToolkitConfig, model: WebSearchModel | undefin
|
|
|
208
208
|
defaultModel: config.imageGeneration.models[0],
|
|
209
209
|
allowedModels: [...config.imageGeneration.models],
|
|
210
210
|
};
|
|
211
|
+
policy.responsesWebSocket = { enabled: false };
|
|
211
212
|
const { enabled, models, reviewerModel, classifier, ...auto } = config.autoMode;
|
|
212
213
|
policy.autoMode = {
|
|
213
214
|
...structuredClone(auto),
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { getApiProvider, registerApiProvider, unregisterApiProviders } from "@earendil-works/pi-ai/compat";
|
|
2
|
+
import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
|
|
3
|
+
import { loadToolkitConfig, resolveToolkitConfig } from "../config";
|
|
4
|
+
import { createResponsesWebSocketProvider } from "./transport";
|
|
5
|
+
|
|
6
|
+
const SOURCE_ID = "pi-openai-toolkit:openai-responses-websocket";
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Add the transport branch at the API-adapter boundary instead of registering
|
|
10
|
+
* a provider. Existing provider ids, models, credentials, and base URLs remain
|
|
11
|
+
* untouched; only openai-responses models eligible for transport=auto/websocket
|
|
12
|
+
* are handled by the wrapper.
|
|
13
|
+
*/
|
|
14
|
+
export function installResponsesWebSocketTransport(
|
|
15
|
+
loadConfig: typeof loadToolkitConfig = loadToolkitConfig,
|
|
16
|
+
): boolean {
|
|
17
|
+
// Re-installation can happen during Pi reloads. Remove only this extension's prior
|
|
18
|
+
// adapter so a config change cannot leave a stale enabled wrapper behind.
|
|
19
|
+
unregisterApiProviders(SOURCE_ID);
|
|
20
|
+
const resolved = resolveToolkitConfig(loadConfig());
|
|
21
|
+
if (!resolved.policy.responsesWebSocket.enabled || resolved.invalidFeatures.includes("responsesWebSocket")) {
|
|
22
|
+
return false;
|
|
23
|
+
}
|
|
24
|
+
const original = getApiProvider("openai-responses");
|
|
25
|
+
if (!original) return false;
|
|
26
|
+
registerApiProvider(createResponsesWebSocketProvider(original, true), SOURCE_ID);
|
|
27
|
+
return true;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export default function responsesWebSocketExtension(_pi: ExtensionAPI): void {
|
|
31
|
+
installResponsesWebSocketTransport();
|
|
32
|
+
}
|