pi-freeflow 1.0.7 → 1.0.9
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/extensions/index.ts +42 -13
- package/package.json +2 -1
package/extensions/index.ts
CHANGED
|
@@ -99,7 +99,11 @@ function loadRelayState(): RelayState {
|
|
|
99
99
|
}
|
|
100
100
|
function saveRelayState(s: RelayState): void {
|
|
101
101
|
try {
|
|
102
|
-
|
|
102
|
+
const dir = path.dirname(RELAY_STATE_FILE);
|
|
103
|
+
if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true });
|
|
104
|
+
const tmpPath = `${RELAY_STATE_FILE}.${randomUUID()}.tmp`;
|
|
105
|
+
fs.writeFileSync(tmpPath, JSON.stringify(s, null, 2), "utf8");
|
|
106
|
+
fs.renameSync(tmpPath, RELAY_STATE_FILE);
|
|
103
107
|
} catch (e) {
|
|
104
108
|
log("warn", "could not persist relay state", { error: String(e) });
|
|
105
109
|
}
|
|
@@ -663,6 +667,7 @@ const ALLOWED_METHODS = new Set(["GET", "POST", "OPTIONS", "HEAD"]);
|
|
|
663
667
|
const STRIP_HEADERS = new Set([
|
|
664
668
|
"authorization",
|
|
665
669
|
"host",
|
|
670
|
+
"content-length",
|
|
666
671
|
"x-forwarded-for",
|
|
667
672
|
"x-forwarded-host",
|
|
668
673
|
"x-forwarded-proto",
|
|
@@ -942,12 +947,21 @@ function normalizeRequestBody(
|
|
|
942
947
|
}
|
|
943
948
|
}
|
|
944
949
|
|
|
945
|
-
// 3. Max tokens
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
if (
|
|
949
|
-
|
|
950
|
-
|
|
950
|
+
// 3. Max & Min tokens clamping (OpenCode Zen requires min 16; Vercel relay caps at 64k)
|
|
951
|
+
const clampTokens = (val: number): number => {
|
|
952
|
+
if (val < 16) return 16;
|
|
953
|
+
if (isRelay && val > RELAY_MAX_TOKENS) return RELAY_MAX_TOKENS;
|
|
954
|
+
return val;
|
|
955
|
+
};
|
|
956
|
+
|
|
957
|
+
if (typeof body.max_tokens === "number") {
|
|
958
|
+
body.max_tokens = clampTokens(body.max_tokens);
|
|
959
|
+
}
|
|
960
|
+
if (typeof body.maxTokens === "number") {
|
|
961
|
+
body.maxTokens = clampTokens(body.maxTokens);
|
|
962
|
+
}
|
|
963
|
+
if (typeof body.max_output_tokens === "number") {
|
|
964
|
+
body.max_output_tokens = clampTokens(body.max_output_tokens);
|
|
951
965
|
}
|
|
952
966
|
|
|
953
967
|
return body;
|
|
@@ -1002,6 +1016,12 @@ function pipeUpstreamStream(
|
|
|
1002
1016
|
req.on("close", () => {
|
|
1003
1017
|
if (!nodeStream.destroyed) nodeStream.destroy();
|
|
1004
1018
|
});
|
|
1019
|
+
res.on("close", () => {
|
|
1020
|
+
if (!nodeStream.destroyed) nodeStream.destroy();
|
|
1021
|
+
});
|
|
1022
|
+
res.on("error", () => {
|
|
1023
|
+
if (!nodeStream.destroyed) nodeStream.destroy();
|
|
1024
|
+
});
|
|
1005
1025
|
}
|
|
1006
1026
|
|
|
1007
1027
|
// ── Start local proxy ──────────────────────────────────────────────
|
|
@@ -1083,13 +1103,15 @@ function startProxy(
|
|
|
1083
1103
|
if (isKilo && parsedBody) {
|
|
1084
1104
|
// KiloCode gateway routing (free models are keyless)
|
|
1085
1105
|
const isStream = parsedBody.stream === true;
|
|
1106
|
+
const kiloBodyObj = structuredClone(parsedBody);
|
|
1107
|
+
normalizeRequestBody(kiloBodyObj, true);
|
|
1086
1108
|
const response = await relayFetch(KILO_CHAT_URL, {
|
|
1087
1109
|
method: "POST",
|
|
1088
1110
|
headers: {
|
|
1089
1111
|
"Content-Type": "application/json",
|
|
1090
1112
|
Authorization: "Bearer kilo-free",
|
|
1091
1113
|
},
|
|
1092
|
-
body: JSON.stringify(
|
|
1114
|
+
body: JSON.stringify(kiloBodyObj),
|
|
1093
1115
|
signal: AbortSignal.timeout(300_000),
|
|
1094
1116
|
});
|
|
1095
1117
|
if (isStream && response.ok && response.body) {
|
|
@@ -1215,12 +1237,18 @@ function startProxy(
|
|
|
1215
1237
|
res.end();
|
|
1216
1238
|
}
|
|
1217
1239
|
});
|
|
1218
|
-
proxy.setTimeout(
|
|
1240
|
+
proxy.setTimeout(300_000, () => {
|
|
1219
1241
|
proxy.destroy(new Error("timeout"));
|
|
1220
1242
|
});
|
|
1221
1243
|
req.on("aborted", () => {
|
|
1222
1244
|
if (!proxy.destroyed) proxy.destroy();
|
|
1223
1245
|
});
|
|
1246
|
+
req.on("close", () => {
|
|
1247
|
+
if (!proxy.destroyed) proxy.destroy();
|
|
1248
|
+
});
|
|
1249
|
+
res.on("close", () => {
|
|
1250
|
+
if (!proxy.destroyed) proxy.destroy();
|
|
1251
|
+
});
|
|
1224
1252
|
// ponytail: body already buffered in bodyChunks above for model routing;
|
|
1225
1253
|
// req is drained so pipe() would send an empty body → upstream hang → 502.
|
|
1226
1254
|
proxy.end(directBody);
|
|
@@ -1273,7 +1301,8 @@ async function isProxyAlive(port: number): Promise<boolean> {
|
|
|
1273
1301
|
const res = await fetch(`http://${HOST}:${port}/v1/models`, {
|
|
1274
1302
|
signal: AbortSignal.timeout(500),
|
|
1275
1303
|
});
|
|
1276
|
-
|
|
1304
|
+
const ct = res.headers.get("content-type") || "";
|
|
1305
|
+
return res.ok && ct.includes("application/json");
|
|
1277
1306
|
} catch {
|
|
1278
1307
|
return false;
|
|
1279
1308
|
}
|
|
@@ -1611,7 +1640,7 @@ export default async function (pi: ExtensionAPI) {
|
|
|
1611
1640
|
pi.registerCommand("bansos", commandSpec);
|
|
1612
1641
|
|
|
1613
1642
|
// Reload persisted state on session start/resume (env overrides still win).
|
|
1614
|
-
pi.on("session_start", async (_event, ctx) => {
|
|
1643
|
+
pi.on?.("session_start", async (_event, ctx) => {
|
|
1615
1644
|
relayState = resolveRelayState();
|
|
1616
1645
|
statusUi = ctx.ui;
|
|
1617
1646
|
ctx.ui?.setStatus?.("freeflow", undefined);
|
|
@@ -1620,7 +1649,7 @@ export default async function (pi: ExtensionAPI) {
|
|
|
1620
1649
|
|
|
1621
1650
|
// Pi normally pauses after threshold compaction. Queue a follow-up while the
|
|
1622
1651
|
// original run is still active so the core agent continues automatically.
|
|
1623
|
-
pi.on("session_compact", (event, ctx) => {
|
|
1652
|
+
pi.on?.("session_compact", (event, ctx) => {
|
|
1624
1653
|
if (
|
|
1625
1654
|
event.reason !== "threshold" ||
|
|
1626
1655
|
event.willRetry ||
|
|
@@ -1629,7 +1658,7 @@ export default async function (pi: ExtensionAPI) {
|
|
|
1629
1658
|
) {
|
|
1630
1659
|
return;
|
|
1631
1660
|
}
|
|
1632
|
-
pi.sendUserMessage(
|
|
1661
|
+
pi.sendUserMessage?.(
|
|
1633
1662
|
"Continue the current task from the compacted context. Do not wait for another user message; proceed with the next required step.",
|
|
1634
1663
|
{ deliverAs: "followUp" },
|
|
1635
1664
|
);
|