codex-copilot-dx 0.6.1 → 0.6.3

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.
@@ -0,0 +1,163 @@
1
+ import {
2
+ responsesHistoricalImageStats,
3
+ trimResponsesHistoricalImages,
4
+ } from "./responses-byte-budget.mjs";
5
+
6
+ const MIB = 1024 * 1024;
7
+
8
+ export const DEFAULT_RESPONSES_IMAGE_PRESSURE_POLICY = Object.freeze({
9
+ triggerHistoricalImages: 24,
10
+ triggerBodyBytes: 18 * MIB,
11
+ pressureHistoricalImages: 16,
12
+ pressureBodyBytes: 16 * MIB,
13
+ recoveryHistoricalImages: 8,
14
+ recoveryBodyBytes: 10 * MIB,
15
+ });
16
+
17
+ function normalizedPolicy(policy = {}) {
18
+ return { ...DEFAULT_RESPONSES_IMAGE_PRESSURE_POLICY, ...policy };
19
+ }
20
+
21
+ function bodyPayload(body) {
22
+ const bodyText = JSON.stringify(body);
23
+ return { bodyText, bodyBytes: Buffer.byteLength(bodyText) };
24
+ }
25
+
26
+ export function applyResponsesImagePressure(reqContext, {
27
+ mode = "normal",
28
+ policy: policyOverrides,
29
+ } = {}) {
30
+ const policy = normalizedPolicy(policyOverrides);
31
+ const body = reqContext?.body;
32
+ const currentInputStart = Number.isFinite(reqContext?.currentInputStart)
33
+ ? reqContext.currentInputStart
34
+ : 0;
35
+ const initial = bodyPayload(body);
36
+ const initialImages = responsesHistoricalImageStats(body?.input, currentInputStart);
37
+ const pressureEligible = initialImages.historicalImages > 0 && (
38
+ initialImages.historicalImages > policy.triggerHistoricalImages
39
+ || initial.bodyBytes > policy.triggerBodyBytes
40
+ );
41
+ const recovery = mode === "recovery";
42
+ const maxHistoricalImages = recovery
43
+ ? policy.recoveryHistoricalImages
44
+ : policy.pressureHistoricalImages;
45
+ const targetBytes = recovery ? policy.recoveryBodyBytes : policy.pressureBodyBytes;
46
+ const shouldAdapt = initialImages.historicalImages > 0 && (recovery
47
+ ? initialImages.historicalImages > maxHistoricalImages || initial.bodyBytes > targetBytes
48
+ : pressureEligible);
49
+
50
+ if (!shouldAdapt) {
51
+ return {
52
+ mode: "normal",
53
+ pressureEligible,
54
+ adapted: false,
55
+ imagesOmitted: 0,
56
+ initialBodyBytes: initial.bodyBytes,
57
+ bodyBytes: initial.bodyBytes,
58
+ initialHistoricalImages: initialImages.historicalImages,
59
+ historicalImages: initialImages.historicalImages,
60
+ currentImages: initialImages.currentImages,
61
+ overBudget: false,
62
+ overImageBudget: false,
63
+ };
64
+ }
65
+
66
+ const trimmed = trimResponsesHistoricalImages(body, {
67
+ currentInputStart,
68
+ maxHistoricalImages,
69
+ targetBytes,
70
+ initialBodyText: initial.bodyText,
71
+ initialBodyBytes: initial.bodyBytes,
72
+ });
73
+ return {
74
+ mode: recovery ? "recovery" : "pressure",
75
+ pressureEligible: pressureEligible || recovery,
76
+ initialBodyBytes: initial.bodyBytes,
77
+ initialHistoricalImages: initialImages.historicalImages,
78
+ ...trimmed,
79
+ };
80
+ }
81
+
82
+ export function createResponsesImagePressureController({
83
+ now = Date.now,
84
+ maxEntries = 256,
85
+ recoveryTtlMs = 10 * 60 * 1000,
86
+ successesToClear = 2,
87
+ policy: policyOverrides,
88
+ } = {}) {
89
+ const policy = normalizedPolicy(policyOverrides);
90
+ const recovery = new Map();
91
+ const counters = {
92
+ adaptedRequests: 0,
93
+ imagesOmitted: 0,
94
+ recoveryActivations: 0,
95
+ timeoutsRecorded: 0,
96
+ };
97
+
98
+ const prune = () => {
99
+ const timestamp = now();
100
+ for (const [rootId, state] of recovery) {
101
+ if (state.expiresAt <= timestamp) recovery.delete(rootId);
102
+ }
103
+ while (recovery.size > maxEntries) recovery.delete(recovery.keys().next().value);
104
+ };
105
+
106
+ const modeFor = (rootId) => {
107
+ prune();
108
+ return rootId && recovery.has(rootId) ? "recovery" : "normal";
109
+ };
110
+
111
+ return Object.freeze({
112
+ apply(reqContext) {
113
+ const result = applyResponsesImagePressure(reqContext, {
114
+ mode: modeFor(reqContext?.historyRootId),
115
+ policy,
116
+ });
117
+ if (result.adapted) {
118
+ counters.adaptedRequests += 1;
119
+ counters.imagesOmitted += result.imagesOmitted;
120
+ }
121
+ return result;
122
+ },
123
+ markTimeout(rootId, { eligible = false } = {}) {
124
+ if (!rootId || !eligible) return false;
125
+ prune();
126
+ const existing = recovery.get(rootId);
127
+ recovery.delete(rootId);
128
+ recovery.set(rootId, { expiresAt: now() + recoveryTtlMs, successes: 0 });
129
+ counters.timeoutsRecorded += 1;
130
+ if (!existing) counters.recoveryActivations += 1;
131
+ prune();
132
+ return true;
133
+ },
134
+ markSuccess(rootId) {
135
+ if (!rootId) return false;
136
+ prune();
137
+ const state = recovery.get(rootId);
138
+ if (!state) return false;
139
+ state.successes += 1;
140
+ if (state.successes >= successesToClear) {
141
+ recovery.delete(rootId);
142
+ return true;
143
+ }
144
+ return false;
145
+ },
146
+ clear(rootId) {
147
+ return rootId ? recovery.delete(rootId) : false;
148
+ },
149
+ snapshot() {
150
+ prune();
151
+ return {
152
+ active_recovery_trees: recovery.size,
153
+ adapted_requests: counters.adaptedRequests,
154
+ historical_images_omitted: counters.imagesOmitted,
155
+ recovery_activations: counters.recoveryActivations,
156
+ timeouts_recorded: counters.timeoutsRecorded,
157
+ recovery_ttl_ms: recoveryTtlMs,
158
+ pressure_image_limit: policy.pressureHistoricalImages,
159
+ recovery_image_limit: policy.recoveryHistoricalImages,
160
+ };
161
+ },
162
+ });
163
+ }
@@ -126,7 +126,7 @@ export async function proxyCopilotResponses(reqContext, req, res, upstream = cop
126
126
  reqContext = opened.reqContext;
127
127
  if (errorText !== undefined) {
128
128
  sendUpstreamError(res, resp, errorText);
129
- return;
129
+ return { successful: false, compacted: false };
130
130
  }
131
131
 
132
132
  if (reqContext.body.stream) {
@@ -158,7 +158,7 @@ export async function proxyCopilotResponses(reqContext, req, res, upstream = cop
158
158
  if (!streamState.sawTerminal) throw incompleteUpstreamStream("a terminal Responses event");
159
159
  storeCompletedResponse(reqContext, streamState.completed);
160
160
  res.end();
161
- return;
161
+ return { successful: Boolean(streamState.completed), compacted: false };
162
162
  }
163
163
  options.abort?.setTimeout(options.streamIdleTimeoutMs, "stream_idle_timeout");
164
164
  buffer += decoder.decode(value, { stream: true });
@@ -170,12 +170,13 @@ export async function proxyCopilotResponses(reqContext, req, res, upstream = cop
170
170
  if (streamState.sawTerminal) {
171
171
  storeCompletedResponse(reqContext, streamState.completed);
172
172
  res.end();
173
- return;
173
+ return { successful: Boolean(streamState.completed), compacted: false };
174
174
  }
175
175
  }
176
176
  } catch (e) {
177
177
  logRequestFailure("Responses", e, options.abort);
178
178
  await endStreamWithError(res, "responses", e, options.abort);
179
+ return { successful: false, compacted: false };
179
180
  } finally {
180
181
  await reader.cancel().catch(() => {});
181
182
  reader.releaseLock();
@@ -199,7 +200,7 @@ export async function proxyCopilotResponses(reqContext, req, res, upstream = cop
199
200
  contentType: "application/json",
200
201
  }));
201
202
  res.end(JSON.stringify(response));
202
- return;
203
+ return { successful: true, compacted: true };
203
204
  }
204
205
  res.writeHead(resp.status, safeUpstreamResponseHeaders(resp.headers, {
205
206
  contentType: "application/json",
@@ -216,7 +217,9 @@ export async function proxyCopilotResponses(reqContext, req, res, upstream = cop
216
217
  response,
217
218
  event: response,
218
219
  });
220
+ return { successful: true, compacted: false };
219
221
  } catch {}
220
222
  }
223
+ return { successful: false, compacted: false };
221
224
  }
222
225
  }
@@ -1,7 +1,11 @@
1
1
  import { responses as copilotResponses } from "./copilot.mjs";
2
2
  import { httpError } from "./http-transport.mjs";
3
3
  import { debugLog } from "./log.mjs";
4
- import { materializeResponseHistory, rememberResponseHistoryNode } from "./response-history.mjs";
4
+ import {
5
+ materializeResponseHistory,
6
+ rememberResponseHistoryNode,
7
+ responseHistoryRootId,
8
+ } from "./response-history.mjs";
5
9
  import { enforceResponsesImageLimit } from "./responses-image-limit.mjs";
6
10
  import { status } from "./status.mjs";
7
11
 
@@ -157,6 +161,7 @@ export async function openCopilotResponse(reqContext, upstream = copilotResponse
157
161
  const resp = await upstream(reqContext.body, {
158
162
  signal: options.signal,
159
163
  currentInputStart: reqContext.currentInputStart,
164
+ onUpstreamStart: options.onUpstreamStart,
160
165
  payloadPrepared,
161
166
  });
162
167
  payloadPrepared = true;
@@ -198,9 +203,11 @@ export function prepareResponsesRequest(reqBody, { mutate = false } = {}) {
198
203
  );
199
204
  const previousId = body.previous_response_id;
200
205
  let historyItems = [];
206
+ let historyRootId = null;
201
207
 
202
208
  if (previousId !== undefined && previousId !== null) {
203
209
  historyItems = materializeResponseHistory(previousId);
210
+ historyRootId = responseHistoryRootId(previousId);
204
211
  body.input = [...historyItems, ...currentInputItems];
205
212
  } else {
206
213
  body.input = currentInputItems;
@@ -232,6 +239,7 @@ export function prepareResponsesRequest(reqBody, { mutate = false } = {}) {
232
239
  inputItems: body.input,
233
240
  currentInputStart: retainedCurrentInputStart < 0 ? body.input.length : retainedCurrentInputStart,
234
241
  historyParentId: previousId ?? null,
242
+ historyRootId,
235
243
  historyInputItems,
236
244
  takeHistoryOwnership: mutate,
237
245
  };