codex-copilot-dx 0.4.42 → 0.4.43
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +9 -5
- package/package.json +1 -1
- package/src/adapter.mjs +1 -0
- package/src/copilot.mjs +32 -5
- package/src/http-transport.mjs +1 -1
- package/src/image-optimization.mjs +269 -82
- package/src/responses-bridge.mjs +31 -11
- package/src/responses-byte-budget.mjs +314 -0
- package/src/responses-chat-payload.mjs +128 -0
- package/src/responses-content.mjs +86 -0
- package/src/responses-handler.mjs +39 -6
- package/src/responses-image-limit.mjs +15 -26
- package/src/responses-request.mjs +43 -6
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { readResponsesImagePart, readResponsesToolOutputParts } from "./responses-content.mjs";
|
|
2
|
+
|
|
1
3
|
export const MAX_UPSTREAM_IMAGES = 50;
|
|
2
4
|
|
|
3
5
|
function isImagePart(part) {
|
|
@@ -8,13 +10,13 @@ function isImagePart(part) {
|
|
|
8
10
|
function imageIdentity(part) {
|
|
9
11
|
if (!isImagePart(part)) return null;
|
|
10
12
|
|
|
13
|
+
const inlineIdentity = readResponsesImagePart(part)?.identity;
|
|
14
|
+
if (inlineIdentity) return { kind: "inline:data", value: inlineIdentity };
|
|
15
|
+
|
|
11
16
|
if (part.type === "image") {
|
|
12
17
|
const source = part.source;
|
|
13
|
-
if (typeof source?.data === "string") {
|
|
14
|
-
return { kind: `image:${source.type || "base64"}:${source.media_type || ""}`, value: source.data };
|
|
15
|
-
}
|
|
16
18
|
if (typeof source?.url === "string") {
|
|
17
|
-
return { kind: `
|
|
19
|
+
return { kind: `url:${part.detail || ""}`, value: source.url };
|
|
18
20
|
}
|
|
19
21
|
}
|
|
20
22
|
|
|
@@ -22,10 +24,10 @@ function imageIdentity(part) {
|
|
|
22
24
|
const url = typeof raw === "string" ? raw : raw?.url;
|
|
23
25
|
if (typeof url === "string") {
|
|
24
26
|
const detail = part.detail ?? raw?.detail ?? "";
|
|
25
|
-
return { kind:
|
|
27
|
+
return { kind: `url:${detail}`, value: url };
|
|
26
28
|
}
|
|
27
29
|
if (typeof part.file_id === "string") {
|
|
28
|
-
return { kind:
|
|
30
|
+
return { kind: "file", value: part.file_id };
|
|
29
31
|
}
|
|
30
32
|
return null;
|
|
31
33
|
}
|
|
@@ -100,26 +102,13 @@ function collectImages(inputItems) {
|
|
|
100
102
|
});
|
|
101
103
|
}
|
|
102
104
|
|
|
103
|
-
|
|
104
|
-
if (
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
}
|
|
111
|
-
if (typeof item.output !== "string" || !item.output.trim().startsWith("[")) continue;
|
|
112
|
-
try {
|
|
113
|
-
const parsed = JSON.parse(item.output);
|
|
114
|
-
if (!Array.isArray(parsed)) continue;
|
|
115
|
-
addPartContainer(records, refs, parsed, {
|
|
116
|
-
kind: "tool-output",
|
|
117
|
-
itemIndex,
|
|
118
|
-
commit: () => { item.output = JSON.stringify(parsed); },
|
|
119
|
-
});
|
|
120
|
-
} catch {
|
|
121
|
-
// Preserve non-JSON tool output unchanged.
|
|
122
|
-
}
|
|
105
|
+
const toolOutput = readResponsesToolOutputParts(item);
|
|
106
|
+
if (!toolOutput) continue;
|
|
107
|
+
addPartContainer(records, refs, toolOutput.parts, {
|
|
108
|
+
kind: "tool-output",
|
|
109
|
+
itemIndex,
|
|
110
|
+
commit: toolOutput.commit,
|
|
111
|
+
});
|
|
123
112
|
}
|
|
124
113
|
|
|
125
114
|
if (hasTopLevelImages) records.push(topLevelRecord);
|
|
@@ -31,7 +31,24 @@ export function stripInternalResponsesInputFields(inputItems) {
|
|
|
31
31
|
|
|
32
32
|
function responsesOutputItems(output) {
|
|
33
33
|
if (!Array.isArray(output)) return [];
|
|
34
|
-
return output.filter((item) =>
|
|
34
|
+
return output.filter((item) => ["message", "function_call", "custom_tool_call"].includes(item?.type));
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function isCompactedResponsesOutput(output) {
|
|
38
|
+
return Array.isArray(output) && output.some((item) => item?.type === "compaction");
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function isSuccessfulCompactionResponse(response) {
|
|
42
|
+
if (!isCompactedResponsesOutput(response?.output)) return false;
|
|
43
|
+
if (Object.prototype.hasOwnProperty.call(response, "status") && response.status !== "completed") {
|
|
44
|
+
return false;
|
|
45
|
+
}
|
|
46
|
+
return response.object === "response.compaction" || response.status === "completed";
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
function replayableResponsesOutputItems(output) {
|
|
50
|
+
if (!Array.isArray(output)) return [];
|
|
51
|
+
return output.filter((item) => item && typeof item === "object");
|
|
35
52
|
}
|
|
36
53
|
|
|
37
54
|
function stripEncryptedReasoningValue(value, state) {
|
|
@@ -62,16 +79,21 @@ function isEncryptedReasoningInputItem(item) {
|
|
|
62
79
|
export function sanitizeEncryptedReasoningRequest(reqContext) {
|
|
63
80
|
const state = { changed: false };
|
|
64
81
|
let body = cloneJson(reqContext.body);
|
|
82
|
+
let currentInputStart = reqContext.currentInputStart;
|
|
65
83
|
if (Array.isArray(body.input)) {
|
|
66
84
|
const input = [];
|
|
67
|
-
|
|
85
|
+
let retainedBeforeCurrent = 0;
|
|
86
|
+
for (let index = 0; index < body.input.length; index += 1) {
|
|
87
|
+
const item = body.input[index];
|
|
68
88
|
if (isEncryptedReasoningInputItem(item)) {
|
|
69
89
|
state.changed = true;
|
|
70
90
|
continue;
|
|
71
91
|
}
|
|
72
92
|
input.push(stripEncryptedReasoningValue(item, state));
|
|
93
|
+
if (Number.isFinite(currentInputStart) && index < currentInputStart) retainedBeforeCurrent += 1;
|
|
73
94
|
}
|
|
74
95
|
body.input = input;
|
|
96
|
+
if (Number.isFinite(currentInputStart)) currentInputStart = retainedBeforeCurrent;
|
|
75
97
|
} else {
|
|
76
98
|
body = stripEncryptedReasoningValue(body, state);
|
|
77
99
|
}
|
|
@@ -84,6 +106,7 @@ export function sanitizeEncryptedReasoningRequest(reqContext) {
|
|
|
84
106
|
return {
|
|
85
107
|
...reqContext,
|
|
86
108
|
body,
|
|
109
|
+
currentInputStart,
|
|
87
110
|
inputItems: Array.isArray(body.input) ? body.input : reqContext.inputItems,
|
|
88
111
|
historyInputItems,
|
|
89
112
|
};
|
|
@@ -129,8 +152,14 @@ export function sanitizeImageNamespaceCollisionRequest(reqContext) {
|
|
|
129
152
|
export async function openCopilotResponse(reqContext, upstream = copilotResponses, options = {}) {
|
|
130
153
|
let encryptedRetried = false;
|
|
131
154
|
let imageNamespaceRetried = false;
|
|
155
|
+
let payloadPrepared = false;
|
|
132
156
|
for (let attempt = 0; attempt < 3; attempt += 1) {
|
|
133
|
-
const resp = await upstream(reqContext.body, {
|
|
157
|
+
const resp = await upstream(reqContext.body, {
|
|
158
|
+
signal: options.signal,
|
|
159
|
+
currentInputStart: reqContext.currentInputStart,
|
|
160
|
+
payloadPrepared,
|
|
161
|
+
});
|
|
162
|
+
payloadPrepared = true;
|
|
134
163
|
if (resp.ok) return { resp, reqContext };
|
|
135
164
|
|
|
136
165
|
const errorText = await resp.text();
|
|
@@ -164,6 +193,9 @@ function isBuiltinImageTool(tool) {
|
|
|
164
193
|
export function prepareResponsesRequest(reqBody, { mutate = false } = {}) {
|
|
165
194
|
const body = mutate ? reqBody : cloneJson(reqBody);
|
|
166
195
|
const currentInputItems = responsesInputItems(body.input, { clone: !mutate });
|
|
196
|
+
const currentInputRefs = new Set(
|
|
197
|
+
currentInputItems.filter((item) => item && typeof item === "object"),
|
|
198
|
+
);
|
|
167
199
|
const previousId = body.previous_response_id;
|
|
168
200
|
let historyItems = [];
|
|
169
201
|
|
|
@@ -193,10 +225,12 @@ export function prepareResponsesRequest(reqBody, { mutate = false } = {}) {
|
|
|
193
225
|
}
|
|
194
226
|
stripInternalResponsesInputFields(body.input);
|
|
195
227
|
stripInternalResponsesInputFields(historyInputItems);
|
|
228
|
+
const retainedCurrentInputStart = body.input.findIndex((item) => currentInputRefs.has(item));
|
|
196
229
|
|
|
197
230
|
return {
|
|
198
231
|
body,
|
|
199
232
|
inputItems: body.input,
|
|
233
|
+
currentInputStart: retainedCurrentInputStart < 0 ? body.input.length : retainedCurrentInputStart,
|
|
200
234
|
historyParentId: previousId ?? null,
|
|
201
235
|
historyInputItems,
|
|
202
236
|
takeHistoryOwnership: mutate,
|
|
@@ -205,11 +239,14 @@ export function prepareResponsesRequest(reqBody, { mutate = false } = {}) {
|
|
|
205
239
|
|
|
206
240
|
export function rememberResponseHistory(reqContext, responseJson) {
|
|
207
241
|
if (!responseJson?.id || !Array.isArray(reqContext?.historyInputItems || reqContext?.inputItems)) return;
|
|
208
|
-
const
|
|
209
|
-
const
|
|
242
|
+
const compacted = isSuccessfulCompactionResponse(responseJson);
|
|
243
|
+
const sourceInputItems = compacted ? [] : reqContext.historyInputItems || reqContext.inputItems;
|
|
244
|
+
const sourceOutputItems = compacted
|
|
245
|
+
? replayableResponsesOutputItems(responseJson.output)
|
|
246
|
+
: responsesOutputItems(responseJson.output);
|
|
210
247
|
rememberResponseHistoryNode({
|
|
211
248
|
id: responseJson.id,
|
|
212
|
-
parentId: reqContext.historyParentId,
|
|
249
|
+
parentId: compacted ? null : reqContext.historyParentId,
|
|
213
250
|
inputItems: sourceInputItems,
|
|
214
251
|
outputItems: sourceOutputItems,
|
|
215
252
|
takeOwnership: reqContext.takeHistoryOwnership,
|