open-agents-ai 0.103.15 → 0.103.16
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.js +163 -21
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -26223,6 +26223,13 @@ function cleanForwardHeaders(raw, targetHost) {
|
|
|
26223
26223
|
out.host = targetHost;
|
|
26224
26224
|
return out;
|
|
26225
26225
|
}
|
|
26226
|
+
function fmtTokens(n) {
|
|
26227
|
+
if (n < 1e3)
|
|
26228
|
+
return String(n);
|
|
26229
|
+
if (n < 1e6)
|
|
26230
|
+
return `${(n / 1e3).toFixed(1)}K`;
|
|
26231
|
+
return `${(n / 1e6).toFixed(1)}M`;
|
|
26232
|
+
}
|
|
26226
26233
|
function readExposeState(stateDir) {
|
|
26227
26234
|
try {
|
|
26228
26235
|
const path = join35(stateDir, STATE_FILE_NAME);
|
|
@@ -26347,7 +26354,11 @@ var init_expose = __esm({
|
|
|
26347
26354
|
totalRequests: 0,
|
|
26348
26355
|
activeConnections: 0,
|
|
26349
26356
|
errors: 0,
|
|
26350
|
-
|
|
26357
|
+
totalTokensIn: 0,
|
|
26358
|
+
totalTokensOut: 0,
|
|
26359
|
+
startedAt: Date.now(),
|
|
26360
|
+
modelUsage: /* @__PURE__ */ new Map(),
|
|
26361
|
+
users: /* @__PURE__ */ new Map()
|
|
26351
26362
|
};
|
|
26352
26363
|
get tunnelUrl() {
|
|
26353
26364
|
return this._tunnelUrl;
|
|
@@ -26509,7 +26520,20 @@ var init_expose = __esm({
|
|
|
26509
26520
|
totalRequests: this._stats.totalRequests,
|
|
26510
26521
|
activeConnections: this._stats.activeConnections,
|
|
26511
26522
|
errors: this._stats.errors,
|
|
26512
|
-
|
|
26523
|
+
totalTokensIn: this._stats.totalTokensIn,
|
|
26524
|
+
totalTokensOut: this._stats.totalTokensOut,
|
|
26525
|
+
uptimeSeconds: Math.floor((Date.now() - this._stats.startedAt) / 1e3),
|
|
26526
|
+
modelUsage: Object.fromEntries(this._stats.modelUsage),
|
|
26527
|
+
users: Array.from(this._stats.users.values()).map((u) => ({
|
|
26528
|
+
ip: u.ip,
|
|
26529
|
+
requests: u.requests,
|
|
26530
|
+
tokensIn: u.tokensIn,
|
|
26531
|
+
tokensOut: u.tokensOut,
|
|
26532
|
+
activeRequests: u.activeRequests,
|
|
26533
|
+
firstSeen: new Date(u.firstSeen).toISOString(),
|
|
26534
|
+
lastSeen: new Date(u.lastSeen).toISOString(),
|
|
26535
|
+
models: Object.fromEntries(Array.from(u.models.entries()).map(([m, v]) => [m, { requests: v.requests, tokensIn: v.tokensIn, tokensOut: v.tokensOut }]))
|
|
26536
|
+
}))
|
|
26513
26537
|
};
|
|
26514
26538
|
res.writeHead(200, { "Content-Type": "application/json" });
|
|
26515
26539
|
res.end(JSON.stringify({ ...metrics, gateway: gatewayStats }));
|
|
@@ -26519,8 +26543,26 @@ var init_expose = __esm({
|
|
|
26519
26543
|
});
|
|
26520
26544
|
return;
|
|
26521
26545
|
}
|
|
26546
|
+
const userIp = req.headers["cf-connecting-ip"] ?? req.headers["x-forwarded-for"]?.split(",")[0]?.trim() ?? req.socket.remoteAddress ?? "unknown";
|
|
26547
|
+
let user = this._stats.users.get(userIp);
|
|
26548
|
+
if (!user) {
|
|
26549
|
+
user = {
|
|
26550
|
+
ip: userIp,
|
|
26551
|
+
firstSeen: Date.now(),
|
|
26552
|
+
lastSeen: Date.now(),
|
|
26553
|
+
requests: 0,
|
|
26554
|
+
tokensIn: 0,
|
|
26555
|
+
tokensOut: 0,
|
|
26556
|
+
activeRequests: 0,
|
|
26557
|
+
models: /* @__PURE__ */ new Map()
|
|
26558
|
+
};
|
|
26559
|
+
this._stats.users.set(userIp, user);
|
|
26560
|
+
}
|
|
26522
26561
|
this._stats.totalRequests++;
|
|
26523
26562
|
this._stats.activeConnections++;
|
|
26563
|
+
user.requests++;
|
|
26564
|
+
user.activeRequests++;
|
|
26565
|
+
user.lastSeen = Date.now();
|
|
26524
26566
|
this.emitStats();
|
|
26525
26567
|
url.searchParams.delete("key");
|
|
26526
26568
|
const forwardPath = url.pathname + url.search;
|
|
@@ -26529,14 +26571,22 @@ var init_expose = __esm({
|
|
|
26529
26571
|
req.on("end", () => {
|
|
26530
26572
|
const body = Buffer.concat(bodyChunks);
|
|
26531
26573
|
let isStreaming = false;
|
|
26574
|
+
let requestModel = "";
|
|
26532
26575
|
if (req.method === "POST" && body.length > 0) {
|
|
26533
26576
|
try {
|
|
26534
26577
|
const text = body.toString("utf8", 0, Math.min(body.length, 1024));
|
|
26535
26578
|
const modelMatch = text.match(/"model"\s*:\s*"([^"]+)"/);
|
|
26536
26579
|
if (modelMatch) {
|
|
26537
|
-
|
|
26538
|
-
const count = this._stats.modelUsage.get(
|
|
26539
|
-
this._stats.modelUsage.set(
|
|
26580
|
+
requestModel = modelMatch[1];
|
|
26581
|
+
const count = this._stats.modelUsage.get(requestModel) ?? 0;
|
|
26582
|
+
this._stats.modelUsage.set(requestModel, count + 1);
|
|
26583
|
+
let mm = user.models.get(requestModel);
|
|
26584
|
+
if (!mm) {
|
|
26585
|
+
mm = { requests: 0, tokensIn: 0, tokensOut: 0, lastUsed: Date.now() };
|
|
26586
|
+
user.models.set(requestModel, mm);
|
|
26587
|
+
}
|
|
26588
|
+
mm.requests++;
|
|
26589
|
+
mm.lastUsed = Date.now();
|
|
26540
26590
|
}
|
|
26541
26591
|
isStreaming = /"stream"\s*:\s*true/.test(text);
|
|
26542
26592
|
} catch {
|
|
@@ -26567,6 +26617,50 @@ var init_expose = __esm({
|
|
|
26567
26617
|
heartbeatTimer = null;
|
|
26568
26618
|
}
|
|
26569
26619
|
};
|
|
26620
|
+
let responseTail = "";
|
|
26621
|
+
const finalizeRequest = () => {
|
|
26622
|
+
user.activeRequests = Math.max(0, user.activeRequests - 1);
|
|
26623
|
+
this._stats.activeConnections = Math.max(0, this._stats.activeConnections - 1);
|
|
26624
|
+
try {
|
|
26625
|
+
const promptEval = responseTail.match(/"prompt_eval_count"\s*:\s*(\d+)/);
|
|
26626
|
+
const evalCount = responseTail.match(/"eval_count"\s*:\s*(\d+)/);
|
|
26627
|
+
if (promptEval || evalCount) {
|
|
26628
|
+
const tIn = parseInt(promptEval?.[1] ?? "0", 10);
|
|
26629
|
+
const tOut = parseInt(evalCount?.[1] ?? "0", 10);
|
|
26630
|
+
this._stats.totalTokensIn += tIn;
|
|
26631
|
+
this._stats.totalTokensOut += tOut;
|
|
26632
|
+
user.tokensIn += tIn;
|
|
26633
|
+
user.tokensOut += tOut;
|
|
26634
|
+
if (requestModel) {
|
|
26635
|
+
const mm = user.models.get(requestModel);
|
|
26636
|
+
if (mm) {
|
|
26637
|
+
mm.tokensIn += tIn;
|
|
26638
|
+
mm.tokensOut += tOut;
|
|
26639
|
+
}
|
|
26640
|
+
}
|
|
26641
|
+
} else {
|
|
26642
|
+
const promptTokens = responseTail.match(/"prompt_tokens"\s*:\s*(\d+)/);
|
|
26643
|
+
const completionTokens = responseTail.match(/"completion_tokens"\s*:\s*(\d+)/);
|
|
26644
|
+
if (promptTokens || completionTokens) {
|
|
26645
|
+
const tIn = parseInt(promptTokens?.[1] ?? "0", 10);
|
|
26646
|
+
const tOut = parseInt(completionTokens?.[1] ?? "0", 10);
|
|
26647
|
+
this._stats.totalTokensIn += tIn;
|
|
26648
|
+
this._stats.totalTokensOut += tOut;
|
|
26649
|
+
user.tokensIn += tIn;
|
|
26650
|
+
user.tokensOut += tOut;
|
|
26651
|
+
if (requestModel) {
|
|
26652
|
+
const mm = user.models.get(requestModel);
|
|
26653
|
+
if (mm) {
|
|
26654
|
+
mm.tokensIn += tIn;
|
|
26655
|
+
mm.tokensOut += tOut;
|
|
26656
|
+
}
|
|
26657
|
+
}
|
|
26658
|
+
}
|
|
26659
|
+
}
|
|
26660
|
+
} catch {
|
|
26661
|
+
}
|
|
26662
|
+
this.emitStats();
|
|
26663
|
+
};
|
|
26570
26664
|
const proxyReq = httpRequest({
|
|
26571
26665
|
hostname: target.hostname,
|
|
26572
26666
|
port: target.port || (target.protocol === "https:" ? 443 : 80),
|
|
@@ -26576,8 +26670,14 @@ var init_expose = __esm({
|
|
|
26576
26670
|
}, (proxyRes) => {
|
|
26577
26671
|
cleanupHeartbeat();
|
|
26578
26672
|
proxyRes.on("error", () => {
|
|
26579
|
-
|
|
26580
|
-
|
|
26673
|
+
finalizeRequest();
|
|
26674
|
+
});
|
|
26675
|
+
proxyRes.on("data", (chunk) => {
|
|
26676
|
+
const text = chunk.toString();
|
|
26677
|
+
responseTail += text;
|
|
26678
|
+
if (responseTail.length > 2048) {
|
|
26679
|
+
responseTail = responseTail.slice(-2048);
|
|
26680
|
+
}
|
|
26581
26681
|
});
|
|
26582
26682
|
if (isStreaming) {
|
|
26583
26683
|
if (proxyRes.statusCode !== 200) {
|
|
@@ -26597,8 +26697,7 @@ var init_expose = __esm({
|
|
|
26597
26697
|
} catch {
|
|
26598
26698
|
}
|
|
26599
26699
|
this._stats.errors++;
|
|
26600
|
-
|
|
26601
|
-
this.emitStats();
|
|
26700
|
+
finalizeRequest();
|
|
26602
26701
|
});
|
|
26603
26702
|
return;
|
|
26604
26703
|
}
|
|
@@ -26608,14 +26707,12 @@ var init_expose = __esm({
|
|
|
26608
26707
|
proxyRes.pipe(res);
|
|
26609
26708
|
}
|
|
26610
26709
|
proxyRes.on("end", () => {
|
|
26611
|
-
|
|
26612
|
-
this.emitStats();
|
|
26710
|
+
finalizeRequest();
|
|
26613
26711
|
});
|
|
26614
26712
|
});
|
|
26615
26713
|
proxyReq.on("error", (err) => {
|
|
26616
26714
|
cleanupHeartbeat();
|
|
26617
26715
|
this._stats.errors++;
|
|
26618
|
-
this._stats.activeConnections = Math.max(0, this._stats.activeConnections - 1);
|
|
26619
26716
|
if (!res.headersSent) {
|
|
26620
26717
|
res.writeHead(502, { "Content-Type": "application/json" });
|
|
26621
26718
|
res.end(JSON.stringify({ error: `Backend unreachable: ${err.message}` }));
|
|
@@ -26631,7 +26728,7 @@ var init_expose = __esm({
|
|
|
26631
26728
|
} catch {
|
|
26632
26729
|
}
|
|
26633
26730
|
}
|
|
26634
|
-
|
|
26731
|
+
finalizeRequest();
|
|
26635
26732
|
});
|
|
26636
26733
|
if (body.length > 0) {
|
|
26637
26734
|
proxyReq.write(body);
|
|
@@ -26639,6 +26736,7 @@ var init_expose = __esm({
|
|
|
26639
26736
|
proxyReq.end();
|
|
26640
26737
|
});
|
|
26641
26738
|
req.on("error", () => {
|
|
26739
|
+
user.activeRequests = Math.max(0, user.activeRequests - 1);
|
|
26642
26740
|
this._stats.activeConnections = Math.max(0, this._stats.activeConnections - 1);
|
|
26643
26741
|
this.emitStats();
|
|
26644
26742
|
});
|
|
@@ -26669,8 +26767,12 @@ var init_expose = __esm({
|
|
|
26669
26767
|
});
|
|
26670
26768
|
this._cloudflaredPid = this.cloudflaredProcess.pid ?? null;
|
|
26671
26769
|
let urlFound = false;
|
|
26770
|
+
let stderrOutput = "";
|
|
26672
26771
|
const handleOutput = (data) => {
|
|
26673
26772
|
const text = data.toString();
|
|
26773
|
+
stderrOutput += text;
|
|
26774
|
+
if (stderrOutput.length > 4096)
|
|
26775
|
+
stderrOutput = stderrOutput.slice(-4096);
|
|
26674
26776
|
const urlMatch = text.match(/https:\/\/[a-z0-9-]+\.trycloudflare\.com/);
|
|
26675
26777
|
if (urlMatch && !urlFound) {
|
|
26676
26778
|
urlFound = true;
|
|
@@ -26690,7 +26792,8 @@ var init_expose = __esm({
|
|
|
26690
26792
|
this.cloudflaredProcess.on("close", (code) => {
|
|
26691
26793
|
if (!urlFound) {
|
|
26692
26794
|
clearTimeout(timeout);
|
|
26693
|
-
|
|
26795
|
+
const hint = stderrOutput.trim().split("\n").slice(-3).join(" | ");
|
|
26796
|
+
reject(new Error(`Cloudflared exited with code ${code}. ${hint ? "Output: " + hint : ""}`));
|
|
26694
26797
|
}
|
|
26695
26798
|
if (this._stats.status === "active") {
|
|
26696
26799
|
this.options.onInfo?.("Cloudflared tunnel died \u2014 restarting...");
|
|
@@ -26769,7 +26872,11 @@ ${this.formatConnectionInfo()}`);
|
|
|
26769
26872
|
});
|
|
26770
26873
|
}
|
|
26771
26874
|
emitStats() {
|
|
26772
|
-
this.emit("stats", {
|
|
26875
|
+
this.emit("stats", {
|
|
26876
|
+
...this._stats,
|
|
26877
|
+
modelUsage: new Map(this._stats.modelUsage),
|
|
26878
|
+
users: new Map(this._stats.users)
|
|
26879
|
+
});
|
|
26773
26880
|
}
|
|
26774
26881
|
/** Format connection info for display */
|
|
26775
26882
|
formatConnectionInfo() {
|
|
@@ -26795,15 +26902,50 @@ ${this.formatConnectionInfo()}`);
|
|
|
26795
26902
|
formatStats() {
|
|
26796
26903
|
const s = this._stats;
|
|
26797
26904
|
const lines = [];
|
|
26905
|
+
const uptimeSec = Math.floor((Date.now() - s.startedAt) / 1e3);
|
|
26906
|
+
const uptimeStr = uptimeSec < 60 ? `${uptimeSec}s` : uptimeSec < 3600 ? `${Math.floor(uptimeSec / 60)}m ${uptimeSec % 60}s` : `${Math.floor(uptimeSec / 3600)}h ${Math.floor(uptimeSec % 3600 / 60)}m`;
|
|
26798
26907
|
lines.push(` ${c2.bold("Expose Gateway Stats")}`);
|
|
26799
|
-
lines.push(` ${c2.cyan("Status".padEnd(
|
|
26800
|
-
lines.push(` ${c2.cyan("
|
|
26801
|
-
lines.push(` ${c2.cyan("
|
|
26802
|
-
lines.push(` ${c2.cyan("
|
|
26908
|
+
lines.push(` ${c2.cyan("Status".padEnd(18))} ${s.status === "active" ? c2.green("active") : s.status === "error" ? c2.red("error") : c2.yellow("standby")}`);
|
|
26909
|
+
lines.push(` ${c2.cyan("Uptime".padEnd(18))} ${uptimeStr}`);
|
|
26910
|
+
lines.push(` ${c2.cyan("Total requests".padEnd(18))} ${s.totalRequests}`);
|
|
26911
|
+
lines.push(` ${c2.cyan("Active conns".padEnd(18))} ${s.activeConnections}`);
|
|
26912
|
+
lines.push(` ${c2.cyan("Errors".padEnd(18))} ${s.errors}`);
|
|
26913
|
+
lines.push(` ${c2.cyan("Tokens in".padEnd(18))} ${fmtTokens(s.totalTokensIn)}`);
|
|
26914
|
+
lines.push(` ${c2.cyan("Tokens out".padEnd(18))} ${fmtTokens(s.totalTokensOut)}`);
|
|
26803
26915
|
if (s.modelUsage.size > 0) {
|
|
26804
|
-
lines.push(
|
|
26916
|
+
lines.push("");
|
|
26917
|
+
lines.push(` ${c2.bold("Models")}`);
|
|
26805
26918
|
for (const [model, count] of s.modelUsage) {
|
|
26806
|
-
|
|
26919
|
+
let mIn = 0, mOut = 0;
|
|
26920
|
+
for (const user of s.users.values()) {
|
|
26921
|
+
const mm = user.models.get(model);
|
|
26922
|
+
if (mm) {
|
|
26923
|
+
mIn += mm.tokensIn;
|
|
26924
|
+
mOut += mm.tokensOut;
|
|
26925
|
+
}
|
|
26926
|
+
}
|
|
26927
|
+
lines.push(` ${c2.cyan(model.padEnd(30))} ${count} reqs ${c2.dim(`in:${fmtTokens(mIn)} out:${fmtTokens(mOut)}`)}`);
|
|
26928
|
+
}
|
|
26929
|
+
}
|
|
26930
|
+
if (s.users.size > 0) {
|
|
26931
|
+
lines.push("");
|
|
26932
|
+
lines.push(` ${c2.bold("Active Users")} (${s.users.size})`);
|
|
26933
|
+
for (const user of s.users.values()) {
|
|
26934
|
+
const ageSec = Math.floor((Date.now() - user.firstSeen) / 1e3);
|
|
26935
|
+
const ageStr = ageSec < 60 ? `${ageSec}s` : ageSec < 3600 ? `${Math.floor(ageSec / 60)}m` : `${Math.floor(ageSec / 3600)}h ${Math.floor(ageSec % 3600 / 60)}m`;
|
|
26936
|
+
const lastSec = Math.floor((Date.now() - user.lastSeen) / 1e3);
|
|
26937
|
+
const lastStr = lastSec < 5 ? "now" : lastSec < 60 ? `${lastSec}s ago` : `${Math.floor(lastSec / 60)}m ago`;
|
|
26938
|
+
const activeTag = user.activeRequests > 0 ? c2.green(` [${user.activeRequests} active]`) : "";
|
|
26939
|
+
lines.push(` ${c2.bold(user.ip)}${activeTag}`);
|
|
26940
|
+
lines.push(` ${c2.dim("Session:")} ${ageStr} ${c2.dim("Last seen:")} ${lastStr} ${c2.dim("Requests:")} ${user.requests}`);
|
|
26941
|
+
lines.push(` ${c2.dim("Tokens:")} in:${fmtTokens(user.tokensIn)} out:${fmtTokens(user.tokensOut)} ${c2.dim("Total:")} ${fmtTokens(user.tokensIn + user.tokensOut)}`);
|
|
26942
|
+
if (user.models.size > 0) {
|
|
26943
|
+
const modelParts = [];
|
|
26944
|
+
for (const [m, mm] of user.models) {
|
|
26945
|
+
modelParts.push(`${m} (${mm.requests} reqs, ${fmtTokens(mm.tokensIn + mm.tokensOut)} tokens)`);
|
|
26946
|
+
}
|
|
26947
|
+
lines.push(` ${c2.dim("Models:")} ${modelParts.join(", ")}`);
|
|
26948
|
+
}
|
|
26807
26949
|
}
|
|
26808
26950
|
}
|
|
26809
26951
|
return lines.join("\n");
|
package/package.json
CHANGED