@openhoo/hoopilot 2.1.0 → 2.1.2
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 +3 -1
- package/dist/{chunk-6ALEIJJM.js → chunk-CYR6I4C3.js} +13 -2
- package/dist/chunk-CYR6I4C3.js.map +1 -0
- package/dist/cli.js +252 -34
- package/dist/cli.js.map +1 -1
- package/dist/codexx.js +1 -1
- package/dist/index.js +219 -21
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/dist/chunk-6ALEIJJM.js.map +0 -1
package/dist/codexx.js
CHANGED
package/dist/index.js
CHANGED
|
@@ -94,6 +94,16 @@ function parseStreamingProxyMode(value) {
|
|
|
94
94
|
|
|
95
95
|
// src/openai.ts
|
|
96
96
|
var DEFAULT_MODEL = "gpt-4.1";
|
|
97
|
+
var COMPACTION_SUMMARIZATION_PROMPT = `You are performing a CONTEXT CHECKPOINT COMPACTION. Create a handoff summary for another LLM that will resume the task.
|
|
98
|
+
|
|
99
|
+
Include:
|
|
100
|
+
- Current progress and key decisions made
|
|
101
|
+
- Important context, constraints, or user preferences
|
|
102
|
+
- What remains to be done (clear next steps)
|
|
103
|
+
- Any critical data, examples, or references needed to continue
|
|
104
|
+
|
|
105
|
+
Be concise, structured, and focused on helping the next LLM seamlessly continue the work.`;
|
|
106
|
+
var COMPACTION_SUMMARY_PREFIX = "Another language model started to solve this problem and produced a summary of its thinking process. You also have access to the state of the tools that were used by that language model. Use this to build on the work that has already been done and avoid duplicating work. Here is the summary produced by the other language model, use the information in this summary to assist with your own analysis:";
|
|
97
107
|
var OpenAICompatibilityError = class extends Error {
|
|
98
108
|
constructor(message) {
|
|
99
109
|
super(message);
|
|
@@ -184,19 +194,111 @@ function chatCompletionToResponse(completion, responseId) {
|
|
|
184
194
|
});
|
|
185
195
|
}
|
|
186
196
|
function responsesCompactionResult(upstreamText, isSse) {
|
|
187
|
-
const
|
|
188
|
-
return { output };
|
|
197
|
+
const summary = compactionSummaryText(upstreamText, isSse);
|
|
198
|
+
return { output: [compactionSummaryMessageItem(summary)] };
|
|
199
|
+
}
|
|
200
|
+
function isResponsesCompactionRequest(request) {
|
|
201
|
+
return responseInputItems(request.input).some(
|
|
202
|
+
(item) => contentToText(asRecord(item).type) === "compaction_trigger"
|
|
203
|
+
);
|
|
204
|
+
}
|
|
205
|
+
function responsesCompactionRequestBody(request) {
|
|
206
|
+
return JSON.stringify(
|
|
207
|
+
removeUndefined({
|
|
208
|
+
...request,
|
|
209
|
+
input: [
|
|
210
|
+
...compactionInputItemsForCopilot(request.input),
|
|
211
|
+
{
|
|
212
|
+
content: [{ text: COMPACTION_SUMMARIZATION_PROMPT, type: "input_text" }],
|
|
213
|
+
role: "user",
|
|
214
|
+
type: "message"
|
|
215
|
+
}
|
|
216
|
+
],
|
|
217
|
+
parallel_tool_calls: false,
|
|
218
|
+
stream: false,
|
|
219
|
+
tool_choice: "none",
|
|
220
|
+
tools: []
|
|
221
|
+
})
|
|
222
|
+
);
|
|
223
|
+
}
|
|
224
|
+
function normalizeResponsesRequestForCopilotBody(request) {
|
|
225
|
+
return JSON.stringify(
|
|
226
|
+
removeUndefined({
|
|
227
|
+
...request,
|
|
228
|
+
input: normalizeCompactionInputForCopilot(request.input, { dropTrigger: false })
|
|
229
|
+
})
|
|
230
|
+
);
|
|
231
|
+
}
|
|
232
|
+
function responsesRequestNeedsCopilotNormalization(request) {
|
|
233
|
+
return responseInputItems(request.input).some((item) => {
|
|
234
|
+
const type = contentToText(asRecord(item).type);
|
|
235
|
+
return type === "compaction" || type === "compaction_summary" || type === "context_compaction";
|
|
236
|
+
});
|
|
237
|
+
}
|
|
238
|
+
function responsesCompactionResponse(upstreamText, isSse, model) {
|
|
239
|
+
const output = [compactionOutputItem(compactionSummaryText(upstreamText, isSse))];
|
|
240
|
+
return removeUndefined({
|
|
241
|
+
created_at: epochSeconds(),
|
|
242
|
+
error: null,
|
|
243
|
+
id: `resp_${randomId()}`,
|
|
244
|
+
incomplete_details: null,
|
|
245
|
+
instructions: null,
|
|
246
|
+
max_output_tokens: null,
|
|
247
|
+
metadata: {},
|
|
248
|
+
model,
|
|
249
|
+
object: "response",
|
|
250
|
+
output,
|
|
251
|
+
output_text: "",
|
|
252
|
+
parallel_tool_calls: false,
|
|
253
|
+
status: "completed",
|
|
254
|
+
temperature: null,
|
|
255
|
+
tool_choice: "none",
|
|
256
|
+
tools: [],
|
|
257
|
+
top_p: null
|
|
258
|
+
});
|
|
259
|
+
}
|
|
260
|
+
function responsesCompactionSseText(upstreamText, isSse, model) {
|
|
261
|
+
const responseId = `resp_${randomId()}`;
|
|
262
|
+
const item = compactionOutputItem(compactionSummaryText(upstreamText, isSse));
|
|
263
|
+
const createdAt = epochSeconds();
|
|
264
|
+
let sequenceNumber = 0;
|
|
265
|
+
const event = (name, data) => encodeSse(name, data === "[DONE]" ? data : { ...data, sequence_number: sequenceNumber++ });
|
|
266
|
+
return [
|
|
267
|
+
event("response.created", {
|
|
268
|
+
response: baseStreamResponse(responseId, model, createdAt, "in_progress", []),
|
|
269
|
+
type: "response.created"
|
|
270
|
+
}),
|
|
271
|
+
event("response.output_item.done", {
|
|
272
|
+
item,
|
|
273
|
+
output_index: 0,
|
|
274
|
+
type: "response.output_item.done"
|
|
275
|
+
}),
|
|
276
|
+
event("response.completed", {
|
|
277
|
+
response: baseStreamResponse(responseId, model, createdAt, "completed", [item]),
|
|
278
|
+
type: "response.completed"
|
|
279
|
+
}),
|
|
280
|
+
event("done", "[DONE]")
|
|
281
|
+
].join("");
|
|
189
282
|
}
|
|
190
|
-
function
|
|
191
|
-
|
|
192
|
-
|
|
283
|
+
function compactionSummaryText(upstreamText, isSse) {
|
|
284
|
+
const summary = isSse ? compactionSummaryTextFromResponsesSse(upstreamText) : compactionSummaryTextFromResponse(asRecord(safeJsonParse(upstreamText)));
|
|
285
|
+
return summary.trim() || "(no summary available)";
|
|
286
|
+
}
|
|
287
|
+
function compactionSummaryTextFromResponse(response) {
|
|
288
|
+
const output = Array.isArray(response.output) ? response.output.map((item) => asRecord(item)) : [];
|
|
289
|
+
const compaction = output.find((item) => contentToText(item.type) === "compaction");
|
|
290
|
+
if (compaction) {
|
|
291
|
+
return contentToText(compaction.encrypted_content);
|
|
292
|
+
}
|
|
293
|
+
const text = outputText(output);
|
|
294
|
+
if (text) {
|
|
295
|
+
return text;
|
|
193
296
|
}
|
|
194
|
-
|
|
195
|
-
return text ? [messageOutputItem(text)] : [];
|
|
297
|
+
return contentToText(response.output_text);
|
|
196
298
|
}
|
|
197
|
-
function
|
|
299
|
+
function compactionSummaryTextFromResponsesSse(text) {
|
|
198
300
|
let deltas = "";
|
|
199
|
-
let
|
|
301
|
+
let completedResponse;
|
|
200
302
|
for (const block of text.split(/\r?\n\r?\n/)) {
|
|
201
303
|
const data = block.split(/\r?\n/).filter((line) => line.startsWith("data:")).map((line) => line.slice(5).trim()).join("");
|
|
202
304
|
if (!data || data === "[DONE]") {
|
|
@@ -207,16 +309,16 @@ function compactionOutputFromResponsesSse(text) {
|
|
|
207
309
|
if (type === "response.output_text.delta") {
|
|
208
310
|
deltas += contentToText(record.delta);
|
|
209
311
|
} else if (type === "response.completed" || type === "response.incomplete") {
|
|
210
|
-
|
|
211
|
-
if (Array.isArray(response.output)) {
|
|
212
|
-
completedOutput = response.output;
|
|
213
|
-
}
|
|
312
|
+
completedResponse = asRecord(record.response);
|
|
214
313
|
}
|
|
215
314
|
}
|
|
216
|
-
if (
|
|
217
|
-
|
|
315
|
+
if (completedResponse) {
|
|
316
|
+
const summary = compactionSummaryTextFromResponse(completedResponse);
|
|
317
|
+
if (summary) {
|
|
318
|
+
return summary;
|
|
319
|
+
}
|
|
218
320
|
}
|
|
219
|
-
return deltas
|
|
321
|
+
return deltas;
|
|
220
322
|
}
|
|
221
323
|
function chatCompletionToCompletion(completion) {
|
|
222
324
|
return removeUndefined({
|
|
@@ -737,6 +839,66 @@ function messageOutputItem(text, id = `msg_${randomId()}`) {
|
|
|
737
839
|
type: "message"
|
|
738
840
|
};
|
|
739
841
|
}
|
|
842
|
+
function compactionSummaryMessageItem(text, id = `msg_${randomId()}`) {
|
|
843
|
+
return {
|
|
844
|
+
content: [
|
|
845
|
+
{
|
|
846
|
+
text: `${COMPACTION_SUMMARY_PREFIX}
|
|
847
|
+
${text}`,
|
|
848
|
+
type: "input_text"
|
|
849
|
+
}
|
|
850
|
+
],
|
|
851
|
+
id,
|
|
852
|
+
role: "user",
|
|
853
|
+
type: "message"
|
|
854
|
+
};
|
|
855
|
+
}
|
|
856
|
+
function compactionOutputItem(text, id = `cmpct_${randomId()}`) {
|
|
857
|
+
return {
|
|
858
|
+
encrypted_content: text,
|
|
859
|
+
id,
|
|
860
|
+
type: "compaction"
|
|
861
|
+
};
|
|
862
|
+
}
|
|
863
|
+
function normalizeCompactionInputForCopilot(input, options) {
|
|
864
|
+
const items = responseInputItems(input);
|
|
865
|
+
if (items.length === 0) {
|
|
866
|
+
return input;
|
|
867
|
+
}
|
|
868
|
+
const normalized = [];
|
|
869
|
+
for (const item of items) {
|
|
870
|
+
const record = asRecord(item);
|
|
871
|
+
const type = contentToText(record.type);
|
|
872
|
+
if (type === "compaction_trigger" && options.dropTrigger) {
|
|
873
|
+
continue;
|
|
874
|
+
}
|
|
875
|
+
if (type === "compaction" || type === "compaction_summary" || type === "context_compaction") {
|
|
876
|
+
const text = contentToText(record.encrypted_content);
|
|
877
|
+
if (text) {
|
|
878
|
+
normalized.push(compactionSummaryMessageItem(text));
|
|
879
|
+
}
|
|
880
|
+
continue;
|
|
881
|
+
}
|
|
882
|
+
normalized.push(item);
|
|
883
|
+
}
|
|
884
|
+
return normalized;
|
|
885
|
+
}
|
|
886
|
+
function compactionInputItemsForCopilot(input) {
|
|
887
|
+
if (Array.isArray(input)) {
|
|
888
|
+
return normalizeCompactionInputForCopilot(input, { dropTrigger: true });
|
|
889
|
+
}
|
|
890
|
+
const text = contentToText(input);
|
|
891
|
+
return text ? [
|
|
892
|
+
{
|
|
893
|
+
content: [{ text, type: "input_text" }],
|
|
894
|
+
role: "user",
|
|
895
|
+
type: "message"
|
|
896
|
+
}
|
|
897
|
+
] : [];
|
|
898
|
+
}
|
|
899
|
+
function responseInputItems(input) {
|
|
900
|
+
return Array.isArray(input) ? input : [];
|
|
901
|
+
}
|
|
740
902
|
function functionCallItem(tool, status = "completed") {
|
|
741
903
|
return {
|
|
742
904
|
arguments: tool.arguments,
|
|
@@ -4080,7 +4242,21 @@ async function handleCompletions(client, metrics, recordTokens, recordExtraction
|
|
|
4080
4242
|
}
|
|
4081
4243
|
async function handleResponses(client, metrics, recordTokens, recordExtraction, request, logger, bufferProxyBodies) {
|
|
4082
4244
|
const { json, text: body } = await readJsonText(request);
|
|
4083
|
-
|
|
4245
|
+
if (isResponsesCompactionRequest(json)) {
|
|
4246
|
+
return handleResponsesCompactionV2(
|
|
4247
|
+
client,
|
|
4248
|
+
metrics,
|
|
4249
|
+
recordTokens,
|
|
4250
|
+
recordExtraction,
|
|
4251
|
+
json,
|
|
4252
|
+
request,
|
|
4253
|
+
logger
|
|
4254
|
+
);
|
|
4255
|
+
}
|
|
4256
|
+
const upstream = await client.responses(
|
|
4257
|
+
responsesRequestNeedsCopilotNormalization(json) ? normalizeResponsesRequestForCopilotBody(json) : body,
|
|
4258
|
+
request.signal
|
|
4259
|
+
);
|
|
4084
4260
|
metrics.recordUpstream("/responses", upstream.ok);
|
|
4085
4261
|
if (!upstream.ok) {
|
|
4086
4262
|
return proxyError(upstream, logger);
|
|
@@ -4100,10 +4276,7 @@ async function handleResponses(client, metrics, recordTokens, recordExtraction,
|
|
|
4100
4276
|
}
|
|
4101
4277
|
async function handleResponsesCompact(client, metrics, recordTokens, recordExtraction, request, logger) {
|
|
4102
4278
|
const body = await readJson(request);
|
|
4103
|
-
const upstream = await client.responses(
|
|
4104
|
-
JSON.stringify({ ...body, stream: false }),
|
|
4105
|
-
request.signal
|
|
4106
|
-
);
|
|
4279
|
+
const upstream = await client.responses(responsesCompactionRequestBody(body), request.signal);
|
|
4107
4280
|
metrics.recordUpstream("/responses", upstream.ok);
|
|
4108
4281
|
if (!upstream.ok) {
|
|
4109
4282
|
return proxyError(upstream, logger);
|
|
@@ -4120,6 +4293,22 @@ async function handleResponsesCompact(client, metrics, recordTokens, recordExtra
|
|
|
4120
4293
|
);
|
|
4121
4294
|
return jsonResponse(responsesCompactionResult(text, isSse));
|
|
4122
4295
|
}
|
|
4296
|
+
async function handleResponsesCompactionV2(client, metrics, recordTokens, recordExtraction, json, request, logger) {
|
|
4297
|
+
const upstream = await client.responses(responsesCompactionRequestBody(json), request.signal);
|
|
4298
|
+
metrics.recordUpstream("/responses", upstream.ok);
|
|
4299
|
+
if (!upstream.ok) {
|
|
4300
|
+
return proxyError(upstream, logger);
|
|
4301
|
+
}
|
|
4302
|
+
logUpstreamSuccess(logger, "/responses", upstream.status);
|
|
4303
|
+
const isSse = isStreamingResponse(upstream);
|
|
4304
|
+
const text = await upstream.text();
|
|
4305
|
+
const model = normalizeRequestedModel(json.model);
|
|
4306
|
+
recordResponseTextUsage(text, isSse, model, recordTokens, recordExtraction);
|
|
4307
|
+
if (json.stream === true) {
|
|
4308
|
+
return textResponse(responsesCompactionSseText(text, isSse, model), "text/event-stream");
|
|
4309
|
+
}
|
|
4310
|
+
return jsonResponse(responsesCompactionResponse(text, isSse, model));
|
|
4311
|
+
}
|
|
4123
4312
|
async function responseWithObservedUsage(response, fallbackModel, recordTokens, signal, bufferBody, recordExtraction) {
|
|
4124
4313
|
const isSse = isStreamingResponse(response);
|
|
4125
4314
|
if (bufferBody && response.body) {
|
|
@@ -4228,6 +4417,15 @@ function jsonResponse(body, status = 200) {
|
|
|
4228
4417
|
status
|
|
4229
4418
|
});
|
|
4230
4419
|
}
|
|
4420
|
+
function textResponse(body, contentType, status = 200) {
|
|
4421
|
+
return new Response(body, {
|
|
4422
|
+
headers: {
|
|
4423
|
+
...corsHeaders(),
|
|
4424
|
+
"content-type": `${contentType}; charset=utf-8`
|
|
4425
|
+
},
|
|
4426
|
+
status
|
|
4427
|
+
});
|
|
4428
|
+
}
|
|
4231
4429
|
function jsonError(status, code, message) {
|
|
4232
4430
|
return jsonResponse(
|
|
4233
4431
|
{
|