@openhoo/hoopilot 0.9.1 → 0.9.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.
package/dist/index.d.cts CHANGED
@@ -282,6 +282,16 @@ declare function normalizeChatCompletionRequest(request: JsonObject): JsonObject
282
282
  declare function completionsRequestToChatCompletion(request: JsonObject): JsonObject;
283
283
  declare function normalizeRequestedModel(model: unknown): string;
284
284
  declare function chatCompletionToResponse(completion: JsonObject, responseId?: string): JsonObject;
285
+ /**
286
+ * Reduce a Copilot `/responses` result into the `{ output }` document Codex's
287
+ * remote-compaction client (`POST /responses/compact`) deserializes. Codex keeps
288
+ * only assistant/user message items from `output` and discards everything else,
289
+ * so a Responses `output` array passes through verbatim; when the upstream only
290
+ * exposes `output_text` (or, for a stream it did not honor `stream: false` on,
291
+ * `output_text` deltas) a single assistant message is synthesized instead. The
292
+ * input may be a unary JSON body or an SSE stream, so both framings are handled.
293
+ */
294
+ declare function responsesCompactionResult(upstreamText: string, isSse: boolean): JsonObject;
285
295
  declare function chatCompletionToCompletion(completion: JsonObject): JsonObject;
286
296
  declare function completionStreamFromChatStream(chatStream: ReadableStream<Uint8Array>): ReadableStream<Uint8Array>;
287
297
  declare function normalizeModelsResponse(upstream: unknown): JsonObject;
@@ -299,4 +309,4 @@ declare function extractTokenUsage(usage: unknown): TokenUsage | undefined;
299
309
  declare function createHoopilotHandler(options?: HoopilotServerOptions): (request: Request) => Promise<Response>;
300
310
  declare function startHoopilotServer(options?: HoopilotServerOptions): StartedHoopilotServer;
301
311
 
302
- export { AnthropicCompatibilityError, COPILOT_USAGE_API_VERSION, type CopilotAccess, CopilotAuth, CopilotAuthError, type CopilotAuthOptions, CopilotClient, type CopilotQuota, type CopilotUsage, DEFAULT_GITHUB_API_BASE_URL, DEFAULT_LOG_FORMAT, DEFAULT_LOG_LEVEL, DEFAULT_MODEL, type FetchLike, type HoopilotLogger, type HoopilotLoggerOptions, type HoopilotServerOptions, type JsonObject, type LogFields, type LogFormat, type LogLevel, type LogMethod, type Logger, MetricsRegistry, type MetricsSnapshot, type ModelTokenTotals, PROMETHEUS_CONTENT_TYPE, type RequestObservation, type StartedHoopilotServer, type TokenUsage, anthropicMessagesToResponsesRequest, applyCopilotHeaders, applyGithubApiHeaders, authStorePath, chatCompletionToCompletion, chatCompletionToResponse, completionStreamFromChatStream, completionsRequestToChatCompletion, createHoopilotHandler, createHoopilotLogger, estimateAnthropicMessageTokens, extractTokenUsage, fallbackModels, githubCopilotDeviceLogin, noopLogger, normalizeChatCompletionRequest, normalizeCopilotUsage, normalizeModelsResponse, normalizeRequestedModel, observeResponseUsage, parseLogFormat, parseLogLevel, readStoredCopilotAuth, responsesRequestToChatCompletion, responsesResponseToAnthropicMessage, responsesStreamFromChatStream, responsesStreamToAnthropicStream, startHoopilotServer, writeStoredCopilotAuth };
312
+ export { AnthropicCompatibilityError, COPILOT_USAGE_API_VERSION, type CopilotAccess, CopilotAuth, CopilotAuthError, type CopilotAuthOptions, CopilotClient, type CopilotQuota, type CopilotUsage, DEFAULT_GITHUB_API_BASE_URL, DEFAULT_LOG_FORMAT, DEFAULT_LOG_LEVEL, DEFAULT_MODEL, type FetchLike, type HoopilotLogger, type HoopilotLoggerOptions, type HoopilotServerOptions, type JsonObject, type LogFields, type LogFormat, type LogLevel, type LogMethod, type Logger, MetricsRegistry, type MetricsSnapshot, type ModelTokenTotals, PROMETHEUS_CONTENT_TYPE, type RequestObservation, type StartedHoopilotServer, type TokenUsage, anthropicMessagesToResponsesRequest, applyCopilotHeaders, applyGithubApiHeaders, authStorePath, chatCompletionToCompletion, chatCompletionToResponse, completionStreamFromChatStream, completionsRequestToChatCompletion, createHoopilotHandler, createHoopilotLogger, estimateAnthropicMessageTokens, extractTokenUsage, fallbackModels, githubCopilotDeviceLogin, noopLogger, normalizeChatCompletionRequest, normalizeCopilotUsage, normalizeModelsResponse, normalizeRequestedModel, observeResponseUsage, parseLogFormat, parseLogLevel, readStoredCopilotAuth, responsesCompactionResult, responsesRequestToChatCompletion, responsesResponseToAnthropicMessage, responsesStreamFromChatStream, responsesStreamToAnthropicStream, startHoopilotServer, writeStoredCopilotAuth };
package/dist/index.d.ts CHANGED
@@ -282,6 +282,16 @@ declare function normalizeChatCompletionRequest(request: JsonObject): JsonObject
282
282
  declare function completionsRequestToChatCompletion(request: JsonObject): JsonObject;
283
283
  declare function normalizeRequestedModel(model: unknown): string;
284
284
  declare function chatCompletionToResponse(completion: JsonObject, responseId?: string): JsonObject;
285
+ /**
286
+ * Reduce a Copilot `/responses` result into the `{ output }` document Codex's
287
+ * remote-compaction client (`POST /responses/compact`) deserializes. Codex keeps
288
+ * only assistant/user message items from `output` and discards everything else,
289
+ * so a Responses `output` array passes through verbatim; when the upstream only
290
+ * exposes `output_text` (or, for a stream it did not honor `stream: false` on,
291
+ * `output_text` deltas) a single assistant message is synthesized instead. The
292
+ * input may be a unary JSON body or an SSE stream, so both framings are handled.
293
+ */
294
+ declare function responsesCompactionResult(upstreamText: string, isSse: boolean): JsonObject;
285
295
  declare function chatCompletionToCompletion(completion: JsonObject): JsonObject;
286
296
  declare function completionStreamFromChatStream(chatStream: ReadableStream<Uint8Array>): ReadableStream<Uint8Array>;
287
297
  declare function normalizeModelsResponse(upstream: unknown): JsonObject;
@@ -299,4 +309,4 @@ declare function extractTokenUsage(usage: unknown): TokenUsage | undefined;
299
309
  declare function createHoopilotHandler(options?: HoopilotServerOptions): (request: Request) => Promise<Response>;
300
310
  declare function startHoopilotServer(options?: HoopilotServerOptions): StartedHoopilotServer;
301
311
 
302
- export { AnthropicCompatibilityError, COPILOT_USAGE_API_VERSION, type CopilotAccess, CopilotAuth, CopilotAuthError, type CopilotAuthOptions, CopilotClient, type CopilotQuota, type CopilotUsage, DEFAULT_GITHUB_API_BASE_URL, DEFAULT_LOG_FORMAT, DEFAULT_LOG_LEVEL, DEFAULT_MODEL, type FetchLike, type HoopilotLogger, type HoopilotLoggerOptions, type HoopilotServerOptions, type JsonObject, type LogFields, type LogFormat, type LogLevel, type LogMethod, type Logger, MetricsRegistry, type MetricsSnapshot, type ModelTokenTotals, PROMETHEUS_CONTENT_TYPE, type RequestObservation, type StartedHoopilotServer, type TokenUsage, anthropicMessagesToResponsesRequest, applyCopilotHeaders, applyGithubApiHeaders, authStorePath, chatCompletionToCompletion, chatCompletionToResponse, completionStreamFromChatStream, completionsRequestToChatCompletion, createHoopilotHandler, createHoopilotLogger, estimateAnthropicMessageTokens, extractTokenUsage, fallbackModels, githubCopilotDeviceLogin, noopLogger, normalizeChatCompletionRequest, normalizeCopilotUsage, normalizeModelsResponse, normalizeRequestedModel, observeResponseUsage, parseLogFormat, parseLogLevel, readStoredCopilotAuth, responsesRequestToChatCompletion, responsesResponseToAnthropicMessage, responsesStreamFromChatStream, responsesStreamToAnthropicStream, startHoopilotServer, writeStoredCopilotAuth };
312
+ export { AnthropicCompatibilityError, COPILOT_USAGE_API_VERSION, type CopilotAccess, CopilotAuth, CopilotAuthError, type CopilotAuthOptions, CopilotClient, type CopilotQuota, type CopilotUsage, DEFAULT_GITHUB_API_BASE_URL, DEFAULT_LOG_FORMAT, DEFAULT_LOG_LEVEL, DEFAULT_MODEL, type FetchLike, type HoopilotLogger, type HoopilotLoggerOptions, type HoopilotServerOptions, type JsonObject, type LogFields, type LogFormat, type LogLevel, type LogMethod, type Logger, MetricsRegistry, type MetricsSnapshot, type ModelTokenTotals, PROMETHEUS_CONTENT_TYPE, type RequestObservation, type StartedHoopilotServer, type TokenUsage, anthropicMessagesToResponsesRequest, applyCopilotHeaders, applyGithubApiHeaders, authStorePath, chatCompletionToCompletion, chatCompletionToResponse, completionStreamFromChatStream, completionsRequestToChatCompletion, createHoopilotHandler, createHoopilotLogger, estimateAnthropicMessageTokens, extractTokenUsage, fallbackModels, githubCopilotDeviceLogin, noopLogger, normalizeChatCompletionRequest, normalizeCopilotUsage, normalizeModelsResponse, normalizeRequestedModel, observeResponseUsage, parseLogFormat, parseLogLevel, readStoredCopilotAuth, responsesCompactionResult, responsesRequestToChatCompletion, responsesResponseToAnthropicMessage, responsesStreamFromChatStream, responsesStreamToAnthropicStream, startHoopilotServer, writeStoredCopilotAuth };
package/dist/index.js CHANGED
@@ -137,6 +137,48 @@ function chatCompletionToResponse(completion, responseId) {
137
137
  usage
138
138
  });
139
139
  }
140
+ function responsesCompactionResult(upstreamText, isSse) {
141
+ const output = isSse ? compactionOutputFromResponsesSse(upstreamText) : compactionOutputFromResponse(asRecord(safeJsonParse(upstreamText)));
142
+ return { output };
143
+ }
144
+ function compactionOutputFromResponse(response) {
145
+ if (Array.isArray(response.output) && response.output.length > 0) {
146
+ return response.output;
147
+ }
148
+ const text = contentToText(response.output_text);
149
+ return text ? [messageOutputItem(text)] : [];
150
+ }
151
+ function compactionOutputFromResponsesSse(text) {
152
+ let deltas = "";
153
+ let completedOutput;
154
+ for (const block of text.split(/\r?\n\r?\n/)) {
155
+ const data = block.split(/\r?\n/).filter((line) => line.startsWith("data:")).map((line) => line.slice(5).trim()).join("");
156
+ if (!data || data === "[DONE]") {
157
+ continue;
158
+ }
159
+ const record = asRecord(safeJsonParse(data));
160
+ const type = contentToText(record.type);
161
+ if (type === "response.output_text.delta") {
162
+ deltas += contentToText(record.delta);
163
+ } else if (type === "response.completed" || type === "response.incomplete") {
164
+ const response = asRecord(record.response);
165
+ if (Array.isArray(response.output)) {
166
+ completedOutput = response.output;
167
+ }
168
+ }
169
+ }
170
+ if (completedOutput && completedOutput.length > 0) {
171
+ return completedOutput;
172
+ }
173
+ return deltas ? [messageOutputItem(deltas)] : [];
174
+ }
175
+ function safeJsonParse(text) {
176
+ try {
177
+ return JSON.parse(text);
178
+ } catch {
179
+ return void 0;
180
+ }
181
+ }
140
182
  function chatCompletionToCompletion(completion) {
141
183
  return removeUndefined({
142
184
  choices: completionChoices(completion).map((choice, index) => {
@@ -2691,6 +2733,11 @@ function createHoopilotHandler(options = {}) {
2691
2733
  )
2692
2734
  );
2693
2735
  }
2736
+ if (request.method === "POST" && apiPath === "/v1/responses/compact") {
2737
+ return finish(
2738
+ await handleResponsesCompact(client, metrics, recordTokens, request, requestLogger)
2739
+ );
2740
+ }
2694
2741
  if (request.method === "POST" && apiPath === "/v1/responses") {
2695
2742
  return finish(
2696
2743
  await handleResponses(
@@ -2905,6 +2952,22 @@ async function handleResponses(client, metrics, recordTokens, request, logger, b
2905
2952
  )
2906
2953
  );
2907
2954
  }
2955
+ async function handleResponsesCompact(client, metrics, recordTokens, request, logger) {
2956
+ const body = await readJson(request);
2957
+ const upstream = await client.responses(
2958
+ JSON.stringify({ ...body, stream: false }),
2959
+ request.signal
2960
+ );
2961
+ metrics.recordUpstream("/responses", upstream.ok);
2962
+ if (!upstream.ok) {
2963
+ return proxyError(upstream, logger);
2964
+ }
2965
+ logUpstreamSuccess(logger, "/responses", upstream.status);
2966
+ const isSse = isStreamingResponse(upstream);
2967
+ const text = await upstream.text();
2968
+ recordResponseTextUsage(text, isSse, normalizeRequestedModel(body.model), recordTokens);
2969
+ return jsonResponse(responsesCompactionResult(text, isSse));
2970
+ }
2908
2971
  async function responseWithObservedUsage(response, fallbackModel, recordTokens, signal, bufferBody) {
2909
2972
  const isSse = isStreamingResponse(response);
2910
2973
  if (bufferBody && response.body) {
@@ -3224,6 +3287,8 @@ function canonicalApiPath(path) {
3224
3287
  return "/v1/messages/count_tokens";
3225
3288
  case "/responses":
3226
3289
  return "/v1/responses";
3290
+ case "/responses/compact":
3291
+ return "/v1/responses/compact";
3227
3292
  case "/usage":
3228
3293
  return "/v1/usage";
3229
3294
  default:
@@ -3258,6 +3323,9 @@ function routeFor(method, path) {
3258
3323
  if (method === "POST" && path === "/v1/completions") {
3259
3324
  return "completions";
3260
3325
  }
3326
+ if (method === "POST" && path === "/v1/responses/compact") {
3327
+ return "responses_compact";
3328
+ }
3261
3329
  if (method === "POST" && path === "/v1/responses") {
3262
3330
  return "responses";
3263
3331
  }
@@ -3365,6 +3433,7 @@ export {
3365
3433
  parseLogFormat,
3366
3434
  parseLogLevel,
3367
3435
  readStoredCopilotAuth,
3436
+ responsesCompactionResult,
3368
3437
  responsesRequestToChatCompletion,
3369
3438
  responsesResponseToAnthropicMessage,
3370
3439
  responsesStreamFromChatStream,