@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,378 @@
1
+ import { randomUUID } from "node:crypto";
2
+ import { CodexAppServerServerRequestCancelledError, } from "./client.js";
3
+ import { redactCodexNativeSensitiveText, redactCodexNativeValue } from "./redaction.js";
4
+ const MAX_REQUEST_TEXT_LENGTH = 4_000;
5
+ const MAX_USER_INPUT_ANSWER_LENGTH = 16_000;
6
+ const MAX_USER_INPUT_QUESTIONS = 10;
7
+ const MAX_USER_INPUT_OPTIONS = 20;
8
+ const APPROVAL_DECISIONS = [
9
+ { id: "accept", label: "Approve once", description: "Allow this action once." },
10
+ { id: "acceptForSession", label: "Approve for session", description: "Allow matching actions for the rest of this native session." },
11
+ { id: "decline", label: "Decline", description: "Deny this action and let the turn continue." },
12
+ { id: "cancel", label: "Cancel turn", description: "Deny this action and interrupt the active turn." },
13
+ ];
14
+ const APPROVAL_DECISION_IDS = new Set(APPROVAL_DECISIONS.map((decision) => decision.id));
15
+ function deferred() {
16
+ let resolve;
17
+ let reject;
18
+ const promise = new Promise((resolvePromise, rejectPromise) => {
19
+ resolve = resolvePromise;
20
+ reject = rejectPromise;
21
+ });
22
+ return { promise, resolve, reject };
23
+ }
24
+ function isRecord(value) {
25
+ return Boolean(value) && typeof value === "object" && !Array.isArray(value);
26
+ }
27
+ function requiredRecord(value, label) {
28
+ if (!isRecord(value))
29
+ throw new Error(`Codex ${label} is invalid.`);
30
+ return value;
31
+ }
32
+ function requiredString(value, label) {
33
+ if (typeof value !== "string" || !value)
34
+ throw new Error(`Codex ${label} is invalid.`);
35
+ return value;
36
+ }
37
+ function requiredInteger(value, label) {
38
+ if (!Number.isSafeInteger(value))
39
+ throw new Error(`Codex ${label} is invalid.`);
40
+ return Number(value);
41
+ }
42
+ function boundedText(value, fallback = "") {
43
+ if (typeof value !== "string")
44
+ return fallback;
45
+ return redactCodexNativeSensitiveText(value).slice(0, MAX_REQUEST_TEXT_LENGTH);
46
+ }
47
+ function jsonValue(value) {
48
+ return redactCodexNativeValue(value);
49
+ }
50
+ function nativeRequestKey(requestId) {
51
+ return `${typeof requestId}:${String(requestId)}`;
52
+ }
53
+ function cloneApproval(request) {
54
+ return structuredClone(request);
55
+ }
56
+ function cloneUserInput(request) {
57
+ return structuredClone(request);
58
+ }
59
+ function validateScope(params, expectedThreadId, activeTurnId, label) {
60
+ const threadId = requiredString(params.threadId, `${label} thread id`);
61
+ const turnId = requiredString(params.turnId, `${label} turn id`);
62
+ const itemId = requiredString(params.itemId, `${label} item id`);
63
+ if (threadId !== expectedThreadId)
64
+ throw new Error(`Codex ${label} belongs to a different native thread.`);
65
+ if (!activeTurnId || turnId !== activeTurnId)
66
+ throw new Error(`Codex ${label} does not match the active native turn.`);
67
+ return { threadId, turnId, itemId };
68
+ }
69
+ function approvalRequest(requestId, requestType, params) {
70
+ if (requestType === "command_execution") {
71
+ const command = boundedText(params.command, "Codex command");
72
+ const reason = boundedText(params.reason);
73
+ const argumentsValue = {
74
+ command,
75
+ itemId: requiredString(params.itemId, "command approval item id"),
76
+ };
77
+ if (Array.isArray(params.commandActions))
78
+ argumentsValue.commandActions = jsonValue(params.commandActions);
79
+ if (params.networkApprovalContext !== undefined && params.networkApprovalContext !== null) {
80
+ argumentsValue.networkApprovalContext = jsonValue(params.networkApprovalContext);
81
+ }
82
+ if (params.proposedExecpolicyAmendment !== undefined && params.proposedExecpolicyAmendment !== null) {
83
+ argumentsValue.proposedExecpolicyAmendment = jsonValue(params.proposedExecpolicyAmendment);
84
+ }
85
+ if (params.proposedNetworkPolicyAmendments !== undefined && params.proposedNetworkPolicyAmendments !== null) {
86
+ argumentsValue.proposedNetworkPolicyAmendments = jsonValue(params.proposedNetworkPolicyAmendments);
87
+ }
88
+ return {
89
+ requestId,
90
+ requestType,
91
+ title: "Run Codex command",
92
+ ...(reason ? { detail: reason } : {}),
93
+ arguments: argumentsValue,
94
+ decisions: APPROVAL_DECISIONS.map((decision) => ({ ...decision })),
95
+ };
96
+ }
97
+ const reason = boundedText(params.reason);
98
+ const argumentsValue = {
99
+ itemId: requiredString(params.itemId, "file approval item id"),
100
+ };
101
+ if (typeof params.grantRoot === "string" && params.grantRoot) {
102
+ argumentsValue.grantRoot = boundedText(params.grantRoot);
103
+ }
104
+ return {
105
+ requestId,
106
+ requestType,
107
+ title: "Apply Codex file changes",
108
+ ...(reason ? { detail: reason } : {}),
109
+ arguments: argumentsValue,
110
+ decisions: APPROVAL_DECISIONS.map((decision) => ({ ...decision })),
111
+ };
112
+ }
113
+ function validateOptions(value, questionId) {
114
+ if (value === undefined || value === null)
115
+ return undefined;
116
+ if (!Array.isArray(value) || value.length > MAX_USER_INPUT_OPTIONS) {
117
+ throw new Error(`Codex user-input options for question "${questionId}" are invalid.`);
118
+ }
119
+ return value.map((entry) => {
120
+ const option = requiredRecord(entry, "user-input option");
121
+ return {
122
+ label: boundedText(requiredString(option.label, "user-input option label")),
123
+ ...(typeof option.description === "string"
124
+ ? { description: boundedText(option.description) }
125
+ : {}),
126
+ };
127
+ });
128
+ }
129
+ function userInputQuestion(value) {
130
+ const question = requiredRecord(value, "user-input question");
131
+ const id = requiredString(question.id, "user-input question id");
132
+ return {
133
+ id,
134
+ header: boundedText(requiredString(question.header, "user-input question header")),
135
+ question: boundedText(requiredString(question.question, "user-input question text")),
136
+ options: validateOptions(question.options, id),
137
+ multiSelect: false,
138
+ allowFreeform: question.isOther === true,
139
+ secret: question.isSecret === true,
140
+ };
141
+ }
142
+ function normalizeAnswers(request, answers) {
143
+ const expected = new Set(request.questions.map((question) => question.id));
144
+ for (const key of Object.keys(answers)) {
145
+ if (!expected.has(key))
146
+ throw new Error(`Unknown answer id "${key}" for runtime user-input request.`);
147
+ }
148
+ const normalized = {};
149
+ for (const question of request.questions) {
150
+ const value = answers[question.id];
151
+ const values = typeof value === "string"
152
+ ? [value]
153
+ : Array.isArray(value) && value.every((entry) => typeof entry === "string")
154
+ ? value
155
+ : undefined;
156
+ if (!values || values.length === 0 || values.some((entry) => entry.length > MAX_USER_INPUT_ANSWER_LENGTH)) {
157
+ throw new Error(`Runtime user-input question "${question.id}" requires at least one bounded string answer.`);
158
+ }
159
+ if (question.multiSelect !== true && values.length > 1) {
160
+ throw new Error(`Runtime user-input question "${question.id}" accepts one answer.`);
161
+ }
162
+ if (question.options?.length && !question.allowFreeform) {
163
+ const allowed = new Set(question.options.map((option) => option.label));
164
+ if (values.some((entry) => !allowed.has(entry))) {
165
+ throw new Error(`Runtime user-input question "${question.id}" requires a listed option.`);
166
+ }
167
+ }
168
+ normalized[question.id] = { answers: [...values] };
169
+ }
170
+ return { answers: normalized };
171
+ }
172
+ export class CodexNativeRequestController {
173
+ client;
174
+ getThreadId;
175
+ getActiveTurnId;
176
+ structuredUserInputEnabled;
177
+ emit;
178
+ pendingByProductId = new Map();
179
+ productIdByNativeKey = new Map();
180
+ unsubscribeNotifications;
181
+ unsubscribeDiagnostics;
182
+ disposed = false;
183
+ constructor(client, getThreadId, getActiveTurnId, structuredUserInputEnabled, emit) {
184
+ this.client = client;
185
+ this.getThreadId = getThreadId;
186
+ this.getActiveTurnId = getActiveTurnId;
187
+ this.structuredUserInputEnabled = structuredUserInputEnabled;
188
+ this.emit = emit;
189
+ client.setServerRequestHandler((request) => this.handleServerRequest(request));
190
+ this.unsubscribeNotifications = client.subscribeNotifications((notification) => {
191
+ if (this.disposed)
192
+ return;
193
+ if (notification.method === "serverRequest/resolved")
194
+ this.handleResolvedNotification(notification.params);
195
+ else if (notification.method === "turn/completed")
196
+ this.handleTurnCompleted(notification.params);
197
+ else if (notification.method === "turn/started")
198
+ this.handleTurnStarted(notification.params);
199
+ });
200
+ this.unsubscribeDiagnostics = client.subscribeDiagnostics((diagnostic) => {
201
+ if (this.disposed || diagnostic.level !== "error")
202
+ return;
203
+ for (const pending of [...this.pendingByProductId.values()])
204
+ this.cancelPending(pending, "aborted");
205
+ });
206
+ }
207
+ get pendingApproval() {
208
+ return this.pendingApprovals[0];
209
+ }
210
+ get pendingUserInput() {
211
+ return this.pendingUserInputs[0];
212
+ }
213
+ get pendingApprovals() {
214
+ return [...this.pendingByProductId.values()]
215
+ .filter((pending) => pending.kind === "approval")
216
+ .map((pending) => cloneApproval(pending.request));
217
+ }
218
+ get pendingUserInputs() {
219
+ return [...this.pendingByProductId.values()]
220
+ .filter((pending) => pending.kind === "user_input")
221
+ .map((pending) => cloneUserInput(pending.request));
222
+ }
223
+ async respondToApproval(requestId, decision) {
224
+ const pending = this.pendingByProductId.get(requestId);
225
+ if (!pending || pending.kind !== "approval")
226
+ throw new Error("The runtime approval request is no longer pending.");
227
+ if (!APPROVAL_DECISION_IDS.has(decision) || !pending.request.decisions?.some((candidate) => candidate.id === decision)) {
228
+ throw new Error(`Unsupported runtime approval decision "${decision}".`);
229
+ }
230
+ this.removePending(pending, "responded");
231
+ pending.deferred.resolve({ decision: decision });
232
+ }
233
+ async respondToUserInput(requestId, answers) {
234
+ const pending = this.pendingByProductId.get(requestId);
235
+ if (!pending || pending.kind !== "user_input")
236
+ throw new Error("The runtime user-input request is no longer pending.");
237
+ const response = normalizeAnswers(pending.request, answers);
238
+ this.removePending(pending, "responded");
239
+ pending.deferred.resolve(response);
240
+ }
241
+ dispose() {
242
+ if (this.disposed)
243
+ return;
244
+ this.disposed = true;
245
+ this.unsubscribeNotifications();
246
+ this.unsubscribeDiagnostics();
247
+ this.client.setServerRequestHandler(undefined);
248
+ for (const pending of [...this.pendingByProductId.values()])
249
+ this.cancelPending(pending, "aborted");
250
+ }
251
+ async handleServerRequest(request) {
252
+ if (this.disposed)
253
+ throw new CodexAppServerServerRequestCancelledError();
254
+ if (request.method === "item/commandExecution/requestApproval")
255
+ return await this.handleCommandApproval(request);
256
+ if (request.method === "item/fileChange/requestApproval")
257
+ return await this.handleFileApproval(request);
258
+ if (request.method === "item/tool/requestUserInput")
259
+ return await this.handleUserInput(request);
260
+ throw new Error(`Unsupported Codex server request method: ${request.method}`);
261
+ }
262
+ async handleCommandApproval(request) {
263
+ const params = requiredRecord(request.params, "command approval request");
264
+ const scope = validateScope(params, this.getThreadId(), this.getActiveTurnId(), "command approval request");
265
+ requiredInteger(params.startedAtMs, "command approval start timestamp");
266
+ const pending = this.createApproval(request.id, scope, approvalRequest(randomUUID(), "command_execution", params));
267
+ return await pending.deferred.promise;
268
+ }
269
+ async handleFileApproval(request) {
270
+ const params = requiredRecord(request.params, "file approval request");
271
+ const scope = validateScope(params, this.getThreadId(), this.getActiveTurnId(), "file approval request");
272
+ requiredInteger(params.startedAtMs, "file approval start timestamp");
273
+ const pending = this.createApproval(request.id, scope, approvalRequest(randomUUID(), "file_change", params));
274
+ return await pending.deferred.promise;
275
+ }
276
+ async handleUserInput(request) {
277
+ if (!this.structuredUserInputEnabled)
278
+ throw new Error("Codex structured user input is not enabled for this configured runtime instance.");
279
+ const params = requiredRecord(request.params, "user-input request");
280
+ const scope = validateScope(params, this.getThreadId(), this.getActiveTurnId(), "user-input request");
281
+ if (typeof params.isBlocking !== "boolean")
282
+ throw new Error("Codex user-input blocking state is invalid.");
283
+ if (!Array.isArray(params.questions) || params.questions.length === 0 || params.questions.length > MAX_USER_INPUT_QUESTIONS) {
284
+ throw new Error("Codex user-input questions are invalid.");
285
+ }
286
+ const questions = params.questions.map(userInputQuestion);
287
+ if (new Set(questions.map((question) => question.id)).size !== questions.length) {
288
+ throw new Error("Codex user-input question ids must be unique.");
289
+ }
290
+ const productRequestId = randomUUID();
291
+ const runtimeRequest = {
292
+ requestId: productRequestId,
293
+ questions,
294
+ blocking: params.isBlocking,
295
+ };
296
+ const pending = {
297
+ kind: "user_input",
298
+ productRequestId,
299
+ nativeRequestId: request.id,
300
+ nativeRequestKey: nativeRequestKey(request.id),
301
+ ...scope,
302
+ request: runtimeRequest,
303
+ deferred: deferred(),
304
+ };
305
+ this.addPending(pending);
306
+ this.emit({ type: "user_input_requested", request: cloneUserInput(runtimeRequest) });
307
+ return await pending.deferred.promise;
308
+ }
309
+ createApproval(nativeRequestId, scope, runtimeRequest) {
310
+ const pending = {
311
+ kind: "approval",
312
+ productRequestId: runtimeRequest.requestId,
313
+ nativeRequestId,
314
+ nativeRequestKey: nativeRequestKey(nativeRequestId),
315
+ ...scope,
316
+ request: runtimeRequest,
317
+ deferred: deferred(),
318
+ };
319
+ this.addPending(pending);
320
+ this.emit({ type: "approval_requested", request: cloneApproval(runtimeRequest) });
321
+ return pending;
322
+ }
323
+ addPending(pending) {
324
+ if (this.productIdByNativeKey.has(pending.nativeRequestKey))
325
+ throw new Error("Codex repeated a pending server request id.");
326
+ this.pendingByProductId.set(pending.productRequestId, pending);
327
+ this.productIdByNativeKey.set(pending.nativeRequestKey, pending.productRequestId);
328
+ }
329
+ removePending(pending, resolution) {
330
+ if (!this.pendingByProductId.delete(pending.productRequestId))
331
+ return;
332
+ this.productIdByNativeKey.delete(pending.nativeRequestKey);
333
+ this.emit(pending.kind === "approval"
334
+ ? { type: "approval_resolved", requestId: pending.productRequestId, resolution }
335
+ : { type: "user_input_resolved", requestId: pending.productRequestId, resolution });
336
+ }
337
+ cancelPending(pending, resolution) {
338
+ this.removePending(pending, resolution);
339
+ pending.deferred.reject(new CodexAppServerServerRequestCancelledError());
340
+ }
341
+ handleResolvedNotification(value) {
342
+ const params = requiredRecord(value, "server-request resolution notification");
343
+ if (requiredString(params.threadId, "server-request resolution thread id") !== this.getThreadId())
344
+ return;
345
+ const requestId = params.requestId;
346
+ if ((typeof requestId !== "string" && typeof requestId !== "number") || (typeof requestId === "number" && !Number.isSafeInteger(requestId))) {
347
+ throw new Error("Codex server-request resolution id is invalid.");
348
+ }
349
+ const productRequestId = this.productIdByNativeKey.get(nativeRequestKey(requestId));
350
+ if (!productRequestId)
351
+ return;
352
+ const pending = this.pendingByProductId.get(productRequestId);
353
+ if (pending)
354
+ this.cancelPending(pending, "cleared");
355
+ }
356
+ handleTurnCompleted(value) {
357
+ const params = requiredRecord(value, "turn completion notification");
358
+ if (requiredString(params.threadId, "turn completion thread id") !== this.getThreadId())
359
+ return;
360
+ const turn = requiredRecord(params.turn, "completed turn");
361
+ const turnId = requiredString(turn.id, "completed turn id");
362
+ for (const pending of [...this.pendingByProductId.values()]) {
363
+ if (pending.turnId === turnId)
364
+ this.cancelPending(pending, "cleared");
365
+ }
366
+ }
367
+ handleTurnStarted(value) {
368
+ const params = requiredRecord(value, "turn start notification");
369
+ if (requiredString(params.threadId, "turn start thread id") !== this.getThreadId())
370
+ return;
371
+ const turn = requiredRecord(params.turn, "started turn");
372
+ const turnId = requiredString(turn.id, "started turn id");
373
+ for (const pending of [...this.pendingByProductId.values()]) {
374
+ if (pending.turnId !== turnId)
375
+ this.cancelPending(pending, "expired");
376
+ }
377
+ }
378
+ }