open-agents-ai 0.185.74 → 0.185.76
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 +251 -7
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -65550,6 +65550,9 @@ body {
|
|
|
65550
65550
|
<div id="agent-events" style="font-size:0.78rem;line-height:1.5"></div>
|
|
65551
65551
|
</div>
|
|
65552
65552
|
<div id="jobs-panel" style="display:none;flex:1;overflow-y:auto;padding:12px 16px">
|
|
65553
|
+
<div id="dashboard-health" style="display:flex;gap:12px;margin-bottom:16px;flex-wrap:wrap"></div>
|
|
65554
|
+
<div id="dashboard-usage" style="margin-bottom:16px"></div>
|
|
65555
|
+
<h3 style="color:#b2920a;font-size:0.7rem;margin-bottom:8px">Job History</h3>
|
|
65553
65556
|
<div id="jobs-list" style="font-size:0.78rem"></div>
|
|
65554
65557
|
</div>
|
|
65555
65558
|
|
|
@@ -65873,7 +65876,40 @@ async function abortAgentTask() {
|
|
|
65873
65876
|
try { await fetch('/v1/runs/' + currentRunId, { method: 'DELETE', headers: headers() }); } catch {}
|
|
65874
65877
|
}
|
|
65875
65878
|
|
|
65879
|
+
async function loadDashboard() {
|
|
65880
|
+
// Health card
|
|
65881
|
+
try {
|
|
65882
|
+
const r = await fetch('/health', { headers: headers() });
|
|
65883
|
+
const d = await r.json();
|
|
65884
|
+
document.getElementById('dashboard-health').innerHTML =
|
|
65885
|
+
'<div style="background:#1e1e22;border:1px solid #2a2a30;border-radius:3px;padding:8px 12px;flex:1;min-width:120px">' +
|
|
65886
|
+
'<div style="color:#555;font-size:0.6rem">STATUS</div>' +
|
|
65887
|
+
'<div style="color:#4ec94e;font-size:0.8rem">' + d.status + '</div></div>' +
|
|
65888
|
+
'<div style="background:#1e1e22;border:1px solid #2a2a30;border-radius:3px;padding:8px 12px;flex:1;min-width:120px">' +
|
|
65889
|
+
'<div style="color:#555;font-size:0.6rem">UPTIME</div>' +
|
|
65890
|
+
'<div style="color:#b2920a;font-size:0.8rem">' + Math.floor(d.uptime_s/60) + 'm</div></div>' +
|
|
65891
|
+
'<div style="background:#1e1e22;border:1px solid #2a2a30;border-radius:3px;padding:8px 12px;flex:1;min-width:120px">' +
|
|
65892
|
+
'<div style="color:#555;font-size:0.6rem">VERSION</div>' +
|
|
65893
|
+
'<div style="color:#b0b0b0;font-size:0.8rem">' + d.version + '</div></div>';
|
|
65894
|
+
} catch {}
|
|
65895
|
+
// Usage
|
|
65896
|
+
try {
|
|
65897
|
+
const r = await fetch('/v1/usage', { headers: headers() });
|
|
65898
|
+
const d = await r.json();
|
|
65899
|
+
document.getElementById('dashboard-usage').innerHTML =
|
|
65900
|
+
'<div style="display:flex;gap:12px;flex-wrap:wrap">' +
|
|
65901
|
+
'<div style="background:#1e1e22;border:1px solid #2a2a30;border-radius:3px;padding:8px 12px;flex:1">' +
|
|
65902
|
+
'<div style="color:#555;font-size:0.6rem">TOKENS IN</div>' +
|
|
65903
|
+
'<div style="color:#b2920a;font-size:0.8rem">' + (d.totalTokensIn || 0).toLocaleString() + '</div></div>' +
|
|
65904
|
+
'<div style="background:#1e1e22;border:1px solid #2a2a30;border-radius:3px;padding:8px 12px;flex:1">' +
|
|
65905
|
+
'<div style="color:#555;font-size:0.6rem">TOKENS OUT</div>' +
|
|
65906
|
+
'<div style="color:#b2920a;font-size:0.8rem">' + (d.totalTokensOut || 0).toLocaleString() + '</div></div>' +
|
|
65907
|
+
'</div>';
|
|
65908
|
+
} catch {}
|
|
65909
|
+
}
|
|
65910
|
+
|
|
65876
65911
|
async function loadJobs() {
|
|
65912
|
+
loadDashboard();
|
|
65877
65913
|
const list = document.getElementById('jobs-list');
|
|
65878
65914
|
try {
|
|
65879
65915
|
const r = await fetch('/v1/runs', { headers: headers() });
|
|
@@ -65941,6 +65977,98 @@ var init_logger = __esm({
|
|
|
65941
65977
|
}
|
|
65942
65978
|
});
|
|
65943
65979
|
|
|
65980
|
+
// packages/cli/dist/api/openapi.js
|
|
65981
|
+
function getOpenApiSpec() {
|
|
65982
|
+
return {
|
|
65983
|
+
openapi: "3.0.3",
|
|
65984
|
+
info: {
|
|
65985
|
+
title: "Open Agents REST API",
|
|
65986
|
+
description: "AI coding agent powered by open-weight models. Enterprise REST API for agentic task execution, OpenAI-compatible inference, and system management.",
|
|
65987
|
+
version: "0.185.75",
|
|
65988
|
+
license: { name: "CC-BY-NC-4.0", url: "https://creativecommons.org/licenses/by-nc/4.0/" }
|
|
65989
|
+
},
|
|
65990
|
+
servers: [{ url: "http://localhost:11435", description: "Local development" }],
|
|
65991
|
+
security: [{ BearerAuth: [] }],
|
|
65992
|
+
components: {
|
|
65993
|
+
securitySchemes: {
|
|
65994
|
+
BearerAuth: { type: "http", scheme: "bearer", description: "API key with scope (read/run/admin)" }
|
|
65995
|
+
}
|
|
65996
|
+
},
|
|
65997
|
+
paths: {
|
|
65998
|
+
"/health": { get: { summary: "Liveness probe", tags: ["Health"], security: [], responses: { 200: { description: "Server is alive" } } } },
|
|
65999
|
+
"/health/ready": { get: { summary: "Readiness probe (checks backend)", tags: ["Health"], security: [], responses: { 200: { description: "Backend reachable" }, 503: { description: "Backend unreachable" } } } },
|
|
66000
|
+
"/health/startup": { get: { summary: "Startup complete", tags: ["Health"], security: [], responses: { 200: { description: "Started" } } } },
|
|
66001
|
+
"/version": { get: { summary: "Version info", tags: ["Health"], security: [], responses: { 200: { description: "Version, node, platform" } } } },
|
|
66002
|
+
"/metrics": { get: { summary: "Prometheus metrics", tags: ["Health"], security: [], responses: { 200: { description: "Prometheus text format" } } } },
|
|
66003
|
+
"/v1/models": { get: { summary: "List available models", tags: ["Inference"], security: [{ BearerAuth: [] }], responses: { 200: { description: "OpenAI-format model list" } } } },
|
|
66004
|
+
"/v1/chat/completions": { post: { summary: "Chat completion (OpenAI-compatible)", tags: ["Inference"], security: [{ BearerAuth: [] }], requestBody: { required: true, content: { "application/json": { schema: { type: "object", required: ["model", "messages"], properties: { model: { type: "string" }, messages: { type: "array" }, stream: { type: "boolean" }, max_tokens: { type: "integer" }, temperature: { type: "number" } } } } } }, responses: { 200: { description: "Chat response" } } } },
|
|
66005
|
+
"/v1/embeddings": { post: { summary: "Generate embeddings", tags: ["Inference"], responses: { 200: { description: "Embedding vectors" } } } },
|
|
66006
|
+
"/v1/run": { post: { summary: "Submit agentic task", tags: ["Agentic"], requestBody: { required: true, content: { "application/json": { schema: { type: "object", required: ["task"], properties: { task: { type: "string" }, model: { type: "string" }, stream: { type: "boolean" }, profile: { type: "string" }, working_directory: { type: "string" }, isolate: { type: "boolean" } } } } } }, responses: { 202: { description: "Task accepted" } } } },
|
|
66007
|
+
"/v1/runs": { get: { summary: "List all runs", tags: ["Agentic"], parameters: [{ name: "limit", in: "query", schema: { type: "integer" } }, { name: "offset", in: "query", schema: { type: "integer" } }, { name: "status", in: "query", schema: { type: "string" } }], responses: { 200: { description: "Run list with pagination" } } } },
|
|
66008
|
+
"/v1/runs/{id}": { get: { summary: "Get run status", tags: ["Agentic"], parameters: [{ name: "id", in: "path", required: true, schema: { type: "string" } }], responses: { 200: { description: "Run details" }, 404: { description: "Not found" } } }, delete: { summary: "Abort run", tags: ["Agentic"], responses: { 200: { description: "Aborted" } } } },
|
|
66009
|
+
"/v1/config": { get: { summary: "Get configuration", tags: ["Config"], responses: { 200: { description: "Current config" } } }, patch: { summary: "Update configuration", tags: ["Config"], responses: { 200: { description: "Updated" } } } },
|
|
66010
|
+
"/v1/config/model": { get: { summary: "Current model", tags: ["Config"], responses: { 200: { description: "Model name" } } }, put: { summary: "Switch model", tags: ["Config"], responses: { 200: { description: "Switched" } } } },
|
|
66011
|
+
"/v1/config/endpoint": { get: { summary: "Current endpoint", tags: ["Config"], responses: { 200: { description: "Endpoint URL" } } }, put: { summary: "Switch endpoint", tags: ["Config"], responses: { 200: { description: "Switched" } } } },
|
|
66012
|
+
"/v1/usage": { get: { summary: "Token usage and rate limits", tags: ["Metering"], responses: { 200: { description: "Usage stats" } } } },
|
|
66013
|
+
"/v1/audit": { get: { summary: "Query audit log", tags: ["Audit"], parameters: [{ name: "since", in: "query", schema: { type: "string" } }, { name: "user", in: "query", schema: { type: "string" } }, { name: "limit", in: "query", schema: { type: "integer" } }], responses: { 200: { description: "Audit records" } } } },
|
|
66014
|
+
"/v1/commands": { get: { summary: "List slash commands", tags: ["Commands"], responses: { 200: { description: "Command list" } } } },
|
|
66015
|
+
"/v1/commands/{cmd}": { post: { summary: "Execute slash command", tags: ["Commands"], responses: { 200: { description: "Command output" } } } },
|
|
66016
|
+
"/v1/profiles": { get: { summary: "List tool profiles", tags: ["Profiles"], responses: { 200: { description: "Profile list" } } }, post: { summary: "Create profile", tags: ["Profiles"], responses: { 201: { description: "Created" } } } },
|
|
66017
|
+
"/v1/profiles/{name}": { get: { summary: "Get profile", tags: ["Profiles"], responses: { 200: { description: "Profile details" } } }, delete: { summary: "Delete profile", tags: ["Profiles"], responses: { 200: { description: "Deleted" } } } }
|
|
66018
|
+
}
|
|
66019
|
+
};
|
|
66020
|
+
}
|
|
66021
|
+
function getSwaggerUI() {
|
|
66022
|
+
return `<!DOCTYPE html><html><head><title>OA API Docs</title>
|
|
66023
|
+
<style>body{font-family:'SF Mono',monospace;background:#1a1a1e;color:#b0b0b0;margin:0;padding:20px}
|
|
66024
|
+
h1{color:#b2920a;font-size:1.2rem}h2{color:#b2920a;font-size:0.9rem;margin-top:20px}
|
|
66025
|
+
.endpoint{background:#1e1e22;border:1px solid #2a2a30;border-radius:3px;padding:10px;margin:8px 0}
|
|
66026
|
+
.method{font-weight:bold;padding:2px 8px;border-radius:2px;font-size:0.75rem}
|
|
66027
|
+
.get{color:#4ec94e}.post{color:#b2920a}.put{color:#4e94c9}.patch{color:#c9944e}.delete{color:#c94e4e}
|
|
66028
|
+
.path{color:#b0b0b0;margin-left:8px}.summary{color:#888;font-size:0.75rem;margin-left:12px}
|
|
66029
|
+
.tag{margin-top:16px;border-bottom:1px solid #2a2a30;padding-bottom:4px}
|
|
66030
|
+
a{color:#b2920a}
|
|
66031
|
+
</style></head><body>
|
|
66032
|
+
<h1>Open Agents API</h1>
|
|
66033
|
+
<p>Interactive docs. For full spec: <a href="/openapi.json">/openapi.json</a></p>
|
|
66034
|
+
<div id="docs"></div>
|
|
66035
|
+
<script>
|
|
66036
|
+
fetch('/openapi.json').then(r=>r.json()).then(spec=>{
|
|
66037
|
+
const docs=document.getElementById('docs');
|
|
66038
|
+
const tags={};
|
|
66039
|
+
for(const[path,methods]of Object.entries(spec.paths)){
|
|
66040
|
+
for(const[method,op]of Object.entries(methods)){
|
|
66041
|
+
const tag=(op.tags||['Other'])[0];
|
|
66042
|
+
if(!tags[tag])tags[tag]=[];
|
|
66043
|
+
tags[tag].push({method,path,summary:op.summary||''});
|
|
66044
|
+
}
|
|
66045
|
+
}
|
|
66046
|
+
for(const[tag,endpoints]of Object.entries(tags)){
|
|
66047
|
+
docs.innerHTML+='<div class="tag"><h2>'+tag+'</h2></div>';
|
|
66048
|
+
for(const ep of endpoints){
|
|
66049
|
+
docs.innerHTML+='<div class="endpoint"><span class="method '+ep.method+'">'+ep.method.toUpperCase()+'</span><span class="path">'+ep.path+'</span><span class="summary">'+ep.summary+'</span></div>';
|
|
66050
|
+
}
|
|
66051
|
+
}
|
|
66052
|
+
});
|
|
66053
|
+
</script></body></html>`;
|
|
66054
|
+
}
|
|
66055
|
+
var init_openapi = __esm({
|
|
66056
|
+
"packages/cli/dist/api/openapi.js"() {
|
|
66057
|
+
"use strict";
|
|
66058
|
+
}
|
|
66059
|
+
});
|
|
66060
|
+
|
|
66061
|
+
// packages/cli/dist/api/auth-oidc.js
|
|
66062
|
+
var OIDC_ISSUER, OIDC_AUDIENCE, OIDC_SCOPE_CLAIM;
|
|
66063
|
+
var init_auth_oidc = __esm({
|
|
66064
|
+
"packages/cli/dist/api/auth-oidc.js"() {
|
|
66065
|
+
"use strict";
|
|
66066
|
+
OIDC_ISSUER = process.env["OA_OIDC_ISSUER"] || "";
|
|
66067
|
+
OIDC_AUDIENCE = process.env["OA_OIDC_AUDIENCE"] || "";
|
|
66068
|
+
OIDC_SCOPE_CLAIM = process.env["OA_OIDC_SCOPE_CLAIM"] || "scope";
|
|
66069
|
+
}
|
|
66070
|
+
});
|
|
66071
|
+
|
|
65944
66072
|
// packages/cli/dist/api/profiles.js
|
|
65945
66073
|
import { existsSync as existsSync53, readFileSync as readFileSync42, writeFileSync as writeFileSync25, mkdirSync as mkdirSync27, readdirSync as readdirSync20, unlinkSync as unlinkSync12 } from "node:fs";
|
|
65946
66074
|
import { join as join70 } from "node:path";
|
|
@@ -66462,6 +66590,39 @@ function listJobs() {
|
|
|
66462
66590
|
}
|
|
66463
66591
|
return jobs;
|
|
66464
66592
|
}
|
|
66593
|
+
function getKeyUsage(user) {
|
|
66594
|
+
if (!perKeyUsage.has(user)) {
|
|
66595
|
+
perKeyUsage.set(user, { requestTimestamps: [], tokensToday: 0, tokenDate: (/* @__PURE__ */ new Date()).toISOString().slice(0, 10), activeJobs: 0 });
|
|
66596
|
+
}
|
|
66597
|
+
const u = perKeyUsage.get(user);
|
|
66598
|
+
const today = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
|
|
66599
|
+
if (u.tokenDate !== today) {
|
|
66600
|
+
u.tokensToday = 0;
|
|
66601
|
+
u.tokenDate = today;
|
|
66602
|
+
}
|
|
66603
|
+
return u;
|
|
66604
|
+
}
|
|
66605
|
+
function checkKeyRateLimit(auth) {
|
|
66606
|
+
if (!auth.user || !auth.rpm)
|
|
66607
|
+
return null;
|
|
66608
|
+
const usage = getKeyUsage(auth.user);
|
|
66609
|
+
const now = Date.now();
|
|
66610
|
+
usage.requestTimestamps = usage.requestTimestamps.filter((t) => now - t < 6e4);
|
|
66611
|
+
if (auth.rpm && usage.requestTimestamps.length >= auth.rpm) {
|
|
66612
|
+
return `Rate limit exceeded for ${auth.user}: ${auth.rpm} RPM`;
|
|
66613
|
+
}
|
|
66614
|
+
if (auth.tpd && usage.tokensToday >= auth.tpd) {
|
|
66615
|
+
return `Daily token limit exceeded for ${auth.user}: ${usage.tokensToday}/${auth.tpd}`;
|
|
66616
|
+
}
|
|
66617
|
+
return null;
|
|
66618
|
+
}
|
|
66619
|
+
function recordKeyUsage(user, tokens) {
|
|
66620
|
+
if (!user)
|
|
66621
|
+
return;
|
|
66622
|
+
const usage = getKeyUsage(user);
|
|
66623
|
+
usage.requestTimestamps.push(Date.now());
|
|
66624
|
+
usage.tokensToday += tokens;
|
|
66625
|
+
}
|
|
66465
66626
|
function resolveAuth(req) {
|
|
66466
66627
|
const authHeader = req.headers["authorization"];
|
|
66467
66628
|
const token = authHeader?.startsWith("Bearer ") ? authHeader.slice(7) : null;
|
|
@@ -66470,9 +66631,17 @@ function resolveAuth(req) {
|
|
|
66470
66631
|
if (!token)
|
|
66471
66632
|
return { authenticated: false, scope: "read" };
|
|
66472
66633
|
for (const entry of multiKeys.split(",")) {
|
|
66473
|
-
const
|
|
66634
|
+
const parts = entry.trim().split(":");
|
|
66635
|
+
const [key, scope, user, rpmStr, tpdStr, maxJobsStr] = parts;
|
|
66474
66636
|
if (key === token) {
|
|
66475
|
-
return {
|
|
66637
|
+
return {
|
|
66638
|
+
authenticated: true,
|
|
66639
|
+
scope: scope || "admin",
|
|
66640
|
+
user: user || void 0,
|
|
66641
|
+
rpm: rpmStr ? parseInt(rpmStr, 10) : void 0,
|
|
66642
|
+
tpd: tpdStr ? parseInt(tpdStr, 10) : void 0,
|
|
66643
|
+
maxJobs: maxJobsStr ? parseInt(maxJobsStr, 10) : void 0
|
|
66644
|
+
};
|
|
66476
66645
|
}
|
|
66477
66646
|
}
|
|
66478
66647
|
return { authenticated: false, scope: "read" };
|
|
@@ -66835,6 +67004,20 @@ async function handleV1Run(req, res) {
|
|
|
66835
67004
|
jsonResponse(res, 400, { error: "Missing required field: task" });
|
|
66836
67005
|
return;
|
|
66837
67006
|
}
|
|
67007
|
+
if (task.length > 5e4) {
|
|
67008
|
+
jsonResponse(res, 400, { error: "Task too long", message: "Max 50,000 characters", length: task.length });
|
|
67009
|
+
return;
|
|
67010
|
+
}
|
|
67011
|
+
const sandbox = requestBody["sandbox"] || process.env["OA_DEFAULT_SANDBOX"] || "none";
|
|
67012
|
+
if (sandbox === "container") {
|
|
67013
|
+
try {
|
|
67014
|
+
const { execSync: es } = __require("node:child_process");
|
|
67015
|
+
es("docker --version", { stdio: "pipe", timeout: 5e3 });
|
|
67016
|
+
} catch {
|
|
67017
|
+
jsonResponse(res, 400, { error: "Container sandbox unavailable", message: "Docker not found. Install Docker or use sandbox:'none'." });
|
|
67018
|
+
return;
|
|
67019
|
+
}
|
|
67020
|
+
}
|
|
66838
67021
|
const id = `job-${randomBytes16(3).toString("hex")}`;
|
|
66839
67022
|
const dir = jobsDir();
|
|
66840
67023
|
const workingDir = requestBody["working_directory"] || req.headers["x-working-directory"];
|
|
@@ -66982,9 +67165,17 @@ async function handleV1Run(req, res) {
|
|
|
66982
67165
|
jsonResponse(res, 202, { run_id: id, status: "running", pid: job.pid });
|
|
66983
67166
|
}
|
|
66984
67167
|
}
|
|
66985
|
-
function handleV1Runs(res) {
|
|
66986
|
-
|
|
66987
|
-
|
|
67168
|
+
function handleV1Runs(res, url) {
|
|
67169
|
+
let jobs = listJobs();
|
|
67170
|
+
const statusFilter = url?.searchParams.get("status");
|
|
67171
|
+
if (statusFilter)
|
|
67172
|
+
jobs = jobs.filter((j) => j.status === statusFilter);
|
|
67173
|
+
jobs.sort((a, b) => new Date(b.startedAt ?? 0).getTime() - new Date(a.startedAt ?? 0).getTime());
|
|
67174
|
+
const limit = parseInt(url?.searchParams.get("limit") ?? "50", 10);
|
|
67175
|
+
const offset = parseInt(url?.searchParams.get("offset") ?? "0", 10);
|
|
67176
|
+
const total = jobs.length;
|
|
67177
|
+
jobs = jobs.slice(offset, offset + limit);
|
|
67178
|
+
jsonResponse(res, 200, { runs: jobs, total, limit, offset });
|
|
66988
67179
|
}
|
|
66989
67180
|
function handleV1RunsById(res, id) {
|
|
66990
67181
|
const job = loadJob(id);
|
|
@@ -67193,6 +67384,15 @@ async function handleRequest(req, res, ollamaUrl, verbose) {
|
|
|
67193
67384
|
handleMetrics(res);
|
|
67194
67385
|
return;
|
|
67195
67386
|
}
|
|
67387
|
+
if (pathname === "/openapi.json" && method === "GET") {
|
|
67388
|
+
jsonResponse(res, 200, getOpenApiSpec());
|
|
67389
|
+
return;
|
|
67390
|
+
}
|
|
67391
|
+
if (pathname === "/docs" && method === "GET") {
|
|
67392
|
+
res.writeHead(200, { "Content-Type": "text/html; charset=utf-8" });
|
|
67393
|
+
res.end(getSwaggerUI());
|
|
67394
|
+
return;
|
|
67395
|
+
}
|
|
67196
67396
|
if (pathname === "/" && method === "GET" && req.headers.accept?.includes("text/html")) {
|
|
67197
67397
|
res.writeHead(200, { "Content-Type": "text/html; charset=utf-8" });
|
|
67198
67398
|
res.end(getWebUI());
|
|
@@ -67208,6 +67408,23 @@ async function handleRequest(req, res, ollamaUrl, verbose) {
|
|
|
67208
67408
|
status = 401;
|
|
67209
67409
|
return;
|
|
67210
67410
|
}
|
|
67411
|
+
const auth = resolveAuth(req);
|
|
67412
|
+
const rateLimitMsg = checkKeyRateLimit(auth);
|
|
67413
|
+
if (rateLimitMsg) {
|
|
67414
|
+
status = 429;
|
|
67415
|
+
jsonResponse(res, 429, { error: "Too Many Requests", message: rateLimitMsg });
|
|
67416
|
+
return;
|
|
67417
|
+
}
|
|
67418
|
+
if (auth.user)
|
|
67419
|
+
recordKeyUsage(auth.user, 0);
|
|
67420
|
+
}
|
|
67421
|
+
if ((method === "POST" || method === "PUT" || method === "PATCH") && req.headers["content-length"]) {
|
|
67422
|
+
const bodySize = parseInt(req.headers["content-length"], 10);
|
|
67423
|
+
if (bodySize > 1048576) {
|
|
67424
|
+
status = 413;
|
|
67425
|
+
jsonResponse(res, 413, { error: "Payload Too Large", message: "Request body exceeds 1MB limit" });
|
|
67426
|
+
return;
|
|
67427
|
+
}
|
|
67211
67428
|
}
|
|
67212
67429
|
if (pathname === "/v1/models" && method === "GET") {
|
|
67213
67430
|
await handleV1Models(res, ollamaUrl);
|
|
@@ -67226,7 +67443,7 @@ async function handleRequest(req, res, ollamaUrl, verbose) {
|
|
|
67226
67443
|
return;
|
|
67227
67444
|
}
|
|
67228
67445
|
if (pathname === "/v1/runs" && method === "GET") {
|
|
67229
|
-
handleV1Runs(res);
|
|
67446
|
+
handleV1Runs(res, urlObj);
|
|
67230
67447
|
return;
|
|
67231
67448
|
}
|
|
67232
67449
|
const runsMatch = pathname.match(/^\/v1\/runs\/([a-zA-Z0-9_-]+)$/);
|
|
@@ -67425,6 +67642,30 @@ function startApiServer(options = {}) {
|
|
|
67425
67642
|
const ollamaUrl = options.ollamaUrl ?? config.backendUrl;
|
|
67426
67643
|
const cwd4 = process.cwd();
|
|
67427
67644
|
initAuditLog(join71(cwd4, ".oa"));
|
|
67645
|
+
const retentionDays = parseInt(process.env["OA_JOB_RETENTION_DAYS"] ?? "30", 10);
|
|
67646
|
+
if (retentionDays > 0) {
|
|
67647
|
+
try {
|
|
67648
|
+
const jobsDir3 = join71(cwd4, ".oa", "jobs");
|
|
67649
|
+
if (existsSync54(jobsDir3)) {
|
|
67650
|
+
const cutoff = Date.now() - retentionDays * 864e5;
|
|
67651
|
+
for (const f of readdirSync21(jobsDir3)) {
|
|
67652
|
+
if (!f.endsWith(".json"))
|
|
67653
|
+
continue;
|
|
67654
|
+
try {
|
|
67655
|
+
const jobPath = join71(jobsDir3, f);
|
|
67656
|
+
const job = JSON.parse(readFileSync43(jobPath, "utf-8"));
|
|
67657
|
+
const jobTime = new Date(job.startedAt ?? job.completedAt ?? 0).getTime();
|
|
67658
|
+
if (jobTime > 0 && jobTime < cutoff && job.status !== "running") {
|
|
67659
|
+
const { unlinkSync: unlinkSync13 } = __require("node:fs");
|
|
67660
|
+
unlinkSync13(jobPath);
|
|
67661
|
+
}
|
|
67662
|
+
} catch {
|
|
67663
|
+
}
|
|
67664
|
+
}
|
|
67665
|
+
}
|
|
67666
|
+
} catch {
|
|
67667
|
+
}
|
|
67668
|
+
}
|
|
67428
67669
|
const tlsCert = process.env["OA_TLS_CERT"];
|
|
67429
67670
|
const tlsKey = process.env["OA_TLS_KEY"];
|
|
67430
67671
|
const useTls = !!(tlsCert && tlsKey);
|
|
@@ -67573,7 +67814,7 @@ async function apiServeCommand(opts, config) {
|
|
|
67573
67814
|
server.on("close", resolve36);
|
|
67574
67815
|
});
|
|
67575
67816
|
}
|
|
67576
|
-
var endpointRegistry, modelRouteMap, endpointUsage, metrics, startedAt, _corsOrigins, _corsLocalOnly, runningProcesses;
|
|
67817
|
+
var endpointRegistry, modelRouteMap, endpointUsage, metrics, startedAt, _corsOrigins, _corsLocalOnly, runningProcesses, perKeyUsage;
|
|
67577
67818
|
var init_serve = __esm({
|
|
67578
67819
|
"packages/cli/dist/api/serve.js"() {
|
|
67579
67820
|
"use strict";
|
|
@@ -67581,6 +67822,8 @@ var init_serve = __esm({
|
|
|
67581
67822
|
init_audit_log();
|
|
67582
67823
|
init_web_ui();
|
|
67583
67824
|
init_logger();
|
|
67825
|
+
init_openapi();
|
|
67826
|
+
init_auth_oidc();
|
|
67584
67827
|
init_oa_directory();
|
|
67585
67828
|
init_render();
|
|
67586
67829
|
init_profiles();
|
|
@@ -67597,6 +67840,7 @@ var init_serve = __esm({
|
|
|
67597
67840
|
_corsOrigins = (process.env["OA_CORS_ORIGINS"] || "").split(",").filter(Boolean);
|
|
67598
67841
|
_corsLocalOnly = _corsOrigins.length === 0;
|
|
67599
67842
|
runningProcesses = /* @__PURE__ */ new Map();
|
|
67843
|
+
perKeyUsage = /* @__PURE__ */ new Map();
|
|
67600
67844
|
}
|
|
67601
67845
|
});
|
|
67602
67846
|
|
package/package.json
CHANGED