pi-openai-toolkit 0.23.2 → 0.24.1

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.
Files changed (54) hide show
  1. package/LICENSE +21 -21
  2. package/NOTICE +83 -83
  3. package/README.md +4 -15
  4. package/README.zh.md +4 -15
  5. package/config.schema.json +264 -278
  6. package/docs/configuration.md +304 -306
  7. package/docs/internals.md +34 -120
  8. package/package.json +123 -136
  9. package/src/compact-client.ts +412 -412
  10. package/src/compaction-projection.ts +35 -35
  11. package/src/config/legacy.ts +469 -519
  12. package/src/config/migration.ts +115 -103
  13. package/src/config/notifications.ts +46 -36
  14. package/src/config/policy.ts +115 -116
  15. package/src/config/v2.ts +1128 -1167
  16. package/src/config.ts +320 -310
  17. package/src/debug.ts +238 -238
  18. package/src/deferred-tool-carryover.ts +282 -282
  19. package/src/details-store.ts +151 -151
  20. package/src/extension-runtime.ts +1095 -1919
  21. package/src/image-generation/extension.ts +189 -189
  22. package/src/image-generation/protocol.ts +579 -579
  23. package/src/image-generation/types.ts +300 -300
  24. package/src/native-fallback.ts +140 -152
  25. package/src/payload-rewrite.ts +515 -515
  26. package/src/pi-context-hook.ts +117 -117
  27. package/src/remote-v2-client.ts +811 -811
  28. package/src/request-context-cache.ts +155 -155
  29. package/src/responses-headers.ts +180 -180
  30. package/src/retired-remote-windows.ts +35 -0
  31. package/src/runtime.ts +875 -865
  32. package/src/serializer.ts +882 -882
  33. package/src/supported-environment.ts +27 -27
  34. package/src/types.ts +541 -565
  35. package/src/web-search/alpha-client.ts +876 -876
  36. package/src/web-search/extension.ts +530 -530
  37. package/src/web-search/payload.ts +299 -299
  38. package/src/web-search/prompt.ts +60 -60
  39. package/src/web-search/types.ts +166 -166
  40. package/tsconfig.check.json +50 -50
  41. package/src/context-management/codex-provider.ts +0 -270
  42. package/src/context-management/history-notes.ts +0 -357
  43. package/src/context-management/manual-compact.ts +0 -247
  44. package/src/context-management/messages.ts +0 -238
  45. package/src/context-management/namespace-tools.ts +0 -426
  46. package/src/context-management/responses-tools.ts +0 -238
  47. package/src/context-management/scoped-compaction.ts +0 -89
  48. package/src/context-management/tool-contract.ts +0 -62
  49. package/src/context-management/tools.ts +0 -371
  50. package/src/context-management/types.ts +0 -168
  51. package/src/context-management/window-budget.ts +0 -83
  52. package/src/context-management/window-bulk.ts +0 -155
  53. package/src/context-management/window-manager.ts +0 -912
  54. package/src/context-management/window-request.ts +0 -125
@@ -1,103 +1,115 @@
1
- import { resolveToolkitConfig } from "../config";
2
- import type { LoadedToolkitConfig } from "../types";
3
- import { RETIRED_AUTO_MODE_ISSUE, RETIRED_AUTO_MODE_MESSAGE, type ConfigOrigin } from "./policy";
4
- import { resolveV2Config } from "./v2";
5
-
6
- export type MigrationPreview = {
7
- status: "ready" | "needs-review" | "already-v2" | "unavailable";
8
- candidate?: Record<string, unknown>;
9
- /** Controlled explanations, never arbitrary raw input values. */
10
- reasons: string[];
11
- /** Unknown names are masked; paths never expose unknown values. */
12
- unmappedPaths: string[];
13
- /** Candidate leaf -> origin in the unchanged legacy source (or built-in). */
14
- origins?: Record<string, ConfigOrigin>;
15
- };
16
-
17
- function modelRef(key: string): { provider: string; id: string; api: string } {
18
- const slash = key.indexOf("/");
19
- return { provider: key.slice(0, slash), id: key.slice(slash + 1), api: "openai-responses" };
20
- }
21
-
22
- /** Read-only analysis: never edits a source file or claims a lossy candidate is equivalent. */
23
- export function previewToolkitMigration(loaded: LoadedToolkitConfig): MigrationPreview {
24
- if (loaded.document?.format === "v2") {
25
- const retired = resolveToolkitConfig(loaded).issues.filter((issue) => issue.code === RETIRED_AUTO_MODE_ISSUE);
26
- return { status: "already-v2", reasons: ["The document already uses schemaVersion 2.",
27
- ...(retired.length ? [RETIRED_AUTO_MODE_MESSAGE] : [])], unmappedPaths: retired.map((issue) => issue.path) };
28
- }
29
- if (loaded.document?.format === "invalid" || loaded.document?.format === "missing") {
30
- return { status: "unavailable", reasons: ["A readable legacy document is required; no candidate was produced."], unmappedPaths: [] };
31
- }
32
- const baseline = resolveToolkitConfig(loaded);
33
- const legacy = baseline.config;
34
- const { compatibility: _compatibility, diagnostics, ...defaults } = structuredClone(baseline.policy);
35
- const models: Record<string, unknown> = Object.create(null);
36
- const origins: Record<string, ConfigOrigin> = Object.create(null);
37
- const unmappedPaths = new Set(baseline.issues.map((issue) => issue.path));
38
- for (const [leaf, origin] of Object.entries(baseline.origins)) {
39
- if (leaf.startsWith("compatibility.")) continue;
40
- origins[leaf.startsWith("diagnostics.") ? leaf : `defaults.${leaf}`] = origin;
41
- }
42
- const keys = new Set([
43
- ...legacy.webSearch.models,
44
- ...Object.keys(legacy.webSearch.routes ?? {}),
45
- ...legacy.compaction.gatewayContextModels,
46
- ]);
47
- for (const key of keys) {
48
- const resolved = resolveToolkitConfig(loaded, modelRef(key));
49
- const override: Record<string, unknown> = {};
50
- if (resolved.policy.webSearch.route !== defaults.webSearch.route) override.webSearch = resolved.policy.webSearch;
51
- if (resolved.policy.compatibility.transport !== "standard") override.compatibility = resolved.policy.compatibility;
52
- if (Object.keys(override).length > 0) {
53
- models[key] = override;
54
- for (const [feature, fields] of Object.entries(override)) {
55
- for (const field of Object.keys(fields as Record<string, unknown>)) {
56
- const leaf = `${feature}.${field}`;
57
- origins[`models[${JSON.stringify(key)}].${leaf}`] = resolved.origins[leaf];
58
- }
59
- }
60
- }
61
- }
62
- const candidate = { schemaVersion: 2, defaults, models, diagnostics };
63
- const reasons: string[] = [];
64
- // Retired sections are never migrated; their presence is a controlled removal reason.
65
- if (baseline.issues.some((issue) => issue.code === RETIRED_AUTO_MODE_ISSUE)) {
66
- reasons.push(RETIRED_AUTO_MODE_MESSAGE + " No Auto Mode settings were migrated; review the removal before applying this candidate.");
67
- unmappedPaths.add("autoMode");
68
- }
69
- if (loaded.warnings.length || baseline.issues.length) {
70
- reasons.push("Legacy warnings, unknown fields or normalized invalid values require review. Their original contents remain in the untouched source file.");
71
- }
72
- if (legacy.webSearch.enabled && legacy.webSearch.defaultRoute === undefined &&
73
- legacy.webSearch.models.some((key) => !Object.prototype.hasOwnProperty.call(legacy.webSearch.routes ?? {}, key))) {
74
- reasons.push("Legacy hosted allowlists ignore unsupported APIs and malformed payloads; explicit v2 hosted routes fail closed. This candidate is not behavior-equivalent on those paths.");
75
- }
76
- if (!legacy.webSearch.enabled && (legacy.webSearch.models.length || Object.keys(legacy.webSearch.routes ?? {}).length || legacy.webSearch.defaultRoute)) {
77
- reasons.push("Disabled legacy search contains dormant routes or a model list; simplified v2 policy does not retain that enable-later intent.");
78
- if (legacy.webSearch.models.length) unmappedPaths.add("webSearch.models");
79
- if (Object.keys(legacy.webSearch.routes ?? {}).length) unmappedPaths.add("webSearch.routes");
80
- if (legacy.webSearch.defaultRoute) unmappedPaths.add("webSearch.defaultRoute");
81
- }
82
- if (legacy.webSearch.models.length && (legacy.webSearch.defaultRoute !== undefined ||
83
- legacy.webSearch.models.some((key) => Object.hasOwn(legacy.webSearch.routes ?? {}, key)))) {
84
- unmappedPaths.add("webSearch.models");
85
- }
86
- if (!legacy.compaction.enabled && legacy.compaction.contextManagement === "remote") {
87
- reasons.push("Disabled legacy context management retains a dormant remote mode; the candidate selects Pi ownership.");
88
- unmappedPaths.add("compaction.contextManagement");
89
- }
90
- // Gateway affinity was previously context-mode gated for compaction, and not used by image.
91
- if (legacy.compaction.gatewayContextModels.length) {
92
- reasons.push("Gateway compatibility is now shared across features; review synthetic compaction/image affinity before using this candidate.");
93
- }
94
- const candidateChecks = [resolveV2Config(candidate, undefined), ...[...keys].map((key) => resolveV2Config(candidate, key))];
95
- if (candidateChecks.some((resolved) => resolved.issues.length)) reasons.push("The candidate has v2 validation issues; it cannot be applied as-is.");
96
- return {
97
- status: reasons.length ? "needs-review" : "ready",
98
- candidate,
99
- origins,
100
- unmappedPaths: [...unmappedPaths],
101
- reasons: reasons.length ? reasons : ["Recognized active policies map without a known semantic difference. Preview only; no source file was changed."],
102
- };
103
- }
1
+ import { resolveToolkitConfig } from "../config";
2
+ import type { LoadedToolkitConfig } from "../types";
3
+ import {
4
+ RETIRED_AUTO_MODE_ISSUE, RETIRED_AUTO_MODE_MESSAGE,
5
+ RETIRED_REMOTE_WINDOWS_ISSUE, RETIRED_REMOTE_WINDOWS_MODE_ISSUE,
6
+ RETIRED_REMOTE_WINDOWS_CONFIG_MESSAGE, RETIRED_REMOTE_WINDOWS_MODE_MESSAGE,
7
+ type ConfigOrigin,
8
+ } from "./policy";
9
+ import { resolveV2Config } from "./v2";
10
+
11
+ export type MigrationPreview = {
12
+ status: "ready" | "needs-review" | "already-v2" | "unavailable";
13
+ candidate?: Record<string, unknown>;
14
+ /** Controlled explanations, never arbitrary raw input values. */
15
+ reasons: string[];
16
+ /** Unknown names are masked; paths never expose unknown values. */
17
+ unmappedPaths: string[];
18
+ /** Candidate leaf -> origin in the unchanged legacy source (or built-in). */
19
+ origins?: Record<string, ConfigOrigin>;
20
+ };
21
+
22
+ function modelRef(key: string): { provider: string; id: string; api: string } {
23
+ const slash = key.indexOf("/");
24
+ return { provider: key.slice(0, slash), id: key.slice(slash + 1), api: "openai-responses" };
25
+ }
26
+
27
+ /** Read-only analysis: never edits a source file or claims a lossy candidate is equivalent. */
28
+ export function previewToolkitMigration(loaded: LoadedToolkitConfig): MigrationPreview {
29
+ if (loaded.document?.format === "v2") {
30
+ const retired = resolveToolkitConfig(loaded).issues.filter((issue) =>
31
+ [RETIRED_AUTO_MODE_ISSUE, RETIRED_REMOTE_WINDOWS_ISSUE, RETIRED_REMOTE_WINDOWS_MODE_ISSUE].some((code) => code === issue.code));
32
+ const removedMode = retired.some((issue) => issue.code === RETIRED_REMOTE_WINDOWS_MODE_ISSUE);
33
+ return { status: removedMode ? "needs-review" : "already-v2", reasons: ["The document already uses schemaVersion 2.",
34
+ ...(retired.some((issue) => issue.code === RETIRED_AUTO_MODE_ISSUE) ? [RETIRED_AUTO_MODE_MESSAGE] : []),
35
+ ...(retired.some((issue) => issue.code === RETIRED_REMOTE_WINDOWS_ISSUE) ? [RETIRED_REMOTE_WINDOWS_CONFIG_MESSAGE] : []),
36
+ ...(removedMode ? [RETIRED_REMOTE_WINDOWS_MODE_MESSAGE] : [])], unmappedPaths: retired.map((issue) => issue.path) };
37
+ }
38
+ if (loaded.document?.format === "invalid" || loaded.document?.format === "missing") {
39
+ return { status: "unavailable", reasons: ["A readable legacy document is required; no candidate was produced."], unmappedPaths: [] };
40
+ }
41
+ const baseline = resolveToolkitConfig(loaded);
42
+ const legacy = baseline.config;
43
+ const { compatibility: _compatibility, diagnostics, ...defaults } = structuredClone(baseline.policy);
44
+ const models: Record<string, unknown> = Object.create(null);
45
+ const origins: Record<string, ConfigOrigin> = Object.create(null);
46
+ const unmappedPaths = new Set(baseline.issues.map((issue) => issue.path));
47
+ for (const [leaf, origin] of Object.entries(baseline.origins)) {
48
+ if (leaf.startsWith("compatibility.")) continue;
49
+ origins[leaf.startsWith("diagnostics.") ? leaf : `defaults.${leaf}`] = origin;
50
+ }
51
+ const keys = new Set([
52
+ ...legacy.webSearch.models,
53
+ ...Object.keys(legacy.webSearch.routes ?? {}),
54
+ ...legacy.compaction.gatewayContextModels,
55
+ ]);
56
+ for (const key of keys) {
57
+ const resolved = resolveToolkitConfig(loaded, modelRef(key));
58
+ const override: Record<string, unknown> = {};
59
+ if (resolved.policy.webSearch.route !== defaults.webSearch.route) override.webSearch = resolved.policy.webSearch;
60
+ if (resolved.policy.compatibility.transport !== "standard") override.compatibility = resolved.policy.compatibility;
61
+ if (Object.keys(override).length > 0) {
62
+ models[key] = override;
63
+ for (const [feature, fields] of Object.entries(override)) {
64
+ for (const field of Object.keys(fields as Record<string, unknown>)) {
65
+ const leaf = `${feature}.${field}`;
66
+ origins[`models[${JSON.stringify(key)}].${leaf}`] = resolved.origins[leaf];
67
+ }
68
+ }
69
+ }
70
+ }
71
+ const candidate = { schemaVersion: 2, defaults, models, diagnostics };
72
+ const reasons: string[] = [];
73
+ // Retired sections are never migrated; their presence is a controlled removal reason.
74
+ if (baseline.issues.some((issue) => issue.code === RETIRED_AUTO_MODE_ISSUE)) {
75
+ reasons.push(RETIRED_AUTO_MODE_MESSAGE + " No Auto Mode settings were migrated; review the removal before applying this candidate.");
76
+ unmappedPaths.add("autoMode");
77
+ }
78
+ if (loaded.warnings.length || baseline.issues.length) {
79
+ reasons.push("Legacy warnings, unknown fields or normalized invalid values require review. Their original contents remain in the untouched source file.");
80
+ }
81
+ if (legacy.webSearch.enabled && legacy.webSearch.defaultRoute === undefined &&
82
+ legacy.webSearch.models.some((key) => !Object.prototype.hasOwnProperty.call(legacy.webSearch.routes ?? {}, key))) {
83
+ reasons.push("Legacy hosted allowlists ignore unsupported APIs and malformed payloads; explicit v2 hosted routes fail closed. This candidate is not behavior-equivalent on those paths.");
84
+ }
85
+ if (!legacy.webSearch.enabled && (legacy.webSearch.models.length || Object.keys(legacy.webSearch.routes ?? {}).length || legacy.webSearch.defaultRoute)) {
86
+ reasons.push("Disabled legacy search contains dormant routes or a model list; simplified v2 policy does not retain that enable-later intent.");
87
+ if (legacy.webSearch.models.length) unmappedPaths.add("webSearch.models");
88
+ if (Object.keys(legacy.webSearch.routes ?? {}).length) unmappedPaths.add("webSearch.routes");
89
+ if (legacy.webSearch.defaultRoute) unmappedPaths.add("webSearch.defaultRoute");
90
+ }
91
+ if (legacy.webSearch.models.length && (legacy.webSearch.defaultRoute !== undefined ||
92
+ legacy.webSearch.models.some((key) => Object.hasOwn(legacy.webSearch.routes ?? {}, key)))) {
93
+ unmappedPaths.add("webSearch.models");
94
+ }
95
+ if (baseline.issues.some((issue) => issue.code === RETIRED_REMOTE_WINDOWS_MODE_ISSUE)) {
96
+ reasons.push(`${RETIRED_REMOTE_WINDOWS_MODE_MESSAGE} The preview uses Pi ownership only as a safe review placeholder; it is not behavior-equivalent. Choose a supported mode explicitly before any manual apply.`);
97
+ unmappedPaths.add("compaction.contextManagement");
98
+ }
99
+ if (baseline.issues.some((issue) => issue.code === RETIRED_REMOTE_WINDOWS_ISSUE)) {
100
+ reasons.push(`${RETIRED_REMOTE_WINDOWS_CONFIG_MESSAGE} No retired ancillary settings were migrated; review their removal.`);
101
+ }
102
+ // Gateway affinity is shared across retained compaction and image features.
103
+ if (legacy.compaction.gatewayContextModels.length) {
104
+ reasons.push("Gateway compatibility is now shared across features; review synthetic compaction/image affinity before using this candidate.");
105
+ }
106
+ const candidateChecks = [resolveV2Config(candidate, undefined), ...[...keys].map((key) => resolveV2Config(candidate, key))];
107
+ if (candidateChecks.some((resolved) => resolved.issues.length)) reasons.push("The candidate has v2 validation issues; it cannot be applied as-is.");
108
+ return {
109
+ status: reasons.length ? "needs-review" : "ready",
110
+ candidate,
111
+ origins,
112
+ unmappedPaths: [...unmappedPaths],
113
+ reasons: reasons.length ? reasons : ["Recognized active policies map without a known semantic difference. Preview only; no source file was changed."],
114
+ };
115
+ }
@@ -1,36 +1,46 @@
1
- import type { ExtensionContext } from "@earendil-works/pi-coding-agent";
2
- import type { ResolvedToolkitConfig } from "../config";
3
- import { RETIRED_AUTO_MODE_ISSUE, RETIRED_AUTO_MODE_MESSAGE, type ConfigIssue } from "./policy";
4
- import { redactValue } from "../debug";
5
-
6
- const lastNotice = new WeakMap<object, string>();
7
-
8
- /** Controlled human text for a known code; never built from user-supplied configuration values. */
9
- function issueExplanation(issue: ConfigIssue): string {
10
- return issue.code === RETIRED_AUTO_MODE_ISSUE
11
- ? RETIRED_AUTO_MODE_MESSAGE
12
- : issue.code;
13
- }
14
-
15
- export function formatConfigIssues(issues: readonly ConfigIssue[], limit = 12): string {
16
- const lines = issues.slice(0, limit).map((issue) =>
17
- `${issue.severity}: ${issue.path.slice(0, 220)} — ${issueExplanation(issue)}`);
18
- if (issues.length > limit) lines.push(`${issues.length - limit} more issue(s); inspect the configuration file.`);
19
- return String(redactValue(lines.join("\n")));
20
- }
21
-
22
- /** Per-session bounded notice, independent of feature enablement/debug. Never logs raw config. */
23
- export function notifyConfigIssues(ctx: ExtensionContext, resolved: ResolvedToolkitConfig): void {
24
- const owner = ctx.sessionManager ?? ctx;
25
- if (resolved.issues.length === 0) {
26
- lastNotice.delete(owner);
27
- return;
28
- }
29
- if (!ctx.hasUI || typeof ctx.ui?.notify !== "function") return;
30
- const message = formatConfigIssues(resolved.issues, 4);
31
- const fingerprint = `${resolved.source ?? "defaults"}\n${resolved.modelKey ?? ""}\n${message}`;
32
- if (lastNotice.get(owner) === fingerprint) return;
33
- lastNotice.set(owner, fingerprint);
34
- ctx.ui.notify(`Toolkit configuration:\n${message}\nUse /toolkit-config validate for details.`,
35
- resolved.issues.some((issue) => issue.severity === "error") ? "error" : "warning");
36
- }
1
+ import type { ExtensionContext } from "@earendil-works/pi-coding-agent";
2
+ import type { ResolvedToolkitConfig } from "../config";
3
+ import {
4
+ RETIRED_AUTO_MODE_ISSUE, RETIRED_AUTO_MODE_MESSAGE,
5
+ RETIRED_REMOTE_WINDOWS_ISSUE, RETIRED_REMOTE_WINDOWS_MODE_ISSUE,
6
+ RETIRED_REMOTE_WINDOWS_CONFIG_MESSAGE, RETIRED_REMOTE_WINDOWS_MODE_MESSAGE,
7
+ type ConfigIssue,
8
+ } from "./policy";
9
+ import { redactValue } from "../debug";
10
+ import { detectRetiredRemoteWindows } from "../retired-remote-windows";
11
+
12
+ const lastNotice = new WeakMap<object, string>();
13
+
14
+ /** Controlled human text for a known code; never built from user-supplied configuration values. */
15
+ function issueExplanation(issue: ConfigIssue): string {
16
+ if (issue.code === RETIRED_AUTO_MODE_ISSUE) return RETIRED_AUTO_MODE_MESSAGE;
17
+ if (issue.code === RETIRED_REMOTE_WINDOWS_ISSUE) return RETIRED_REMOTE_WINDOWS_CONFIG_MESSAGE;
18
+ if (issue.code === RETIRED_REMOTE_WINDOWS_MODE_ISSUE) return RETIRED_REMOTE_WINDOWS_MODE_MESSAGE;
19
+ return issue.code;
20
+ }
21
+
22
+ export function formatConfigIssues(issues: readonly ConfigIssue[], limit = 12): string {
23
+ const lines = issues.slice(0, limit).map((issue) =>
24
+ `${issue.severity}: ${issue.path.slice(0, 220)} — ${issueExplanation(issue)}`);
25
+ if (issues.length > limit) lines.push(`${issues.length - limit} more issue(s); inspect the configuration file.`);
26
+ return String(redactValue(lines.join("\n")));
27
+ }
28
+
29
+ /** Per-session bounded notice, independent of feature enablement/debug. Never logs raw config. */
30
+ export function notifyConfigIssues(ctx: ExtensionContext, resolved: ResolvedToolkitConfig): void {
31
+ const owner = ctx.sessionManager ?? ctx;
32
+ if (!ctx.hasUI || typeof ctx.ui?.notify !== "function") return;
33
+ const hasRetiredWindows = resolved.issues.some((issue) => issue.code === RETIRED_REMOTE_WINDOWS_ISSUE)
34
+ && detectRetiredRemoteWindows(ctx.sessionManager.getBranch()) !== undefined;
35
+ const issues = resolved.issues.filter((issue) => issue.code !== RETIRED_REMOTE_WINDOWS_ISSUE || hasRetiredWindows);
36
+ if (issues.length === 0) {
37
+ lastNotice.delete(owner);
38
+ return;
39
+ }
40
+ const message = formatConfigIssues(issues, 4);
41
+ const fingerprint = `${resolved.source ?? "defaults"}\n${resolved.modelKey ?? ""}\n${message}`;
42
+ if (lastNotice.get(owner) === fingerprint) return;
43
+ lastNotice.set(owner, fingerprint);
44
+ ctx.ui.notify(`Toolkit configuration:\n${message}\nUse /toolkit-config validate for details.`,
45
+ issues.some((issue) => issue.severity === "error") ? "error" : "warning");
46
+ }
@@ -1,116 +1,115 @@
1
- import {
2
- DEFAULT_COMPACTION_CONFIG,
3
- DEFAULT_IMAGE_GENERATION_MODEL,
4
- type LeaveManagedModePolicy,
5
- type NativeFallbackConfig,
6
- type RemoteV2ContextSource,
7
- } from "../types";
8
-
9
- export type ConfigFeature = "context" | "webSearch" | "imageGeneration" | "compatibility" | "responsesWebSocket" | "diagnostics";
10
- export type SearchRoute = "unmanaged" | "local" | "hosted" | "standalone-alpha";
11
- export type DiagnosticsConfig = {
12
- level: "error" | "warn" | "info" | "debug";
13
- notifyOnLoad: boolean;
14
- captureRequests: boolean;
15
- /** Captures compact responses, not ordinary conversation responses. */
16
- captureResponses: boolean;
17
- redactSensitiveData: boolean;
18
- artifactRoot: string;
19
- };
20
- export type ContextPolicy = {
21
- mode: "pi" | "remote-compaction" | "remote-windows";
22
- remoteCompaction: {
23
- model: string | null;
24
- inputSource: RemoteV2ContextSource;
25
- allowContinuityBreak: boolean;
26
- apis: string[];
27
- };
28
- nativeFallback: Omit<NativeFallbackConfig, "model"> & { model: string | null };
29
- remoteWindows: {
30
- leaveManagedMode: LeaveManagedModePolicy;
31
- reminderThresholdPercent: number;
32
- };
33
- };
34
- export type EffectiveToolkitPolicy = {
35
- context: ContextPolicy;
36
- webSearch: { route: SearchRoute };
37
- imageGeneration: { enabled: boolean; defaultModel: string; allowedModels: string[] };
38
- responsesWebSocket: { enabled: boolean };
39
- compatibility: { transport: "standard" | "codex-gateway" };
40
- diagnostics: DiagnosticsConfig;
41
- };
42
- export type ConfigOrigin = {
43
- kind: "builtin" | "defaults" | "model" | "legacy";
44
- path?: string;
45
- source?: string;
46
- };
47
- export type ConfigIssue = {
48
- severity: "error" | "warning";
49
- /** Controlled code; do not include raw input values in messages. */
50
- code: string;
51
- path: string;
52
- feature: ConfigFeature | "document";
53
- /** Issues for a different model do not invalidate the selected model. */
54
- modelKey?: string;
55
- };
56
- /**
57
- * Stable code for a configuration section that was removed from the Toolkit. A retired section is
58
- * ignored in any shape and must never invalidate another feature, so it is reported as a warning.
59
- */
60
- export const RETIRED_AUTO_MODE_ISSUE = "retired.autoMode" as const;
61
- /** Controlled explanation of the retirement; never contains user-supplied values. */
62
- export const RETIRED_AUTO_MODE_MESSAGE =
63
- "Auto Mode has been removed; these settings are ignored and tool calls are no longer reviewed by it.";
64
- export type ResolvedToolkitPolicy = {
65
- policy: EffectiveToolkitPolicy;
66
- origins: Record<string, ConfigOrigin>;
67
- issues: ConfigIssue[];
68
- invalidFeatures: ConfigFeature[];
69
- };
70
- export type ConfigDocumentSnapshot = {
71
- format: "legacy" | "v2" | "missing" | "invalid";
72
- configPath: string;
73
- /** In-memory only; never render arbitrary raw configuration values. */
74
- raw?: unknown;
75
- issues: ConfigIssue[];
76
- };
77
- export const CONFIG_FEATURES: readonly ConfigFeature[] = [
78
- "context", "webSearch", "imageGeneration", "compatibility", "responsesWebSocket", "diagnostics",
79
- ];
80
-
81
- /** Independent per-operation defaults, preserving the existing shipped policy. */
82
- export function createPolicyDefaults(): EffectiveToolkitPolicy {
83
- const context = DEFAULT_COMPACTION_CONFIG;
84
- return {
85
- context: {
86
- mode: "remote-compaction",
87
- remoteCompaction: {
88
- model: null,
89
- inputSource: context.remoteV2ContextSource,
90
- allowContinuityBreak: context.allowCompactionContinuityBreak,
91
- apis: [...context.responsesApis],
92
- },
93
- nativeFallback: { ...context.nativeFallback, model: null },
94
- remoteWindows: {
95
- leaveManagedMode: context.leaveManagedMode,
96
- reminderThresholdPercent: context.contextReminderThresholdPercent,
97
- },
98
- },
99
- webSearch: { route: "unmanaged" },
100
- imageGeneration: {
101
- enabled: false,
102
- defaultModel: DEFAULT_IMAGE_GENERATION_MODEL,
103
- allowedModels: [DEFAULT_IMAGE_GENERATION_MODEL],
104
- },
105
- responsesWebSocket: { enabled: false },
106
- compatibility: { transport: "standard" },
107
- diagnostics: {
108
- level: "info",
109
- notifyOnLoad: context.notifyOnLoad,
110
- captureRequests: context.logProviderPayloads,
111
- captureResponses: context.logCompactResponses,
112
- redactSensitiveData: context.redactSensitiveData,
113
- artifactRoot: context.artifactRoot,
114
- },
115
- };
116
- }
1
+ import {
2
+ DEFAULT_COMPACTION_CONFIG,
3
+ DEFAULT_IMAGE_GENERATION_MODEL,
4
+ type NativeFallbackConfig,
5
+ type RemoteV2ContextSource,
6
+ } from "../types";
7
+
8
+ export type ConfigFeature = "context" | "webSearch" | "imageGeneration" | "compatibility" | "responsesWebSocket" | "diagnostics";
9
+ export type SearchRoute = "unmanaged" | "local" | "hosted" | "standalone-alpha";
10
+ export type DiagnosticsConfig = {
11
+ level: "error" | "warn" | "info" | "debug";
12
+ notifyOnLoad: boolean;
13
+ captureRequests: boolean;
14
+ /** Captures compact responses, not ordinary conversation responses. */
15
+ captureResponses: boolean;
16
+ redactSensitiveData: boolean;
17
+ artifactRoot: string;
18
+ };
19
+ export type ContextPolicy = {
20
+ mode: "pi" | "remote-compaction";
21
+ remoteCompaction: {
22
+ model: string | null;
23
+ inputSource: RemoteV2ContextSource;
24
+ allowContinuityBreak: boolean;
25
+ apis: string[];
26
+ };
27
+ nativeFallback: Omit<NativeFallbackConfig, "model"> & { model: string | null };
28
+ };
29
+ export type EffectiveToolkitPolicy = {
30
+ context: ContextPolicy;
31
+ webSearch: { route: SearchRoute };
32
+ imageGeneration: { enabled: boolean; defaultModel: string; allowedModels: string[] };
33
+ responsesWebSocket: { enabled: boolean };
34
+ compatibility: { transport: "standard" | "codex-gateway" };
35
+ diagnostics: DiagnosticsConfig;
36
+ };
37
+ export type ConfigOrigin = {
38
+ kind: "builtin" | "defaults" | "model" | "legacy";
39
+ path?: string;
40
+ source?: string;
41
+ };
42
+ export type ConfigIssue = {
43
+ severity: "error" | "warning";
44
+ /** Controlled code; do not include raw input values in messages. */
45
+ code: string;
46
+ path: string;
47
+ feature: ConfigFeature | "document";
48
+ /** Issues for a different model do not invalidate the selected model. */
49
+ modelKey?: string;
50
+ };
51
+ /**
52
+ * Stable code for a configuration section that was removed from the Toolkit. A retired section is
53
+ * ignored in any shape and must never invalidate another feature, so it is reported as a warning.
54
+ */
55
+ export const RETIRED_AUTO_MODE_ISSUE = "retired.autoMode" as const;
56
+ /** Controlled explanation of the retirement; never contains user-supplied values. */
57
+ export const RETIRED_AUTO_MODE_MESSAGE =
58
+ "Auto Mode has been removed; these settings are ignored and tool calls are no longer reviewed by it.";
59
+ /** Opaque ancillary settings are warning-only; explicitly selected retired modes block context. */
60
+ export const RETIRED_REMOTE_WINDOWS_ISSUE = "retired.remoteWindows" as const;
61
+ export const RETIRED_REMOTE_WINDOWS_MODE_ISSUE = "retired.remoteWindows.mode" as const;
62
+ export const RETIRED_REMOTE_WINDOWS_CONFIG_MESSAGE =
63
+ "Remote Windows has been removed; these settings are ignored. No window behavior or automatic migration is available.";
64
+ export const RETIRED_REMOTE_WINDOWS_MODE_MESSAGE =
65
+ "Remote Windows has been removed. Context operations are blocked until you explicitly select pi or remote-compaction. No replacement mode was activated.";
66
+
67
+ export type ResolvedToolkitPolicy = {
68
+ policy: EffectiveToolkitPolicy;
69
+ origins: Record<string, ConfigOrigin>;
70
+ issues: ConfigIssue[];
71
+ invalidFeatures: ConfigFeature[];
72
+ };
73
+ export type ConfigDocumentSnapshot = {
74
+ format: "legacy" | "v2" | "missing" | "invalid";
75
+ configPath: string;
76
+ /** In-memory only; never render arbitrary raw configuration values. */
77
+ raw?: unknown;
78
+ issues: ConfigIssue[];
79
+ };
80
+ export const CONFIG_FEATURES: readonly ConfigFeature[] = [
81
+ "context", "webSearch", "imageGeneration", "compatibility", "responsesWebSocket", "diagnostics",
82
+ ];
83
+
84
+ /** Independent per-operation defaults, preserving the existing shipped policy. */
85
+ export function createPolicyDefaults(): EffectiveToolkitPolicy {
86
+ const context = DEFAULT_COMPACTION_CONFIG;
87
+ return {
88
+ context: {
89
+ mode: "remote-compaction",
90
+ remoteCompaction: {
91
+ model: null,
92
+ inputSource: context.remoteV2ContextSource,
93
+ allowContinuityBreak: context.allowCompactionContinuityBreak,
94
+ apis: [...context.responsesApis],
95
+ },
96
+ nativeFallback: { ...context.nativeFallback, model: null },
97
+ },
98
+ webSearch: { route: "unmanaged" },
99
+ imageGeneration: {
100
+ enabled: false,
101
+ defaultModel: DEFAULT_IMAGE_GENERATION_MODEL,
102
+ allowedModels: [DEFAULT_IMAGE_GENERATION_MODEL],
103
+ },
104
+ responsesWebSocket: { enabled: false },
105
+ compatibility: { transport: "standard" },
106
+ diagnostics: {
107
+ level: "info",
108
+ notifyOnLoad: context.notifyOnLoad,
109
+ captureRequests: context.logProviderPayloads,
110
+ captureResponses: context.logCompactResponses,
111
+ redactSensitiveData: context.redactSensitiveData,
112
+ artifactRoot: context.artifactRoot,
113
+ },
114
+ };
115
+ }