@openhoo/hoopilot 0.5.3 → 0.5.5
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 +4 -3
- package/dist/cli.js +41 -6
- package/dist/cli.js.map +1 -1
- package/dist/codexx.js +11 -2
- package/dist/codexx.js.map +1 -1
- package/dist/index.cjs +41 -6
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +41 -6
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -124,9 +124,10 @@ $env:HOOPILOT_API_KEY = "local-key"
|
|
|
124
124
|
npx --package @openhoo/hoopilot codexx -m gpt-5.5
|
|
125
125
|
```
|
|
126
126
|
|
|
127
|
-
`codexx` does not start Hoopilot and does not change your shell environment. It
|
|
128
|
-
|
|
129
|
-
`
|
|
127
|
+
`codexx` does not start Hoopilot and does not change your shell environment. It runs
|
|
128
|
+
`codex` with a temporary `hoopilot` model provider pointed at
|
|
129
|
+
`http://127.0.0.1:4141/v1`, disables Codex Responses WebSockets for that provider,
|
|
130
|
+
maps `HOOPILOT_API_KEY` to `OPENAI_API_KEY` for that child process, passes
|
|
130
131
|
`--disable network_proxy` to Codex, and removes standard proxy variables from the
|
|
131
132
|
spawned Codex process so Codex talks directly to the local server. Override the local
|
|
132
133
|
URL with `CODEXX_BASE_URL`, the local key with `CODEXX_API_KEY`, or the Codex
|
package/dist/cli.js
CHANGED
|
@@ -909,12 +909,13 @@ function createHoopilotHandler(options = {}) {
|
|
|
909
909
|
return async (request) => {
|
|
910
910
|
const startedAt = performance.now();
|
|
911
911
|
const url = new URL(request.url);
|
|
912
|
+
const apiPath = canonicalApiPath(url.pathname);
|
|
912
913
|
const requestId = requestIdFor(request);
|
|
913
914
|
const requestLogger = logger.child({
|
|
914
915
|
method: request.method,
|
|
915
916
|
path: url.pathname,
|
|
916
917
|
requestId,
|
|
917
|
-
route: routeFor(request.method,
|
|
918
|
+
route: routeFor(request.method, apiPath)
|
|
918
919
|
});
|
|
919
920
|
if (request.method === "OPTIONS") {
|
|
920
921
|
return finishResponse(new Response(null, { headers: corsHeaders() }), {
|
|
@@ -935,7 +936,7 @@ function createHoopilotHandler(options = {}) {
|
|
|
935
936
|
);
|
|
936
937
|
}
|
|
937
938
|
try {
|
|
938
|
-
if (request.method === "GET" && (
|
|
939
|
+
if (request.method === "GET" && (apiPath === "/" || apiPath === "/healthz")) {
|
|
939
940
|
return finishResponse(
|
|
940
941
|
jsonResponse({
|
|
941
942
|
name: "hoopilot",
|
|
@@ -945,28 +946,35 @@ function createHoopilotHandler(options = {}) {
|
|
|
945
946
|
{ logger: requestLogger, requestId, startedAt }
|
|
946
947
|
);
|
|
947
948
|
}
|
|
948
|
-
if (request.method === "GET" &&
|
|
949
|
+
if (request.method === "GET" && apiPath === "/v1/responses") {
|
|
950
|
+
return finishResponse(websocketUnsupportedResponse(), {
|
|
951
|
+
logger: requestLogger,
|
|
952
|
+
requestId,
|
|
953
|
+
startedAt
|
|
954
|
+
});
|
|
955
|
+
}
|
|
956
|
+
if (request.method === "GET" && apiPath === "/v1/models") {
|
|
949
957
|
return finishResponse(await handleModels(client, request.signal, requestLogger), {
|
|
950
958
|
logger: requestLogger,
|
|
951
959
|
requestId,
|
|
952
960
|
startedAt
|
|
953
961
|
});
|
|
954
962
|
}
|
|
955
|
-
if (request.method === "POST" &&
|
|
963
|
+
if (request.method === "POST" && apiPath === "/v1/chat/completions") {
|
|
956
964
|
return finishResponse(await handleChatCompletions(client, request, requestLogger), {
|
|
957
965
|
logger: requestLogger,
|
|
958
966
|
requestId,
|
|
959
967
|
startedAt
|
|
960
968
|
});
|
|
961
969
|
}
|
|
962
|
-
if (request.method === "POST" &&
|
|
970
|
+
if (request.method === "POST" && apiPath === "/v1/completions") {
|
|
963
971
|
return finishResponse(await handleCompletions(client, request, requestLogger), {
|
|
964
972
|
logger: requestLogger,
|
|
965
973
|
requestId,
|
|
966
974
|
startedAt
|
|
967
975
|
});
|
|
968
976
|
}
|
|
969
|
-
if (request.method === "POST" &&
|
|
977
|
+
if (request.method === "POST" && apiPath === "/v1/responses") {
|
|
970
978
|
return finishResponse(await handleResponses(client, request, requestLogger), {
|
|
971
979
|
logger: requestLogger,
|
|
972
980
|
requestId,
|
|
@@ -1156,6 +1164,15 @@ function jsonError(status, code, message) {
|
|
|
1156
1164
|
status
|
|
1157
1165
|
);
|
|
1158
1166
|
}
|
|
1167
|
+
function websocketUnsupportedResponse() {
|
|
1168
|
+
const response = jsonError(
|
|
1169
|
+
426,
|
|
1170
|
+
"websocket_not_supported",
|
|
1171
|
+
"Hoopilot does not support Responses WebSocket transport; retry with HTTP Responses API."
|
|
1172
|
+
);
|
|
1173
|
+
response.headers.set("upgrade", "websocket");
|
|
1174
|
+
return response;
|
|
1175
|
+
}
|
|
1159
1176
|
function corsHeaders() {
|
|
1160
1177
|
return {
|
|
1161
1178
|
"access-control-allow-headers": "authorization, content-type, x-api-key",
|
|
@@ -1231,6 +1248,21 @@ function requestIdFor(request) {
|
|
|
1231
1248
|
const existing = request.headers.get("x-request-id")?.trim();
|
|
1232
1249
|
return existing || crypto.randomUUID();
|
|
1233
1250
|
}
|
|
1251
|
+
function canonicalApiPath(path) {
|
|
1252
|
+
const withoutTrailingSlash = path.length > 1 ? path.replace(/\/+$/, "") : path;
|
|
1253
|
+
switch (withoutTrailingSlash) {
|
|
1254
|
+
case "/models":
|
|
1255
|
+
return "/v1/models";
|
|
1256
|
+
case "/chat/completions":
|
|
1257
|
+
return "/v1/chat/completions";
|
|
1258
|
+
case "/completions":
|
|
1259
|
+
return "/v1/completions";
|
|
1260
|
+
case "/responses":
|
|
1261
|
+
return "/v1/responses";
|
|
1262
|
+
default:
|
|
1263
|
+
return withoutTrailingSlash;
|
|
1264
|
+
}
|
|
1265
|
+
}
|
|
1234
1266
|
function routeFor(method, path) {
|
|
1235
1267
|
if (method === "OPTIONS") {
|
|
1236
1268
|
return "cors.preflight";
|
|
@@ -1250,6 +1282,9 @@ function routeFor(method, path) {
|
|
|
1250
1282
|
if (method === "POST" && path === "/v1/responses") {
|
|
1251
1283
|
return "responses";
|
|
1252
1284
|
}
|
|
1285
|
+
if (method === "GET" && path === "/v1/responses") {
|
|
1286
|
+
return "responses_websocket";
|
|
1287
|
+
}
|
|
1253
1288
|
return "not_found";
|
|
1254
1289
|
}
|
|
1255
1290
|
function isStreamingResponse(response) {
|