Skip to content
Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 9 additions & 9 deletions ci/e2e-assertion-budget.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,26 +15,26 @@
"testFileCount": 86,
"liveFileCount": 222,
"direct": {
"expectCalls": 1797,
"matcherAssertions": 1766,
"expectCalls": 1808,
"matcherAssertions": 1777,
"nodeAssertions": 105,
"namedAssertionHelpers": 601,
"failCalls": 8,
"throwGuards": 87,
"objectFieldAssertions": 243,
"assertionPoints": 2810,
"objectFieldAssertions": 252,
"assertionPoints": 2830,
"generatedProbeBlocks": 122,
"generatedProbeConditions": 322
},
"unique": {
"expectCalls": 2289,
"matcherAssertions": 2253,
"expectCalls": 2300,
"matcherAssertions": 2264,
"nodeAssertions": 126,
"namedAssertionHelpers": 905,
"failCalls": 38,
"throwGuards": 633,
"objectFieldAssertions": 342,
"assertionPoints": 4297,
"objectFieldAssertions": 351,
"assertionPoints": 4317,
"generatedProbeBlocks": 276,
"generatedProbeConditions": 943
},
Expand Down Expand Up @@ -65,7 +65,7 @@
"test/e2e/live/full-e2e.test.ts": [30,34,39,72,7],
"test/e2e/live/gateway-guard-recovery.test.ts": [48,54,48,57,3],
"test/e2e/live/gpu-double-onboard.test.ts": [21,24,21,24,0],
"test/e2e/live/gpu-e2e.test.ts": [40,45,73,91,3],
"test/e2e/live/gpu-e2e.test.ts": [51,65,84,111,3],
"test/e2e/live/hermes-discord.test.ts": [10,25,17,64,14],
"test/e2e/live/hermes-e2e.test.ts": [82,93,112,127,3],
"test/e2e/live/hermes-gpu-startup.test.ts": [19,27,63,106,12],
Expand Down
79 changes: 79 additions & 0 deletions schemas/nemoclaw-config-v1.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,85 @@
}
},
"additionalProperties": false
},
{
"type": "object",
"required": ["name", "provider", "api", "serving"],
"properties": {
"name": {
"type": "string",
"minLength": 1,
"maxLength": 63,
"pattern": "^[a-z0-9](?:[a-z0-9.-]*[a-z0-9])?$"
},
"provider": {
"type": "string",
"const": "ollama-local"
Comment thread
coderabbitai[bot] marked this conversation as resolved.
Resolved
},
"api": {
"type": "string",
"const": "openai-completions"
},
"serving": {
"type": "object",
"required": ["backend", "daemon", "proxy", "model"],
"properties": {
"backend": {
"type": "string",
"const": "ollama"
},
"daemon": {
"type": "object",
"required": ["management", "hostPort"],
"properties": {
"management": {
"type": "string",
"const": "external"
},
"hostPort": {
"type": "integer",
"minimum": 1,
"maximum": 65535
}
},
"additionalProperties": false
},
"proxy": {
"type": "object",
"required": ["management", "hostPort"],
"properties": {
"management": {
"type": "string",
"const": "nemoclaw"
},
"hostPort": {
"type": "integer",
"minimum": 1,
"maximum": 65535
}
},
"additionalProperties": false
},
"model": {
"type": "object",
"required": ["servedName", "digest"],
"properties": {
"servedName": {
"type": "string",
"const": "qwen3.5:9b"
},
"digest": {
"type": "string",
"pattern": "^sha256:[a-f0-9]{64}$"
}
},
"additionalProperties": false
}
},
"additionalProperties": false
}
},
"additionalProperties": false
}
]
},
Expand Down
30 changes: 29 additions & 1 deletion scripts/ollama-auth-proxy.mts
Original file line number Diff line number Diff line change
Expand Up @@ -342,7 +342,7 @@ function assertBackendBoundToLoopback(port: number): void {

function buildProxyServer(token: string, backendUrl: URL): http.Server {
const expectedBuf = Buffer.from(`Bearer ${token}`);
return http.createServer((clientReq, clientRes) => {
const server = http.createServer((clientReq, clientRes) => {
// Every request must present a valid Bearer token. The proxy binds 0.0.0.0
// so the OpenShell sandbox container can reach it via the docker bridge —
// which also means anything else with network reach to the host could,
Expand All @@ -366,6 +366,33 @@ function buildProxyServer(token: string, backendUrl: URL): http.Server {
return;
}

if (clientReq.url === "/_nemoclaw/proxy-config") {
if (clientReq.method !== "GET") {
clientRes.writeHead(405, { Allow: "GET" });
clientRes.end();
return;
}
const listener = server.address();
if (Buffer.byteLength(backendUrl.origin) > 512) {
clientRes.writeHead(503);
clientRes.end();
return;
}
clientRes.writeHead(200, { "Content-Type": "application/json", "Cache-Control": "no-store" });
clientRes.end(
JSON.stringify({
schemaVersion: 1,
pid: process.pid,
listener:
typeof listener === "object" && listener !== null
? { address: listener.address, port: listener.port }
: null,
backendOrigin: backendUrl.origin,
}),
);
return;
}

// Strip the auth header before forwarding to Ollama
const headers = { ...clientReq.headers };
delete headers.authorization;
Expand Down Expand Up @@ -407,6 +434,7 @@ function buildProxyServer(token: string, backendUrl: URL): http.Server {

clientReq.pipe(proxyReq);
});
return server;
}

function shouldProbeBackendHostname(hostname: string): boolean {
Expand Down
1 change: 1 addition & 0 deletions src/lib/actions/config/observe-export-source.ts
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ const LIVE_READ_SOURCE_LABELS = {
"provider-metadata": "live inference provider metadata",
"web-search-provider": "live web-search provider metadata",
"managed-serving": "managed serving runtime",
"ollama-serving": "live Ollama daemon and proxy mapping",
"effective-policy": "effective OpenShell policy",
} satisfies Readonly<Record<ExportSnapshotReadStage, string>>;

Expand Down
Loading
Loading