pi-freeflow 1.0.7 → 1.0.8
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 +37 -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,16 @@ function normalizeRequestBody(
|
|
|
942
947
|
}
|
|
943
948
|
}
|
|
944
949
|
|
|
945
|
-
// 3. Max tokens
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
950
|
+
// 3. Max & Min tokens clamping (OpenCode Zen requires min 16; Vercel relay caps at 64k)
|
|
951
|
+
const mt = (body.max_tokens ?? body.maxTokens ?? body.max_output_tokens) as number | undefined;
|
|
952
|
+
if (typeof mt === "number") {
|
|
953
|
+
let clamped = mt;
|
|
954
|
+
if (clamped < 16) clamped = 16;
|
|
955
|
+
else if (isRelay && clamped > RELAY_MAX_TOKENS) clamped = RELAY_MAX_TOKENS;
|
|
956
|
+
|
|
957
|
+
if (body.max_tokens !== undefined) body.max_tokens = clamped;
|
|
958
|
+
if (body.maxTokens !== undefined) body.maxTokens = clamped;
|
|
959
|
+
if (body.max_output_tokens !== undefined) body.max_output_tokens = clamped;
|
|
951
960
|
}
|
|
952
961
|
|
|
953
962
|
return body;
|
|
@@ -1002,6 +1011,12 @@ function pipeUpstreamStream(
|
|
|
1002
1011
|
req.on("close", () => {
|
|
1003
1012
|
if (!nodeStream.destroyed) nodeStream.destroy();
|
|
1004
1013
|
});
|
|
1014
|
+
res.on("close", () => {
|
|
1015
|
+
if (!nodeStream.destroyed) nodeStream.destroy();
|
|
1016
|
+
});
|
|
1017
|
+
res.on("error", () => {
|
|
1018
|
+
if (!nodeStream.destroyed) nodeStream.destroy();
|
|
1019
|
+
});
|
|
1005
1020
|
}
|
|
1006
1021
|
|
|
1007
1022
|
// ── Start local proxy ──────────────────────────────────────────────
|
|
@@ -1083,13 +1098,15 @@ function startProxy(
|
|
|
1083
1098
|
if (isKilo && parsedBody) {
|
|
1084
1099
|
// KiloCode gateway routing (free models are keyless)
|
|
1085
1100
|
const isStream = parsedBody.stream === true;
|
|
1101
|
+
const kiloBodyObj = structuredClone(parsedBody);
|
|
1102
|
+
normalizeRequestBody(kiloBodyObj, true);
|
|
1086
1103
|
const response = await relayFetch(KILO_CHAT_URL, {
|
|
1087
1104
|
method: "POST",
|
|
1088
1105
|
headers: {
|
|
1089
1106
|
"Content-Type": "application/json",
|
|
1090
1107
|
Authorization: "Bearer kilo-free",
|
|
1091
1108
|
},
|
|
1092
|
-
body: JSON.stringify(
|
|
1109
|
+
body: JSON.stringify(kiloBodyObj),
|
|
1093
1110
|
signal: AbortSignal.timeout(300_000),
|
|
1094
1111
|
});
|
|
1095
1112
|
if (isStream && response.ok && response.body) {
|
|
@@ -1215,12 +1232,18 @@ function startProxy(
|
|
|
1215
1232
|
res.end();
|
|
1216
1233
|
}
|
|
1217
1234
|
});
|
|
1218
|
-
proxy.setTimeout(
|
|
1235
|
+
proxy.setTimeout(300_000, () => {
|
|
1219
1236
|
proxy.destroy(new Error("timeout"));
|
|
1220
1237
|
});
|
|
1221
1238
|
req.on("aborted", () => {
|
|
1222
1239
|
if (!proxy.destroyed) proxy.destroy();
|
|
1223
1240
|
});
|
|
1241
|
+
req.on("close", () => {
|
|
1242
|
+
if (!proxy.destroyed) proxy.destroy();
|
|
1243
|
+
});
|
|
1244
|
+
res.on("close", () => {
|
|
1245
|
+
if (!proxy.destroyed) proxy.destroy();
|
|
1246
|
+
});
|
|
1224
1247
|
// ponytail: body already buffered in bodyChunks above for model routing;
|
|
1225
1248
|
// req is drained so pipe() would send an empty body → upstream hang → 502.
|
|
1226
1249
|
proxy.end(directBody);
|
|
@@ -1273,7 +1296,8 @@ async function isProxyAlive(port: number): Promise<boolean> {
|
|
|
1273
1296
|
const res = await fetch(`http://${HOST}:${port}/v1/models`, {
|
|
1274
1297
|
signal: AbortSignal.timeout(500),
|
|
1275
1298
|
});
|
|
1276
|
-
|
|
1299
|
+
const ct = res.headers.get("content-type") || "";
|
|
1300
|
+
return res.ok && ct.includes("application/json");
|
|
1277
1301
|
} catch {
|
|
1278
1302
|
return false;
|
|
1279
1303
|
}
|
|
@@ -1611,7 +1635,7 @@ export default async function (pi: ExtensionAPI) {
|
|
|
1611
1635
|
pi.registerCommand("bansos", commandSpec);
|
|
1612
1636
|
|
|
1613
1637
|
// Reload persisted state on session start/resume (env overrides still win).
|
|
1614
|
-
pi.on("session_start", async (_event, ctx) => {
|
|
1638
|
+
pi.on?.("session_start", async (_event, ctx) => {
|
|
1615
1639
|
relayState = resolveRelayState();
|
|
1616
1640
|
statusUi = ctx.ui;
|
|
1617
1641
|
ctx.ui?.setStatus?.("freeflow", undefined);
|
|
@@ -1620,7 +1644,7 @@ export default async function (pi: ExtensionAPI) {
|
|
|
1620
1644
|
|
|
1621
1645
|
// Pi normally pauses after threshold compaction. Queue a follow-up while the
|
|
1622
1646
|
// original run is still active so the core agent continues automatically.
|
|
1623
|
-
pi.on("session_compact", (event, ctx) => {
|
|
1647
|
+
pi.on?.("session_compact", (event, ctx) => {
|
|
1624
1648
|
if (
|
|
1625
1649
|
event.reason !== "threshold" ||
|
|
1626
1650
|
event.willRetry ||
|
|
@@ -1629,7 +1653,7 @@ export default async function (pi: ExtensionAPI) {
|
|
|
1629
1653
|
) {
|
|
1630
1654
|
return;
|
|
1631
1655
|
}
|
|
1632
|
-
pi.sendUserMessage(
|
|
1656
|
+
pi.sendUserMessage?.(
|
|
1633
1657
|
"Continue the current task from the compacted context. Do not wait for another user message; proceed with the next required step.",
|
|
1634
1658
|
{ deliverAs: "followUp" },
|
|
1635
1659
|
);
|