@gethelio/proxy 0.1.0 → 0.1.1
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 +13 -14
- package/dist/cli.js +44 -4
- package/dist/dashboard-assets/assets/{index-Yyo92yXC.js → index-CAgnN6wV.js} +28 -28
- package/dist/dashboard-assets/index.html +1 -1
- package/dist/index.js +44 -4
- package/package.json +16 -15
package/README.md
CHANGED
|
@@ -249,20 +249,19 @@ Every tool call recorded: timestamp, agent identity, tool name, inputs, policy d
|
|
|
249
249
|
|
|
250
250
|
## How Helio Compares
|
|
251
251
|
|
|
252
|
-
|
|
|
253
|
-
|
|
|
254
|
-
| **
|
|
255
|
-
| **
|
|
256
|
-
| **
|
|
257
|
-
| **
|
|
258
|
-
| **
|
|
259
|
-
| **
|
|
260
|
-
| **
|
|
261
|
-
| **
|
|
262
|
-
| **
|
|
263
|
-
| **
|
|
264
|
-
| **
|
|
265
|
-
| **Language agnostic** | ✅ (proxy) | ✅ | ✅ | ✅ | ❌ Python only |
|
|
252
|
+
| | Helio | Obot | Cerbos | Built-in (Anthropic / OpenAI) | Framework (LangChain / CrewAI) |
|
|
253
|
+
| -------------------------------------------- | -------------------------------------- | ------------------------------ | --------------------------------- | ------------------------------------- | ----------------------------------- |
|
|
254
|
+
| **What it governs** | Per-call actions with cross-call state | Which tools/MCPs are reachable | App-level authorization decisions | Agent permissions inside one platform | Agent behavior inside one framework |
|
|
255
|
+
| **Architecture** | Out-of-process MCP proxy | Out-of-process MCP gateway | Sidecar / library | In-platform | In-framework |
|
|
256
|
+
| **Open source** | ✅ Apache 2.0 | ✅ Apache 2.0 | ✅ Apache 2.0 | ❌ | Varies |
|
|
257
|
+
| **Time to value** | 5 minutes | Setup-dependent | Hours | Built-in | Built-in |
|
|
258
|
+
| **No agent code changes** | ✅ | ✅ | ❌ | ✅ (within platform) | ❌ |
|
|
259
|
+
| **Governs agents you didn't build** | ✅ Any MCP agent | ✅ Any MCP agent | ✅ (any app) | ❌ One platform only | ❌ One framework only |
|
|
260
|
+
| **Evidence grounding** | ✅ Cumulative across calls | ❌ | ❌ | ❌ | Limited |
|
|
261
|
+
| **Self-repair feedback** | ✅ Structured retry hints | ❌ | ❌ | ❌ | Limited |
|
|
262
|
+
| **Stateful spend / rate limits** | ✅ Per-tool, per-session¹ | Basic | ❌ | ❌ | Limited |
|
|
263
|
+
| **Approval workflows** | ✅ Slack, webhook, dashboard | ✅ | ❌ | Limited | Limited |
|
|
264
|
+
| **Audit trail (incl. downstream responses)** | ✅ Captures upstream MCP responses | Decision logs | Decision logs | Platform telemetry | Framework logs |
|
|
266
265
|
|
|
267
266
|
\* Per-tool and per-session spend limits ship in v0.1. Cross-tool spend aggregation is planned for v0.2.
|
|
268
267
|
|
package/dist/cli.js
CHANGED
|
@@ -1198,6 +1198,45 @@ async function parseUpstreamResponse(res) {
|
|
|
1198
1198
|
return { status: res.status, headers, body };
|
|
1199
1199
|
}
|
|
1200
1200
|
|
|
1201
|
+
// src/upstream/connection-error.ts
|
|
1202
|
+
var UPSTREAM_DOCS_URL = "https://github.com/gethelio/helio/blob/main/docs/getting-started.md";
|
|
1203
|
+
var UNREACHABLE_CODES = /* @__PURE__ */ new Set([
|
|
1204
|
+
"ECONNREFUSED",
|
|
1205
|
+
"ENOTFOUND",
|
|
1206
|
+
"EAI_AGAIN",
|
|
1207
|
+
"ECONNRESET",
|
|
1208
|
+
"EHOSTUNREACH",
|
|
1209
|
+
"ENETUNREACH",
|
|
1210
|
+
"ETIMEDOUT",
|
|
1211
|
+
"EPIPE",
|
|
1212
|
+
"UND_ERR_CONNECT_TIMEOUT",
|
|
1213
|
+
"UND_ERR_SOCKET"
|
|
1214
|
+
]);
|
|
1215
|
+
function extractErrorCode(error) {
|
|
1216
|
+
let current = error;
|
|
1217
|
+
for (let depth = 0; depth < 5 && current != null; depth += 1) {
|
|
1218
|
+
if (typeof current === "object" && "code" in current) {
|
|
1219
|
+
const code = current.code;
|
|
1220
|
+
if (typeof code === "string") return code;
|
|
1221
|
+
}
|
|
1222
|
+
current = current.cause;
|
|
1223
|
+
}
|
|
1224
|
+
return void 0;
|
|
1225
|
+
}
|
|
1226
|
+
function describeUnreachableUpstream(error, url) {
|
|
1227
|
+
const code = extractErrorCode(error);
|
|
1228
|
+
const isGenericFetchFailure = error instanceof TypeError && error.message === "fetch failed";
|
|
1229
|
+
if (code !== void 0) {
|
|
1230
|
+
if (!UNREACHABLE_CODES.has(code)) return null;
|
|
1231
|
+
} else if (!isGenericFetchFailure) {
|
|
1232
|
+
return null;
|
|
1233
|
+
}
|
|
1234
|
+
const codeSuffix = code ? ` (${code})` : "";
|
|
1235
|
+
return new Error(
|
|
1236
|
+
`Upstream MCP server at ${url} is unreachable${codeSuffix} \u2014 is it running? Helio proxies an existing MCP server: set upstream.url in helio.yaml to a reachable server, or start the server it points at. See ${UPSTREAM_DOCS_URL}`
|
|
1237
|
+
);
|
|
1238
|
+
}
|
|
1239
|
+
|
|
1201
1240
|
// src/upstream/forwarder.ts
|
|
1202
1241
|
var UpstreamForwarder = class {
|
|
1203
1242
|
url;
|
|
@@ -1245,7 +1284,7 @@ var UpstreamForwarder = class {
|
|
|
1245
1284
|
if (isTimeout) {
|
|
1246
1285
|
throw new Error(`upstream request timed out after ${String(this.requestTimeoutMs)}ms`);
|
|
1247
1286
|
}
|
|
1248
|
-
throw error;
|
|
1287
|
+
throw describeUnreachableUpstream(error, this.url) ?? error;
|
|
1249
1288
|
}
|
|
1250
1289
|
const durationMs = performance.now() - start;
|
|
1251
1290
|
const contentType = res.headers.get("content-type") ?? "";
|
|
@@ -1406,7 +1445,7 @@ var SseUpstreamForwarder = class {
|
|
|
1406
1445
|
);
|
|
1407
1446
|
return;
|
|
1408
1447
|
}
|
|
1409
|
-
reject(asError);
|
|
1448
|
+
reject(describeUnreachableUpstream(err, this.url) ?? asError);
|
|
1410
1449
|
}
|
|
1411
1450
|
});
|
|
1412
1451
|
});
|
|
@@ -1452,7 +1491,7 @@ var SseUpstreamForwarder = class {
|
|
|
1452
1491
|
`upstream notification POST timed out after ${String(this.requestTimeoutMs)}ms`
|
|
1453
1492
|
);
|
|
1454
1493
|
}
|
|
1455
|
-
throw asError;
|
|
1494
|
+
throw describeUnreachableUpstream(error, this.postUrl) ?? asError;
|
|
1456
1495
|
}
|
|
1457
1496
|
if (!res.ok) {
|
|
1458
1497
|
throw new Error(`upstream notification POST failed: HTTP ${String(res.status)}`);
|
|
@@ -1499,7 +1538,8 @@ var SseUpstreamForwarder = class {
|
|
|
1499
1538
|
const asError = error instanceof Error ? error : new Error(String(error));
|
|
1500
1539
|
const isTimeout = asError.name === "TimeoutError";
|
|
1501
1540
|
const isAborted = request.signal?.aborted === true;
|
|
1502
|
-
const
|
|
1541
|
+
const networkFailure = describeUnreachableUpstream(error, this.postUrl) ?? asError;
|
|
1542
|
+
const postFailure = isTimeout ? new Error(`upstream request POST timed out after ${String(this.requestTimeoutMs)}ms`) : networkFailure;
|
|
1503
1543
|
this.pending.reject(
|
|
1504
1544
|
requestId,
|
|
1505
1545
|
isAborted ? new Error("request aborted by downstream client") : postFailure
|