Publish curated ITWorx-ModelForge source from 990401737f96c8d46a9f7b0d84994516cadcb6a0

This commit is contained in:
Public Source Publisher committed 2026-09-30 09:23:17 +00:00
1 parent 7082ab955a
commit 848f0d8f8a
434 files changed
+67298 -4315

No files matched your search

+54
View File
@@ -0,0 +1,54 @@
# Lightweight ModelForge clients
These dependency-free clients are included in the installable release archive. They invoke an exact
capability, never a model, node or worker. They use explicit timeouts, bounded responses and typed
errors carrying the HTTP status and correlation ID. They do not automatically retry inference or
follow redirects with credentials. They are server-side consumer clients, not browser session SDKs.
For Python 3.11+, copy `python/modelforge_client.py` into your application's import path. For Node.js
20+ JavaScript/TypeScript, copy `typescript/modelforge-client.mjs` and its adjacent `.d.mts` declaration
file into your source directory. No package registry or dependency installation is required.
Configure the consumer process:
```text
MODELFORGE_URL=https://modelforge.example.internal
MODELFORGE_TOKEN_FILE=/run/secrets/modelforge-token
MODELFORGE_CAPABILITY=rag.embedding@1
```
Store only the issued service key in that protected file. HTTP is rejected by default; set
`MODELFORGE_ALLOW_HTTP=true` only for an explicitly trusted private lab. Origins cannot contain
userinfo, paths, query strings or fragments. TLS certificate verification stays enabled.
```python
from modelforge_client import ModelForgeClient, ModelForgeError
client = ModelForgeClient.from_env(timeout=60)
try:
print(client.health()) # Verifies identity and scope; does not start inference.
response = client.invoke({"input": ["A non-sensitive integration check"]})
except ModelForgeError as error:
print(error.code, error.status, error.correlation_id)
```
```typescript
import { ModelForgeClient, ModelForgeError } from "./modelforge-client.mjs";
const client = await ModelForgeClient.fromEnv({ timeoutMs: 60000 });
try {
console.log(await client.health());
const response = await client.invoke({ input: ["A non-sensitive integration check"] });
} catch (error) {
if (error instanceof ModelForgeError)
console.error(error.code, error.status, error.correlationId);
else throw error;
}
```
Use the payload defined by your selected capability. `health()` proves connectivity, not model
health or production eligibility. Do not automatically retry timed-out inference: the server may
have admitted the original request. Retain correlation/request IDs for diagnosis.
Validation: backend `test_project_python_client.py` and
`node --test clients/typescript/modelforge-client.test.mjs`, both included in managed full validation.
+108
View File
@@ -0,0 +1,108 @@
"""Dependency-free ModelForge capability client. Python 3.11+, no automatic inference retries."""
from __future__ import annotations
import json
import math
import os
import re
from http.client import HTTPException
from pathlib import Path
from typing import Any
from urllib.error import HTTPError, URLError
from urllib.parse import quote, urlsplit
from urllib.request import HTTPRedirectHandler, Request, build_opener
MAX_RESPONSE_BYTES = 8 * 1024 * 1024
class ModelForgeError(Exception):
def __init__(self, code: str, message: str, status: int = 0, correlation_id: str | None = None):
super().__init__(message)
self.code = code
self.status = status
self.correlation_id = correlation_id
class _NoRedirect(HTTPRedirectHandler):
def redirect_request(self, req: Any, fp: Any, code: int, msg: str, headers: Any, newurl: str) -> None:
return None
class ModelForgeClient:
def __init__(self, base_url: str, token: str, capability: str, *, timeout: float = 60, allow_http: bool = False):
url = urlsplit(base_url)
if (url.scheme not in ({"http", "https"} if allow_http else {"https"})
or not url.hostname or url.username or url.password or url.query or url.fragment
or url.path not in {"", "/"}):
raise ValueError("Use a gateway origin without userinfo, path, query or fragment; HTTP requires allow_http=True")
if not re.fullmatch(r"[a-z][a-z0-9_.]*@[1-9][0-9]*", capability):
raise ValueError("Use an exact versioned capability key")
if not re.fullmatch(r"mf_[A-Za-z0-9_-]{48}", token):
raise ValueError("Use a scoped ModelForge service credential")
if not math.isfinite(timeout) or not 0 < timeout <= 300:
raise ValueError("timeout must be between 0 and 300 seconds")
self.base_url = base_url.rstrip("/")
self.capability = capability
self.timeout = timeout
self._token = token
self._opener = build_opener(_NoRedirect())
@classmethod
def from_env(cls, *, timeout: float = 60) -> ModelForgeClient:
with Path(os.environ["MODELFORGE_TOKEN_FILE"]).open("r", encoding="ascii") as handle:
token = handle.read(513).strip()
return cls(os.environ["MODELFORGE_URL"], token, os.environ["MODELFORGE_CAPABILITY"],
timeout=timeout, allow_http=os.getenv("MODELFORGE_ALLOW_HTTP") == "true")
def _request(self, suffix: str, body: dict[str, Any] | None = None) -> Any:
path = f"/api/v1/capabilities/{quote(self.capability, safe='')}/{suffix}"
request = Request(self.base_url + path, data=json.dumps(body).encode() if body is not None else None,
headers={"Authorization": f"Bearer {self._token}", "Content-Type": "application/json"},
method="POST" if body is not None else "GET")
try:
response = self._opener.open(request, timeout=self.timeout)
except HTTPError as error:
correlation = error.headers.get("X-Correlation-ID")
try:
with error:
raw = error.read(MAX_RESPONSE_BYTES + 1)
except (TimeoutError, OSError, HTTPException):
raise ModelForgeError("TRANSPORT_ERROR", "Gateway response failed or timed out",
error.code, correlation) from None
try:
payload = json.loads(raw) if len(raw) <= MAX_RESPONSE_BYTES else {}
except (ValueError, UnicodeError):
payload = {}
if not isinstance(payload, dict):
payload = {}
nested_error = payload.get("error")
error_payload = nested_error if isinstance(nested_error, dict) else payload
raise ModelForgeError(
str(error_payload.get("code", "HTTP_ERROR")),
str(error_payload.get("message", "Gateway request refused")),
error.code,
error_payload.get("correlation_id") or correlation,
) from None
except (URLError, TimeoutError, OSError, HTTPException):
raise ModelForgeError("TRANSPORT_ERROR", "Gateway connection failed or timed out") from None
try:
with response:
raw = response.read(MAX_RESPONSE_BYTES + 1)
correlation = response.headers.get("X-Correlation-ID")
except (TimeoutError, OSError, HTTPException):
raise ModelForgeError("TRANSPORT_ERROR", "Gateway response failed or timed out") from None
if len(raw) > MAX_RESPONSE_BYTES:
raise ModelForgeError("RESPONSE_TOO_LARGE", "Gateway response exceeds the client limit", correlation_id=correlation)
try:
return json.loads(raw)
except (ValueError, UnicodeError):
raise ModelForgeError("INVALID_RESPONSE", "Gateway response is not JSON", correlation_id=correlation) from None
def health(self) -> dict[str, Any]:
"""Authenticate the exact scope without executing inference."""
return self._request("check")
def invoke(self, payload: dict[str, Any]) -> Any:
"""Execute once. The client never changes capability, deployment or scheduling priority."""
return self._request("invoke", payload)
@@ -0,0 +1,17 @@
export interface ClientOptions { timeoutMs?: number; allowHttp?: boolean; }
export interface Connectivity { client_id: string; project_key: string | null; capability: string; connected: true; correlation_id: string; }
export class ModelForgeError extends Error {
readonly code: string;
readonly status: number;
readonly correlationId: string | null;
constructor(code: string, message: string, status?: number, correlationId?: string | null);
}
export class ModelForgeClient {
readonly baseUrl: string;
readonly capability: string;
readonly timeoutMs: number;
constructor(baseUrl: string, token: string, capability: string, options?: ClientOptions);
static fromEnv(options?: ClientOptions): Promise<ModelForgeClient>;
health(): Promise<Connectivity>;
invoke<T = unknown>(payload: Record<string, unknown>): Promise<T>;
}
+69
View File
@@ -0,0 +1,69 @@
import { open } from "node:fs/promises";
export class ModelForgeError extends Error {
constructor(code, message, status = 0, correlationId = null) {
super(message); this.name = "ModelForgeError"; this.code = code;
this.status = status; this.correlationId = correlationId;
}
}
/** Node.js 20+. Capability-only, bounded requests, no redirects or inference retries. */
export class ModelForgeClient {
#token;
constructor(baseUrl, token, capability, { timeoutMs = 60000, allowHttp = false } = {}) {
const url = new URL(baseUrl);
if (!((allowHttp && url.protocol === "http:") || url.protocol === "https:") || url.username || url.password || url.search || url.hash || url.pathname !== "/") throw new TypeError("Use a gateway origin; HTTP requires allowHttp: true");
if (!/^[a-z][a-z0-9_.]*@[1-9][0-9]*$/.test(capability)) throw new TypeError("Use an exact versioned capability key");
if (!/^mf_[A-Za-z0-9_-]{48}$/.test(token)) throw new TypeError("Use a scoped ModelForge service credential");
if (!Number.isFinite(timeoutMs) || timeoutMs <= 0 || timeoutMs > 300000) throw new TypeError("timeoutMs must be between 0 and 300000");
this.baseUrl = url.origin; this.capability = capability; this.timeoutMs = timeoutMs; this.#token = token;
}
static async fromEnv(options = {}) {
const file = await open(process.env.MODELFORGE_TOKEN_FILE, "r");
let token;
try { const buffer = Buffer.alloc(513); const { bytesRead } = await file.read(buffer); token = buffer.subarray(0, bytesRead).toString("utf8").trim(); }
finally { await file.close(); }
return new ModelForgeClient(process.env.MODELFORGE_URL, token, process.env.MODELFORGE_CAPABILITY, { allowHttp: process.env.MODELFORGE_ALLOW_HTTP === "true", ...options });
}
async #request(suffix, payload) {
let response;
let raw;
try {
response = await fetch(`${this.baseUrl}/api/v1/capabilities/${encodeURIComponent(this.capability)}/${suffix}`, {
method: payload === undefined ? "GET" : "POST", redirect: "error", credentials: "omit",
signal: AbortSignal.timeout(this.timeoutMs),
headers: { Authorization: `Bearer ${this.#token}`, "Content-Type": "application/json" },
body: payload === undefined ? undefined : JSON.stringify(payload),
});
const reader = response.body?.getReader();
const chunks = []; let size = 0;
if (reader) { try { while (true) {
const { done, value } = await reader.read(); if (done) break;
size += value.length;
if (size > 8 * 1024 * 1024) { await reader.cancel(); throw new ModelForgeError("RESPONSE_TOO_LARGE", "Gateway response exceeds the client limit"); }
chunks.push(value);
} } finally { reader.releaseLock(); } }
raw = Buffer.concat(chunks).toString("utf8");
} catch (error) {
if (error instanceof ModelForgeError) throw error;
throw new ModelForgeError("TRANSPORT_ERROR", "Gateway connection failed or timed out");
}
let data;
try { data = JSON.parse(raw); } catch { throw new ModelForgeError("INVALID_RESPONSE", "Gateway response is not JSON", response.status, response.headers.get("X-Correlation-ID")); }
if (!response.ok) {
const nestedError = data?.error;
const error = nestedError !== null && typeof nestedError === "object" ? nestedError : data;
const code = typeof error?.code === "string" ? error.code : "HTTP_ERROR";
const message = typeof error?.message === "string" ? error.message : "Gateway request refused";
throw new ModelForgeError(
code,
message,
response.status,
error?.correlation_id ?? response.headers.get("X-Correlation-ID"),
);
}
return data;
}
health() { return this.#request("check"); }
invoke(payload) { return this.#request("invoke", payload); }
}
@@ -0,0 +1,54 @@
import { strict as assert } from "node:assert";
import { createServer } from "node:http";
import { once } from "node:events";
import { test } from "node:test";
import { ModelForgeClient, ModelForgeError } from "./modelforge-client.mjs";
test("capability scope, typed errors, no retries, no redirect credential forwarding", async () => {
const seen = [];
const server = createServer(async (req, res) => {
seen.push({ path: req.url, authorization: req.headers.authorization });
if (req.method === "GET") { res.end('{"connected":true}'); return; }
const chunks = []; for await (const chunk of req) chunks.push(chunk);
const body = JSON.parse(Buffer.concat(chunks));
if (body.redirect) { res.writeHead(307, { Location: "/must-not-follow" }); res.end(); return; }
res.writeHead(503, { "Content-Type": "application/json" });
if (body.flat_error) {
res.end('{"code":"LEGACY_ERROR","message":"Legacy error","correlation_id":"legacy-case"}');
return;
}
res.end(JSON.stringify({ error: {
code: "NO_ELIGIBLE_NODE", message: "No node", correlation_id: "sdk-case",
details: { input: "private benchmark input that must remain redacted" },
} }));
});
server.listen(0, "127.0.0.1"); await once(server, "listening");
const token = "mf_" + "k".repeat(48);
try {
const client = new ModelForgeClient(`http://127.0.0.1:${server.address().port}`, token, "rag.embedding@1", { allowHttp: true, timeoutMs: 2000 });
assert.deepEqual(await client.health(), { connected: true });
await assert.rejects(client.invoke({ input: ["test"] }), (error) => {
assert.ok(error instanceof ModelForgeError);
assert.equal(error.code, "NO_ELIGIBLE_NODE");
assert.equal(error.message, "No node");
assert.equal(error.status, 503);
assert.equal(error.correlationId, "sdk-case");
assert.ok(!error.message.includes("private benchmark input"));
return true;
});
await assert.rejects(client.invoke({ flat_error: true }), (error) =>
error instanceof ModelForgeError
&& error.code === "LEGACY_ERROR"
&& error.message === "Legacy error"
&& error.correlationId === "legacy-case");
await assert.rejects(client.invoke({ redirect: true }), (error) => error instanceof ModelForgeError && error.code === "TRANSPORT_ERROR");
assert.equal(seen.length, 4);
assert.ok(seen.every(({ path, authorization }) => path.startsWith("/api/v1/capabilities/rag.embedding%401/") && authorization === `Bearer ${token}`));
assert.ok(!JSON.stringify(client).includes(token));
} finally { server.closeAllConnections(); await new Promise((resolve) => server.close(resolve)); }
});
test("unsafe origins and credential classes fail before network access", () => {
for (const origin of ["http://lab.invalid", "https://user:password@lab.invalid", "https://lab.invalid/path", "https://lab.invalid/?q=key"]) assert.throws(() => new ModelForgeClient(origin, "mf_" + "k".repeat(48), "rag.embedding@1"));
assert.throws(() => new ModelForgeClient("https://lab.invalid", "mfop_" + "k".repeat(43), "rag.embedding@1"));
});