@pasko70/pibo 1.16.6 → 2.0.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.
Files changed (145) hide show
  1. package/dist/agent-runtime/auth.js +28 -0
  2. package/dist/agent-runtime/capabilities.js +221 -0
  3. package/dist/agent-runtime/context-build.js +313 -0
  4. package/dist/agent-runtime/contract.js +45 -0
  5. package/dist/agent-runtime/errors.js +57 -0
  6. package/dist/agent-runtime/events.js +1 -0
  7. package/dist/agent-runtime/history.js +1 -0
  8. package/dist/agent-runtime/profile-validation.js +109 -0
  9. package/dist/agent-runtime/registry.js +608 -0
  10. package/dist/agent-runtime/resource-files.js +87 -0
  11. package/dist/agent-runtime/resource-service.js +635 -0
  12. package/dist/agent-runtime/resources.js +1 -0
  13. package/dist/agent-runtime/routed-session.js +931 -0
  14. package/dist/agent-runtime/testing/contract.js +51 -0
  15. package/dist/agent-runtime/testing/fake-adapter.js +192 -0
  16. package/dist/agent-runtime/types.js +3 -0
  17. package/dist/agent-runtimes/codex-native/adapter.js +905 -0
  18. package/dist/agent-runtimes/codex-native/auth.js +476 -0
  19. package/dist/agent-runtimes/codex-native/client.js +734 -0
  20. package/dist/agent-runtimes/codex-native/config.js +152 -0
  21. package/dist/agent-runtimes/codex-native/history.js +283 -0
  22. package/dist/agent-runtimes/codex-native/mcp-stdio-launcher.js +89 -0
  23. package/dist/agent-runtimes/codex-native/models.js +581 -0
  24. package/dist/agent-runtimes/codex-native/process.js +459 -0
  25. package/dist/agent-runtimes/codex-native/protocol-types.js +1 -0
  26. package/dist/agent-runtimes/codex-native/protocol-version.js +7 -0
  27. package/dist/agent-runtimes/codex-native/redaction.js +31 -0
  28. package/dist/agent-runtimes/codex-native/requests.js +378 -0
  29. package/dist/agent-runtimes/codex-native/resource-delivery.js +445 -0
  30. package/dist/agent-runtimes/codex-native/thread.js +388 -0
  31. package/dist/agent-runtimes/codex-native/turn.js +849 -0
  32. package/dist/agent-runtimes/pi/adapter.js +653 -0
  33. package/dist/agent-runtimes/pi/auth.js +455 -0
  34. package/dist/agent-runtimes/pi/history.js +640 -0
  35. package/dist/agent-runtimes/pi/model-catalog.js +87 -0
  36. package/dist/agent-runtimes/pi/routed-session.js +1464 -0
  37. package/dist/agent-runtimes/pi/runtime.js +534 -0
  38. package/dist/agent-runtimes/pi/tool-compiler.js +69 -0
  39. package/dist/apps/chat/agent-profiles.js +40 -23
  40. package/dist/apps/chat/agent-store.js +111 -64
  41. package/dist/apps/chat/chat-api-routes.js +1 -1
  42. package/dist/apps/chat/chat-request-normalizers.js +47 -0
  43. package/dist/apps/chat/data/chat-data-mappers.js +25 -9
  44. package/dist/apps/chat/data/history-query-service.js +108 -0
  45. package/dist/apps/chat/data/session-query-service.js +24 -3
  46. package/dist/apps/chat/data/timeline-query-service.js +3 -3
  47. package/dist/apps/chat/model-catalog.js +1 -55
  48. package/dist/apps/chat/provider-auth-actions.js +171 -23
  49. package/dist/apps/chat/stream.js +12 -0
  50. package/dist/apps/chat/trace-v2.js +1 -0
  51. package/dist/apps/chat/trace.js +126 -415
  52. package/dist/apps/chat/web-app.js +582 -157
  53. package/dist/apps/chat-ui/assets/{dist-BTLtT_Vf.js → dist-9v2ZXT6V.js} +1 -1
  54. package/dist/apps/chat-ui/assets/{dist-CMk1aPug.js → dist-B1LVAytl.js} +1 -1
  55. package/dist/apps/chat-ui/assets/{dist-CcwA_IWN.js → dist-C6LPDFXU.js} +1 -1
  56. package/dist/apps/chat-ui/assets/{dist-DKOthbxr.js → dist-DVtXxfHc.js} +1 -1
  57. package/dist/apps/chat-ui/assets/{dist-ls2I6BIw.js → dist-DW4Qrfbd.js} +1 -1
  58. package/dist/apps/chat-ui/assets/{dist-D1rAtRWs.js → dist-DmbsHdMC.js} +1 -1
  59. package/dist/apps/chat-ui/assets/{dist-C1JQRskW.js → dist-DyvwuSFO.js} +1 -1
  60. package/dist/apps/chat-ui/assets/{dist-DfpaylQ-.js → dist-I26VB0QO.js} +1 -1
  61. package/dist/apps/chat-ui/assets/{dist-D10bTFD5.js → dist-RtHbJRPV.js} +1 -1
  62. package/dist/apps/chat-ui/assets/{dist-5KpmmBBZ.js → dist-sZgJkWZb.js} +1 -1
  63. package/dist/apps/chat-ui/assets/index-BPbNvcZe.css +1 -0
  64. package/dist/apps/chat-ui/assets/index-CIOf2uL2.js +237 -0
  65. package/dist/apps/chat-ui/index.html +2 -2
  66. package/dist/apps/chat-vscode-web/assets/index-1ivRyjFs.js +41 -0
  67. package/dist/apps/chat-vscode-web/index.html +1 -1
  68. package/dist/apps/vscode-artifacts/latest.vsix +0 -0
  69. package/dist/apps/vscode-artifacts/pibo-vscode-ext-2.0.0.vsix +0 -0
  70. package/dist/auth/login-actions.js +5 -251
  71. package/dist/cli-session/localSessionSource.js +8 -1
  72. package/dist/core/context-build.js +124 -20
  73. package/dist/core/default-profile.js +8 -0
  74. package/dist/core/profiles.js +30 -3
  75. package/dist/core/routed-session.js +5 -1446
  76. package/dist/core/runtime.js +5 -561
  77. package/dist/core/session-router.js +637 -83
  78. package/dist/data/cli.js +20 -3
  79. package/dist/data/schema.js +104 -1
  80. package/dist/data/session-store.js +24 -1
  81. package/dist/debug/events.js +25 -10
  82. package/dist/debug/failures.js +23 -3
  83. package/dist/debug/index.js +24 -6
  84. package/dist/debug/messages.js +87 -7
  85. package/dist/debug/persisted-payloads.js +31 -0
  86. package/dist/debug/pty.js +7 -6
  87. package/dist/debug/runtime-binding.js +29 -0
  88. package/dist/debug/session.js +137 -0
  89. package/dist/debug/summary.js +12 -0
  90. package/dist/debug/telemetry.js +28 -0
  91. package/dist/debug/tools.js +12 -2
  92. package/dist/debug/trace.js +154 -76
  93. package/dist/gateway/server.js +87 -2
  94. package/dist/gateway/tool.js +5 -5
  95. package/dist/index.js +21 -2
  96. package/dist/loops/tools.js +13 -12
  97. package/dist/mcp/agent-context.js +13 -4
  98. package/dist/mcp/client.js +10 -6
  99. package/dist/mcp/config.js +5 -2
  100. package/dist/mcp/runtime-session.js +166 -0
  101. package/dist/plugins/builtin.js +191 -53
  102. package/dist/plugins/codex-native.js +29 -0
  103. package/dist/plugins/registry.js +66 -2
  104. package/dist/runs/tools.js +26 -25
  105. package/dist/session-ui/terminalRows.js +2 -2
  106. package/dist/sessions/pibo-data-store.js +125 -16
  107. package/dist/sessions/runtime-binding.js +107 -0
  108. package/dist/sessions/sqlite-store.js +239 -18
  109. package/dist/sessions/store.js +86 -7
  110. package/dist/shared/trace-engine.js +18 -9
  111. package/dist/shared/trace-event-projection.js +29 -11
  112. package/dist/shared/{trace-transcript.js → trace-history.js} +193 -195
  113. package/dist/shared/trace-order.js +9 -4
  114. package/dist/shared/trace-page-merge.js +1 -1
  115. package/dist/signals/projector.js +20 -2
  116. package/dist/signals/registry.js +11 -0
  117. package/dist/subagents/tool.js +8 -6
  118. package/dist/tools/codex-browser.js +20 -19
  119. package/dist/tools/codex-compat.js +10 -9
  120. package/dist/tools/codex-image-generation.js +8 -6
  121. package/dist/tools/contract.js +45 -0
  122. package/dist/tools/credential-registry.js +182 -0
  123. package/dist/tools/mcp-bridge.js +511 -0
  124. package/dist/tools/payload-writer.js +17 -0
  125. package/dist/tools/runtime/tool.js +10 -9
  126. package/dist/tools/schema.js +9 -0
  127. package/dist/tools/session-service.js +193 -0
  128. package/dist/tools/session-tool-set.js +85 -0
  129. package/dist/web-annotations/tools.js +17 -16
  130. package/docs/README.md +11 -0
  131. package/package.json +3 -2
  132. package/skills/builtin/pibo-agent-runtime-adapter/SKILL.md +183 -0
  133. package/skills/builtin/pibo-agent-runtime-adapter/evals/README.md +10 -0
  134. package/skills/builtin/pibo-agent-runtime-adapter/evals/evals.json +45 -0
  135. package/skills/builtin/pibo-agent-runtime-adapter/evals/fixtures/orion-full-harness.md +60 -0
  136. package/skills/builtin/pibo-agent-runtime-adapter/evals/fixtures/relay-partial-harness.md +52 -0
  137. package/skills/builtin/pibo-agent-runtime-adapter/references/capabilities-and-designer.md +194 -0
  138. package/skills/builtin/pibo-agent-runtime-adapter/references/history-debug-and-security.md +213 -0
  139. package/skills/builtin/pibo-agent-runtime-adapter/references/interfaces-and-registration.md +214 -0
  140. package/skills/builtin/pibo-agent-runtime-adapter/references/lifecycle-bindings-and-events.md +193 -0
  141. package/skills/builtin/pibo-agent-runtime-adapter/references/portable-delivery-and-native-behavior.md +226 -0
  142. package/skills/builtin/pibo-agent-runtime-adapter/references/testing-migration-and-validation.md +256 -0
  143. package/dist/apps/chat-ui/assets/index-C2YI0xfw.js +0 -237
  144. package/dist/apps/chat-ui/assets/index-E0RmuCkY.css +0 -1
  145. package/dist/apps/chat-vscode-web/assets/index-D-tSsXLG.js +0 -41
@@ -0,0 +1,581 @@
1
+ import { isPiboThinkingLevel } from "../../core/thinking.js";
2
+ export const CODEX_NATIVE_MODEL_PROVIDER_ID = "openai-codex";
3
+ export const CODEX_NATIVE_REASONING_VALUES = ["low", "medium", "high", "xhigh", "max"];
4
+ export const CODEX_NATIVE_MODEL_OPTIONS_SCHEMA = {
5
+ type: "object",
6
+ additionalProperties: false,
7
+ properties: {
8
+ serviceTier: {
9
+ type: "string",
10
+ description: "Optional native Codex service tier. Available values are listed in the selected model's options.",
11
+ },
12
+ personality: {
13
+ type: "string",
14
+ enum: ["none", "friendly", "pragmatic"],
15
+ description: "Optional native Codex response personality for models that support personality selection.",
16
+ },
17
+ reasoningSummary: {
18
+ type: "string",
19
+ enum: ["auto", "concise", "detailed", "none"],
20
+ description: "Optional native Codex reasoning-summary mode.",
21
+ },
22
+ },
23
+ };
24
+ const MAX_MODEL_PAGES = 20;
25
+ const MAX_MODEL_COUNT = 500;
26
+ const MODEL_PAGE_SIZE = 100;
27
+ const MAX_REASONING_OPTIONS = 32;
28
+ const MAX_SERVICE_TIERS = 32;
29
+ const MAX_INPUT_MODALITIES = 8;
30
+ const MAX_PENDING_THREAD_STATES = 8;
31
+ const MAX_IDENTIFIER_LENGTH = 256;
32
+ const MAX_LABEL_LENGTH = 512;
33
+ const MAX_DESCRIPTION_LENGTH = 4_096;
34
+ const MAX_CURSOR_LENGTH = 1_024;
35
+ const PERSONALITIES = new Set(["none", "friendly", "pragmatic"]);
36
+ const REASONING_SUMMARIES = new Set(["auto", "concise", "detailed", "none"]);
37
+ const BINDING_MODEL_KEY = "codexNativeModelId";
38
+ const BINDING_REASONING_KEY = "codexNativeReasoningEffort";
39
+ const BINDING_SERVICE_TIER_KEY = "codexNativeServiceTier";
40
+ const BINDING_PERSONALITY_KEY = "codexNativePersonality";
41
+ const BINDING_REASONING_SUMMARY_KEY = "codexNativeReasoningSummary";
42
+ export class CodexNativeModelProtocolError extends Error {
43
+ constructor(message) {
44
+ super(message);
45
+ this.name = "CodexNativeModelProtocolError";
46
+ }
47
+ }
48
+ function isRecord(value) {
49
+ return Boolean(value) && typeof value === "object" && !Array.isArray(value);
50
+ }
51
+ function requiredText(value, label, maxLength = MAX_LABEL_LENGTH) {
52
+ if (typeof value !== "string")
53
+ throw new CodexNativeModelProtocolError(`Codex ${label} must be a string.`);
54
+ if (value.length > maxLength)
55
+ throw new CodexNativeModelProtocolError(`Codex ${label} exceeds ${maxLength} characters.`);
56
+ return value;
57
+ }
58
+ function requiredString(value, label, maxLength = MAX_IDENTIFIER_LENGTH) {
59
+ const text = requiredText(value, label, maxLength);
60
+ if (!text.trim())
61
+ throw new CodexNativeModelProtocolError(`Codex ${label} must be a non-empty string.`);
62
+ return text;
63
+ }
64
+ function optionalStringOrNull(value, label) {
65
+ if (value === undefined)
66
+ return undefined;
67
+ if (value === null)
68
+ return null;
69
+ return requiredString(value, label);
70
+ }
71
+ function requiredBoolean(value, label) {
72
+ if (typeof value !== "boolean")
73
+ throw new CodexNativeModelProtocolError(`Codex ${label} must be a boolean.`);
74
+ return value;
75
+ }
76
+ function requiredNonNegativeNumber(value, label) {
77
+ if (typeof value !== "number" || !Number.isSafeInteger(value) || value < 0) {
78
+ throw new CodexNativeModelProtocolError(`Codex ${label} must be a non-negative safe integer.`);
79
+ }
80
+ return value;
81
+ }
82
+ function validateModel(value) {
83
+ if (!isRecord(value))
84
+ throw new CodexNativeModelProtocolError("Codex model/list returned an invalid model entry.");
85
+ if (!Array.isArray(value.supportedReasoningEfforts)) {
86
+ throw new CodexNativeModelProtocolError("Codex model/list returned a model without reasoning-effort options.");
87
+ }
88
+ if (value.supportedReasoningEfforts.length > MAX_REASONING_OPTIONS) {
89
+ throw new CodexNativeModelProtocolError(`Codex model/list returned more than ${MAX_REASONING_OPTIONS} reasoning-effort options for one model.`);
90
+ }
91
+ if (value.serviceTiers !== undefined && !Array.isArray(value.serviceTiers)) {
92
+ throw new CodexNativeModelProtocolError("Codex model/list returned invalid service tiers.");
93
+ }
94
+ if (Array.isArray(value.serviceTiers) && value.serviceTiers.length > MAX_SERVICE_TIERS) {
95
+ throw new CodexNativeModelProtocolError(`Codex model/list returned more than ${MAX_SERVICE_TIERS} service tiers for one model.`);
96
+ }
97
+ const supportedReasoningEfforts = value.supportedReasoningEfforts.map((entry, index) => {
98
+ if (!isRecord(entry))
99
+ throw new CodexNativeModelProtocolError(`Codex reasoning-effort option ${index} is invalid.`);
100
+ return {
101
+ reasoningEffort: requiredString(entry.reasoningEffort, `reasoning-effort option ${index} id`),
102
+ description: requiredText(entry.description, `reasoning-effort option ${index} description`, MAX_DESCRIPTION_LENGTH),
103
+ };
104
+ });
105
+ if (new Set(supportedReasoningEfforts.map((entry) => entry.reasoningEffort)).size !== supportedReasoningEfforts.length) {
106
+ throw new CodexNativeModelProtocolError("Codex model/list returned duplicate reasoning-effort ids for one model.");
107
+ }
108
+ const serviceTiers = (value.serviceTiers ?? []).map((entry, index) => {
109
+ if (!isRecord(entry))
110
+ throw new CodexNativeModelProtocolError(`Codex service-tier option ${index} is invalid.`);
111
+ return {
112
+ id: requiredString(entry.id, `service-tier option ${index} id`),
113
+ name: requiredText(entry.name, `service-tier option ${index} name`),
114
+ description: requiredText(entry.description, `service-tier option ${index} description`, MAX_DESCRIPTION_LENGTH),
115
+ };
116
+ });
117
+ if (new Set(serviceTiers.map((entry) => entry.id)).size !== serviceTiers.length) {
118
+ throw new CodexNativeModelProtocolError("Codex model/list returned duplicate service-tier ids for one model.");
119
+ }
120
+ const defaultReasoningEffort = requiredString(value.defaultReasoningEffort, "default reasoning effort");
121
+ if (!supportedReasoningEfforts.some((entry) => entry.reasoningEffort === defaultReasoningEffort)) {
122
+ throw new CodexNativeModelProtocolError(`Codex model default reasoning effort "${defaultReasoningEffort}" was not advertised by that model.`);
123
+ }
124
+ const defaultServiceTier = optionalStringOrNull(value.defaultServiceTier, "default service tier");
125
+ if (defaultServiceTier && !serviceTiers.some((entry) => entry.id === defaultServiceTier)) {
126
+ throw new CodexNativeModelProtocolError(`Codex model default service tier "${defaultServiceTier}" was not advertised by that model.`);
127
+ }
128
+ let inputModalities = ["text", "image"];
129
+ if (value.inputModalities !== undefined) {
130
+ if (!Array.isArray(value.inputModalities))
131
+ throw new CodexNativeModelProtocolError("Codex model input modalities must be an array.");
132
+ if (value.inputModalities.length > MAX_INPUT_MODALITIES) {
133
+ throw new CodexNativeModelProtocolError(`Codex model input modalities exceed ${MAX_INPUT_MODALITIES} entries.`);
134
+ }
135
+ inputModalities = value.inputModalities.map((entry, index) => requiredString(entry, `input modality ${index}`));
136
+ }
137
+ if (value.supportsPersonality !== undefined && typeof value.supportsPersonality !== "boolean") {
138
+ throw new CodexNativeModelProtocolError("Codex model personality support must be a boolean.");
139
+ }
140
+ return {
141
+ id: requiredString(value.id, "model id"),
142
+ model: requiredString(value.model, "model backend id"),
143
+ displayName: requiredText(value.displayName, "model display name"),
144
+ description: requiredText(value.description, "model description", MAX_DESCRIPTION_LENGTH),
145
+ hidden: requiredBoolean(value.hidden, "model hidden flag"),
146
+ isDefault: requiredBoolean(value.isDefault, "model default flag"),
147
+ supportedReasoningEfforts,
148
+ defaultReasoningEffort,
149
+ serviceTiers,
150
+ ...(defaultServiceTier !== undefined ? { defaultServiceTier } : {}),
151
+ inputModalities,
152
+ ...(value.supportsPersonality !== undefined ? { supportsPersonality: value.supportsPersonality } : {}),
153
+ ...(typeof value.modelSpecialty === "string" || value.modelSpecialty === null ? { modelSpecialty: value.modelSpecialty } : {}),
154
+ ...(typeof value.upgrade === "string" || value.upgrade === null ? { upgrade: value.upgrade } : {}),
155
+ };
156
+ }
157
+ function validateModelListResponse(value) {
158
+ if (!isRecord(value) || !Array.isArray(value.data)) {
159
+ throw new CodexNativeModelProtocolError("Codex model/list returned an invalid response.");
160
+ }
161
+ if (value.data.length > MAX_MODEL_COUNT) {
162
+ throw new CodexNativeModelProtocolError(`Codex model/list returned more than ${MAX_MODEL_COUNT} entries in one page.`);
163
+ }
164
+ const nextCursor = value.nextCursor === undefined || value.nextCursor === null
165
+ ? value.nextCursor
166
+ : requiredString(value.nextCursor, "model/list next cursor", MAX_CURSOR_LENGTH);
167
+ return {
168
+ data: value.data.map(validateModel),
169
+ ...(nextCursor !== undefined ? { nextCursor } : {}),
170
+ };
171
+ }
172
+ export async function readCodexNativeModelCatalog(client) {
173
+ const models = [];
174
+ const modelIds = new Set();
175
+ const cursors = new Set();
176
+ let cursor;
177
+ for (let page = 0; page < MAX_MODEL_PAGES; page++) {
178
+ const response = validateModelListResponse(await client.request("model/list", {
179
+ cursor: cursor ?? null,
180
+ limit: MODEL_PAGE_SIZE,
181
+ includeHidden: false,
182
+ }));
183
+ for (const model of response.data) {
184
+ if (model.hidden)
185
+ continue;
186
+ if (modelIds.has(model.id))
187
+ throw new CodexNativeModelProtocolError(`Codex model/list returned duplicate model id "${model.id}".`);
188
+ modelIds.add(model.id);
189
+ models.push(model);
190
+ if (models.length > MAX_MODEL_COUNT)
191
+ throw new CodexNativeModelProtocolError(`Codex model/list exceeded ${MAX_MODEL_COUNT} visible models.`);
192
+ }
193
+ cursor = response.nextCursor;
194
+ if (!cursor)
195
+ break;
196
+ if (cursors.has(cursor))
197
+ throw new CodexNativeModelProtocolError("Codex model/list repeated a pagination cursor.");
198
+ cursors.add(cursor);
199
+ if (page === MAX_MODEL_PAGES - 1)
200
+ throw new CodexNativeModelProtocolError(`Codex model/list exceeded ${MAX_MODEL_PAGES} pages.`);
201
+ }
202
+ if (models.length === 0)
203
+ throw new CodexNativeModelProtocolError("Codex model/list returned no visible models.");
204
+ return { models };
205
+ }
206
+ function modelOptions(model) {
207
+ return {
208
+ providerDisplayName: "OpenAI Codex",
209
+ backendModel: model.model,
210
+ description: model.description,
211
+ isDefault: model.isDefault,
212
+ defaultReasoningEffort: model.defaultReasoningEffort,
213
+ nativeReasoningEfforts: model.supportedReasoningEfforts.map((entry) => ({
214
+ id: entry.reasoningEffort,
215
+ description: entry.description,
216
+ })),
217
+ serviceTiers: model.serviceTiers.map((entry) => ({
218
+ id: entry.id,
219
+ name: entry.name,
220
+ description: entry.description,
221
+ })),
222
+ defaultServiceTier: model.defaultServiceTier ?? null,
223
+ inputModalities: model.inputModalities ?? [],
224
+ supportsPersonality: model.supportsPersonality ?? false,
225
+ ...(model.modelSpecialty !== undefined ? { modelSpecialty: model.modelSpecialty } : {}),
226
+ ...(model.upgrade !== undefined ? { upgrade: model.upgrade } : {}),
227
+ };
228
+ }
229
+ export function toAgentRuntimeModelCatalog(runtimeInstanceId, catalog) {
230
+ return {
231
+ runtimeInstanceId,
232
+ models: catalog.models.map((model) => ({
233
+ provider: CODEX_NATIVE_MODEL_PROVIDER_ID,
234
+ id: model.id,
235
+ displayName: model.displayName,
236
+ reasoningOptions: modelControlReasoningValues(model),
237
+ options: modelOptions(model),
238
+ })),
239
+ };
240
+ }
241
+ export function readCodexNativePersistedSettings(metadata) {
242
+ const profileOptions = {};
243
+ if (!metadata)
244
+ return { profileOptions };
245
+ const modelId = typeof metadata[BINDING_MODEL_KEY] === "string"
246
+ && metadata[BINDING_MODEL_KEY].length <= MAX_IDENTIFIER_LENGTH
247
+ && metadata[BINDING_MODEL_KEY].trim()
248
+ ? metadata[BINDING_MODEL_KEY]
249
+ : undefined;
250
+ const reasoningLevel = typeof metadata[BINDING_REASONING_KEY] === "string"
251
+ && metadata[BINDING_REASONING_KEY].length <= MAX_IDENTIFIER_LENGTH
252
+ && metadata[BINDING_REASONING_KEY].trim()
253
+ ? metadata[BINDING_REASONING_KEY]
254
+ : undefined;
255
+ const serviceTier = metadata[BINDING_SERVICE_TIER_KEY];
256
+ if (serviceTier === null || (typeof serviceTier === "string" && serviceTier.length <= MAX_IDENTIFIER_LENGTH && serviceTier.trim())) {
257
+ profileOptions.serviceTier = serviceTier;
258
+ }
259
+ const personality = metadata[BINDING_PERSONALITY_KEY];
260
+ if (personality === null || (typeof personality === "string" && PERSONALITIES.has(personality))) {
261
+ profileOptions.personality = personality;
262
+ }
263
+ const reasoningSummary = metadata[BINDING_REASONING_SUMMARY_KEY];
264
+ if (reasoningSummary === null || (typeof reasoningSummary === "string" && REASONING_SUMMARIES.has(reasoningSummary))) {
265
+ profileOptions.reasoningSummary = reasoningSummary;
266
+ }
267
+ return {
268
+ ...(modelId ? { activeModel: { provider: CODEX_NATIVE_MODEL_PROVIDER_ID, id: modelId } } : {}),
269
+ ...(reasoningLevel ? { reasoningLevel } : {}),
270
+ profileOptions,
271
+ };
272
+ }
273
+ export function parseCodexNativeProfileOptions(value) {
274
+ const allowed = new Set(["serviceTier", "personality", "reasoningSummary"]);
275
+ const unknown = Object.keys(value).filter((key) => !allowed.has(key));
276
+ if (unknown.length > 0)
277
+ throw new Error(`Unsupported native Codex runtime option${unknown.length === 1 ? "" : "s"}: ${unknown.join(", ")}.`);
278
+ const options = {};
279
+ if (Object.hasOwn(value, "serviceTier")) {
280
+ if (typeof value.serviceTier !== "string" || !value.serviceTier.trim()) {
281
+ throw new Error("Native Codex runtime option serviceTier must be a non-empty string.");
282
+ }
283
+ if (value.serviceTier.length > MAX_IDENTIFIER_LENGTH) {
284
+ throw new Error(`Native Codex runtime option serviceTier exceeds ${MAX_IDENTIFIER_LENGTH} characters.`);
285
+ }
286
+ options.serviceTier = value.serviceTier.trim();
287
+ }
288
+ if (Object.hasOwn(value, "personality")) {
289
+ if (typeof value.personality !== "string" || !PERSONALITIES.has(value.personality)) {
290
+ throw new Error("Native Codex runtime option personality must be one of: none, friendly, pragmatic.");
291
+ }
292
+ options.personality = value.personality;
293
+ }
294
+ if (Object.hasOwn(value, "reasoningSummary")) {
295
+ if (typeof value.reasoningSummary !== "string" || !REASONING_SUMMARIES.has(value.reasoningSummary)) {
296
+ throw new Error("Native Codex runtime option reasoningSummary must be one of: auto, concise, detailed, none.");
297
+ }
298
+ options.reasoningSummary = value.reasoningSummary;
299
+ }
300
+ return options;
301
+ }
302
+ function findModel(catalog, value) {
303
+ return catalog.models.find((model) => model.id === value || model.model === value);
304
+ }
305
+ function selectedModel(catalog, requested) {
306
+ if (requested && requested.provider !== CODEX_NATIVE_MODEL_PROVIDER_ID) {
307
+ throw new Error(`Native Codex models use provider "${CODEX_NATIVE_MODEL_PROVIDER_ID}", not "${requested.provider}".`);
308
+ }
309
+ if (requested) {
310
+ const model = catalog.models.find((entry) => entry.id === requested.id);
311
+ if (!model)
312
+ throw new Error(`Native Codex model "${requested.id}" is not available.`);
313
+ return model;
314
+ }
315
+ return catalog.models.find((model) => model.isDefault) ?? catalog.models[0];
316
+ }
317
+ function modelReasoningValues(model) {
318
+ return model.supportedReasoningEfforts.map((entry) => entry.reasoningEffort);
319
+ }
320
+ function modelControlReasoningValues(model) {
321
+ return modelReasoningValues(model).filter((value) => isPiboThinkingLevel(value)
322
+ && CODEX_NATIVE_REASONING_VALUES.includes(value));
323
+ }
324
+ function validateReasoning(model, value) {
325
+ if (!modelReasoningValues(model).includes(value)) {
326
+ throw new Error(`Native Codex model "${model.id}" does not support reasoning effort "${value}".`);
327
+ }
328
+ return value;
329
+ }
330
+ function validateServiceTier(model, value) {
331
+ if (value !== null && !model.serviceTiers.some((entry) => entry.id === value)) {
332
+ throw new Error(`Native Codex model "${model.id}" does not support service tier "${value}".`);
333
+ }
334
+ return value;
335
+ }
336
+ function normalizeNativeServiceTier(model, value) {
337
+ return value === "default" ? null : validateServiceTier(model, value);
338
+ }
339
+ function validatePersonality(model, value) {
340
+ if (value && value !== "none" && !model.supportsPersonality) {
341
+ throw new Error(`Native Codex model "${model.id}" does not support personality selection.`);
342
+ }
343
+ }
344
+ function setBoundedPending(map, threadId, value) {
345
+ if (!map.has(threadId) && map.size >= MAX_PENDING_THREAD_STATES) {
346
+ const oldest = map.keys().next().value;
347
+ if (oldest !== undefined)
348
+ map.delete(oldest);
349
+ }
350
+ map.set(threadId, value);
351
+ }
352
+ function parseContextUsage(value) {
353
+ if (!isRecord(value.tokenUsage) || !isRecord(value.tokenUsage.total)) {
354
+ throw new CodexNativeModelProtocolError("Codex token-usage notification is missing total usage.");
355
+ }
356
+ const total = value.tokenUsage.total;
357
+ const tokens = requiredNonNegativeNumber(total.totalTokens, "total token usage");
358
+ const contextWindow = value.tokenUsage.modelContextWindow === undefined || value.tokenUsage.modelContextWindow === null
359
+ ? undefined
360
+ : requiredNonNegativeNumber(value.tokenUsage.modelContextWindow, "model context window");
361
+ return {
362
+ tokens,
363
+ ...(contextWindow !== undefined ? {
364
+ contextWindow,
365
+ ...(contextWindow > 0 ? { percent: (tokens / contextWindow) * 100 } : {}),
366
+ } : {}),
367
+ };
368
+ }
369
+ export class CodexNativeSessionSettingsController {
370
+ catalog;
371
+ currentModel;
372
+ reasoningLevel;
373
+ reasoningExplicit;
374
+ serviceTier;
375
+ personality;
376
+ reasoningSummary;
377
+ activeThreadId;
378
+ contextUsage;
379
+ pendingContextUsage = new Map();
380
+ pendingThreadSettings = new Map();
381
+ pendingModelReroutes = new Map();
382
+ unsubscribe = () => { };
383
+ constructor(client, catalog, initial) {
384
+ this.catalog = catalog;
385
+ this.currentModel = selectedModel(catalog, initial.activeModel);
386
+ this.reasoningExplicit = initial.reasoningLevel !== undefined;
387
+ this.reasoningLevel = validateReasoning(this.currentModel, initial.reasoningLevel ?? this.currentModel.defaultReasoningEffort);
388
+ validatePersonality(this.currentModel, initial.profileOptions.personality);
389
+ const selectedTier = initial.initialFastMode
390
+ ? "priority"
391
+ : initial.profileOptions.serviceTier !== undefined
392
+ ? initial.profileOptions.serviceTier
393
+ : this.currentModel.defaultServiceTier ?? null;
394
+ this.serviceTier = validateServiceTier(this.currentModel, selectedTier);
395
+ this.personality = initial.profileOptions.personality;
396
+ this.reasoningSummary = initial.profileOptions.reasoningSummary;
397
+ this.bindClient(client);
398
+ }
399
+ bindClient(client) {
400
+ this.unsubscribe();
401
+ this.unsubscribe = client.subscribeNotifications((notification) => this.handleNotification(notification));
402
+ }
403
+ attachThread(threadId, configuration) {
404
+ this.activeThreadId = threadId;
405
+ const configuredModel = findModel(this.catalog, configuration.model);
406
+ if (!configuredModel)
407
+ throw new CodexNativeModelProtocolError(`Codex selected unadvertised model "${configuration.model}".`);
408
+ this.applyNativeModel(configuredModel);
409
+ if (!this.reasoningExplicit && configuration.reasoningEffort) {
410
+ this.reasoningLevel = validateReasoning(this.currentModel, configuration.reasoningEffort);
411
+ }
412
+ if (configuration.serviceTier !== undefined) {
413
+ this.serviceTier = normalizeNativeServiceTier(this.currentModel, configuration.serviceTier ?? null);
414
+ }
415
+ const pendingSettings = this.pendingThreadSettings.get(threadId);
416
+ if (pendingSettings)
417
+ this.applyThreadSettings(pendingSettings);
418
+ const pendingReroute = this.pendingModelReroutes.get(threadId);
419
+ if (pendingReroute)
420
+ this.applyModelReroute(pendingReroute);
421
+ const pendingContext = this.pendingContextUsage.get(threadId);
422
+ if (pendingContext)
423
+ this.contextUsage = pendingContext;
424
+ this.pendingThreadSettings.clear();
425
+ this.pendingModelReroutes.clear();
426
+ this.pendingContextUsage.clear();
427
+ }
428
+ get activeModel() {
429
+ return { provider: CODEX_NATIVE_MODEL_PROVIDER_ID, id: this.currentModel.id };
430
+ }
431
+ get reasoning() {
432
+ const availableValues = modelControlReasoningValues(this.currentModel);
433
+ return {
434
+ value: this.reasoningLevel,
435
+ availableValues,
436
+ supported: availableValues.length > 0,
437
+ };
438
+ }
439
+ get fastMode() {
440
+ return {
441
+ mode: this.serviceTier === "priority" ? "fast" : "normal",
442
+ supported: this.currentModel.serviceTiers.some((entry) => entry.id === "priority"),
443
+ };
444
+ }
445
+ get currentContextUsage() {
446
+ return this.contextUsage ? structuredClone(this.contextUsage) : undefined;
447
+ }
448
+ get bindingMetadata() {
449
+ return {
450
+ [BINDING_MODEL_KEY]: this.currentModel.id,
451
+ [BINDING_REASONING_KEY]: this.reasoningLevel,
452
+ [BINDING_SERVICE_TIER_KEY]: this.serviceTier,
453
+ [BINDING_PERSONALITY_KEY]: this.personality ?? null,
454
+ [BINDING_REASONING_SUMMARY_KEY]: this.reasoningSummary ?? null,
455
+ };
456
+ }
457
+ get threadSelection() {
458
+ return {
459
+ model: this.currentModel.id,
460
+ serviceTier: this.serviceTier,
461
+ ...(this.personality !== undefined ? { personality: this.personality } : {}),
462
+ };
463
+ }
464
+ get turnOptions() {
465
+ return {
466
+ model: this.currentModel.id,
467
+ effort: this.reasoningLevel,
468
+ serviceTier: this.serviceTier,
469
+ ...(this.reasoningSummary !== undefined ? { summary: this.reasoningSummary } : {}),
470
+ ...(this.personality !== undefined ? { personality: this.personality } : {}),
471
+ };
472
+ }
473
+ setModel(model) {
474
+ const next = selectedModel(this.catalog, model);
475
+ validatePersonality(next, this.personality);
476
+ this.applyNativeModel(next);
477
+ return this.activeModel;
478
+ }
479
+ setReasoning(level) {
480
+ if (!isPiboThinkingLevel(level) || !CODEX_NATIVE_REASONING_VALUES.includes(level)) {
481
+ throw new Error(`Pibo cannot select native Codex reasoning effort "${level}".`);
482
+ }
483
+ this.reasoningLevel = validateReasoning(this.currentModel, level);
484
+ this.reasoningExplicit = true;
485
+ return this.reasoning;
486
+ }
487
+ cycleReasoning() {
488
+ const values = modelControlReasoningValues(this.currentModel);
489
+ if (values.length === 0)
490
+ return this.reasoning;
491
+ const currentIndex = values.indexOf(this.reasoningLevel);
492
+ this.reasoningLevel = values[(currentIndex + 1 + values.length) % values.length];
493
+ this.reasoningExplicit = true;
494
+ return this.reasoning;
495
+ }
496
+ setFastMode(enabled) {
497
+ const supported = this.currentModel.serviceTiers.some((entry) => entry.id === "priority");
498
+ if (enabled && !supported)
499
+ return { ...this.fastMode, changed: false };
500
+ const nextTier = enabled ? "priority" : this.currentModel.defaultServiceTier ?? null;
501
+ const changed = this.serviceTier !== nextTier;
502
+ this.serviceTier = nextTier;
503
+ return { ...this.fastMode, changed };
504
+ }
505
+ dispose() {
506
+ this.unsubscribe();
507
+ this.pendingContextUsage.clear();
508
+ this.pendingThreadSettings.clear();
509
+ this.pendingModelReroutes.clear();
510
+ }
511
+ applyNativeModel(model) {
512
+ const reasoning = modelReasoningValues(model).includes(this.reasoningLevel)
513
+ ? this.reasoningLevel
514
+ : model.defaultReasoningEffort;
515
+ const tier = this.serviceTier === null || model.serviceTiers.some((entry) => entry.id === this.serviceTier)
516
+ ? this.serviceTier
517
+ : model.defaultServiceTier ?? null;
518
+ validatePersonality(model, this.personality);
519
+ this.currentModel = model;
520
+ this.reasoningLevel = validateReasoning(model, reasoning);
521
+ this.serviceTier = validateServiceTier(model, tier);
522
+ }
523
+ handleNotification(notification) {
524
+ if (notification.method === "thread/tokenUsage/updated") {
525
+ if (!isRecord(notification.params))
526
+ throw new CodexNativeModelProtocolError("Codex token-usage notification is invalid.");
527
+ const threadId = requiredString(notification.params.threadId, "token-usage thread id");
528
+ const usage = parseContextUsage(notification.params);
529
+ if (threadId === this.activeThreadId)
530
+ this.contextUsage = usage;
531
+ else
532
+ setBoundedPending(this.pendingContextUsage, threadId, usage);
533
+ return;
534
+ }
535
+ if (notification.method === "thread/settings/updated") {
536
+ if (!isRecord(notification.params) || !isRecord(notification.params.threadSettings)) {
537
+ throw new CodexNativeModelProtocolError("Codex thread-settings notification is invalid.");
538
+ }
539
+ const update = notification.params;
540
+ const threadId = requiredString(update.threadId, "thread-settings thread id");
541
+ if (threadId === this.activeThreadId)
542
+ this.applyThreadSettings(update);
543
+ else
544
+ setBoundedPending(this.pendingThreadSettings, threadId, update);
545
+ return;
546
+ }
547
+ if (notification.method === "model/rerouted") {
548
+ if (!isRecord(notification.params))
549
+ throw new CodexNativeModelProtocolError("Codex model-rerouted notification is invalid.");
550
+ const reroute = notification.params;
551
+ const threadId = requiredString(reroute.threadId, "model-rerouted thread id");
552
+ if (threadId === this.activeThreadId)
553
+ this.applyModelReroute(reroute);
554
+ else
555
+ setBoundedPending(this.pendingModelReroutes, threadId, reroute);
556
+ }
557
+ }
558
+ applyThreadSettings(update) {
559
+ const settings = update.threadSettings;
560
+ const modelId = requiredString(settings.model, "thread-settings model");
561
+ const model = findModel(this.catalog, modelId);
562
+ if (!model)
563
+ throw new CodexNativeModelProtocolError(`Codex selected unadvertised model "${modelId}".`);
564
+ this.applyNativeModel(model);
565
+ if (settings.effort !== undefined) {
566
+ this.reasoningLevel = settings.effort === null
567
+ ? model.defaultReasoningEffort
568
+ : validateReasoning(model, requiredString(settings.effort, "thread-settings reasoning effort"));
569
+ }
570
+ if (settings.serviceTier !== undefined) {
571
+ this.serviceTier = normalizeNativeServiceTier(model, optionalStringOrNull(settings.serviceTier, "thread-settings service tier") ?? null);
572
+ }
573
+ }
574
+ applyModelReroute(reroute) {
575
+ const targetId = requiredString(reroute.toModel, "rerouted model id");
576
+ const model = findModel(this.catalog, targetId);
577
+ if (!model)
578
+ throw new CodexNativeModelProtocolError(`Codex rerouted to unadvertised model "${targetId}".`);
579
+ this.applyNativeModel(model);
580
+ }
581
+ }