pi-freeflow 1.15.0 → 1.15.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/CHANGELOG.md +19 -0
- package/package.json +1 -1
- package/src/proxy.ts +23 -2
- package/src/relay-state.ts +1133 -1133
- package/src/relay.ts +399 -347
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,24 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 1.15.2
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- Relay traffic is now spent only on the free models the pool exists for: requests for other models go straight upstream even with the relay pool on, cutting relay bandwidth. Applies in automatic and always-on modes; relay-off behavior is unchanged.
|
|
8
|
+
- The disabled-deployment rollover now triggers only on genuine hosting verdicts, so ordinary payment and quota refusals always surface immediately without cooling a healthy relay. Relay-list imports also no longer show a negative removal count when the file holds more relays than the current pool.
|
|
9
|
+
|
|
10
|
+
## 1.15.1
|
|
11
|
+
|
|
12
|
+
### Patch Changes
|
|
13
|
+
|
|
14
|
+
- Requests now roll over to the next relay when the current one answers with a disabled-deployment verdict, instead of failing on the first relay and requiring a manual switch. Other payment and quota refusals still surface immediately.
|
|
15
|
+
|
|
16
|
+
## 1.15.0
|
|
17
|
+
|
|
18
|
+
### Minor Changes
|
|
19
|
+
|
|
20
|
+
- Free-tier requests now use native session identifiers and an up-to-date client version, after the upstream gateway began rejecting older formats with a free-tier error. `/freeflow test` also gains an end-to-end chat check that verifies a relay can actually run inference, not just list models.
|
|
21
|
+
|
|
3
22
|
## 1.14.0
|
|
4
23
|
|
|
5
24
|
### Minor Changes
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pi-freeflow",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "1.15.
|
|
4
|
+
"version": "1.15.2",
|
|
5
5
|
"description": "Thin provider for OMP/Pi — model list + dumb relay proxy + log; host pi-ai owns thinking/normalization",
|
|
6
6
|
"main": "extensions/index.ts",
|
|
7
7
|
"types": "src/index.ts",
|
package/src/proxy.ts
CHANGED
|
@@ -89,6 +89,21 @@ function withRateLimitHint(status: number, data: string): string {
|
|
|
89
89
|
return data;
|
|
90
90
|
}
|
|
91
91
|
|
|
92
|
+
/**
|
|
93
|
+
* Relay eligibility: only free-catalog models ride relay egress. Returns true
|
|
94
|
+
* when the model is a non-empty string present in MODEL_MAP or KILO_MODEL_IDS
|
|
95
|
+
* (Kilo traffic leaves via its own branch regardless), and when the model is
|
|
96
|
+
* missing/empty (e.g. GET /v1/models carries no body — preserve routing).
|
|
97
|
+
* Anything else (unknown/paid model ids, non-strings) goes direct upstream.
|
|
98
|
+
*/
|
|
99
|
+
export function isRelayEligibleModel(model: unknown): boolean {
|
|
100
|
+
if (model === undefined || model === null) return true;
|
|
101
|
+
if (typeof model !== "string") return false;
|
|
102
|
+
if (model.trim() === "") return true;
|
|
103
|
+
const canonical = resolveCanonicalModelId(model.trim());
|
|
104
|
+
return MODEL_MAP.has(canonical) || KILO_MODEL_IDS.has(canonical);
|
|
105
|
+
}
|
|
106
|
+
|
|
92
107
|
/**
|
|
93
108
|
* Extract client IP address from incoming HTTP request.
|
|
94
109
|
*/
|
|
@@ -692,12 +707,18 @@ export function startProxy(
|
|
|
692
707
|
res.end(data);
|
|
693
708
|
}
|
|
694
709
|
} else {
|
|
695
|
-
// OpenCode routing — relay
|
|
710
|
+
// OpenCode routing — relay egress is for free-catalog models
|
|
711
|
+
// only; unknown/paid models go direct upstream.
|
|
696
712
|
const relayState = getActiveRelayState();
|
|
697
|
-
const
|
|
713
|
+
const relayPoolOn =
|
|
698
714
|
relayState.mode !== "off" &&
|
|
699
715
|
relayState.enabled !== false &&
|
|
700
716
|
Boolean(relayState.url || (relayState.relays && relayState.relays.length > 0));
|
|
717
|
+
const relayEligible = isRelayEligibleModel(parsedBody?.model);
|
|
718
|
+
const shouldUseRelay = relayPoolOn && relayEligible;
|
|
719
|
+
if (relayPoolOn && !relayEligible) {
|
|
720
|
+
log("info", `relay bypass for non-catalog model ${String(parsedBody?.model ?? "?")} — routing direct upstream`, { model: parsedBody?.model }, reqId);
|
|
721
|
+
}
|
|
701
722
|
if (shouldUseRelay) {
|
|
702
723
|
const fullUrl = `${UPSTREAM_OPENCODE}${req.url ?? "/"}`;
|
|
703
724
|
const activeHost = relayState.url
|