@ainyc/canonry 1.7.0 → 1.7.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 +54 -12
- package/assets/assets/index-D_jajzpq.js +205 -0
- package/assets/index.html +1 -1
- package/dist/{chunk-2QG7TZ4A.js → chunk-WTI5ALRV.js} +72 -5
- package/dist/cli.js +431 -69
- package/dist/index.js +1 -1
- package/package.json +5 -5
- package/assets/assets/index-Cgb-VMub.js +0 -205
package/assets/index.html
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
content="Canonry is the AINYC monitoring dashboard for answer visibility and technical readiness."
|
|
9
9
|
/>
|
|
10
10
|
<title>Canonry</title>
|
|
11
|
-
<script type="module" crossorigin src="/assets/index-
|
|
11
|
+
<script type="module" crossorigin src="/assets/index-D_jajzpq.js"></script>
|
|
12
12
|
<link rel="stylesheet" crossorigin href="/assets/index-BxWGYuSH.css">
|
|
13
13
|
</head>
|
|
14
14
|
<body>
|
|
@@ -1155,6 +1155,55 @@ async function runRoutes(app, opts) {
|
|
|
1155
1155
|
const rows = app.db.select().from(runs).all();
|
|
1156
1156
|
return reply.send(rows.map(formatRun));
|
|
1157
1157
|
});
|
|
1158
|
+
app.post("/runs", async (request, reply) => {
|
|
1159
|
+
const allProjects = app.db.select().from(projects).all();
|
|
1160
|
+
if (allProjects.length === 0) {
|
|
1161
|
+
return reply.status(207).send([]);
|
|
1162
|
+
}
|
|
1163
|
+
const kind = request.body?.kind ?? "answer-visibility";
|
|
1164
|
+
if (kind !== "answer-visibility") {
|
|
1165
|
+
const err = unsupportedKind(kind);
|
|
1166
|
+
return reply.status(err.statusCode).send(err.toJSON());
|
|
1167
|
+
}
|
|
1168
|
+
const rawProviders = request.body?.providers;
|
|
1169
|
+
if (rawProviders?.length) {
|
|
1170
|
+
const parsed = rawProviders.map((p) => parseProviderName(p));
|
|
1171
|
+
const invalid = rawProviders.filter((_, i) => !parsed[i]);
|
|
1172
|
+
if (invalid.length) {
|
|
1173
|
+
return reply.status(400).send({ error: { code: "VALIDATION_ERROR", message: `Invalid provider(s): ${invalid.join(", ")}. Must be one of: gemini, openai, claude, local` } });
|
|
1174
|
+
}
|
|
1175
|
+
rawProviders.splice(0, rawProviders.length, ...parsed.filter(Boolean));
|
|
1176
|
+
}
|
|
1177
|
+
const providers = rawProviders?.length ? rawProviders : void 0;
|
|
1178
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
1179
|
+
const results = [];
|
|
1180
|
+
for (const project of allProjects) {
|
|
1181
|
+
const queueResult = queueRunIfProjectIdle(app.db, {
|
|
1182
|
+
createdAt: now,
|
|
1183
|
+
kind,
|
|
1184
|
+
projectId: project.id,
|
|
1185
|
+
trigger: "manual"
|
|
1186
|
+
});
|
|
1187
|
+
if (queueResult.conflict) {
|
|
1188
|
+
results.push({ projectName: project.name, projectId: project.id, status: "conflict", error: "run_in_progress" });
|
|
1189
|
+
continue;
|
|
1190
|
+
}
|
|
1191
|
+
const runId = queueResult.runId;
|
|
1192
|
+
writeAuditLog(app.db, {
|
|
1193
|
+
projectId: project.id,
|
|
1194
|
+
actor: "api",
|
|
1195
|
+
action: "run.created",
|
|
1196
|
+
entityType: "run",
|
|
1197
|
+
entityId: runId
|
|
1198
|
+
});
|
|
1199
|
+
const run = app.db.select().from(runs).where(eq7(runs.id, runId)).get();
|
|
1200
|
+
if (opts.onRunCreated) {
|
|
1201
|
+
opts.onRunCreated(runId, project.id, providers);
|
|
1202
|
+
}
|
|
1203
|
+
results.push({ ...formatRun(run), projectName: project.name });
|
|
1204
|
+
}
|
|
1205
|
+
return reply.status(207).send(results);
|
|
1206
|
+
});
|
|
1158
1207
|
app.get("/runs/:id", async (request, reply) => {
|
|
1159
1208
|
const run = app.db.select().from(runs).where(eq7(runs.id, request.params.id)).get();
|
|
1160
1209
|
if (!run) {
|
|
@@ -1887,7 +1936,7 @@ async function settingsRoutes(app, opts) {
|
|
|
1887
1936
|
}));
|
|
1888
1937
|
app.put("/settings/providers/:name", async (request, reply) => {
|
|
1889
1938
|
const providerName = parseProviderName(request.params.name);
|
|
1890
|
-
const { apiKey, baseUrl, model } = request.body ?? {};
|
|
1939
|
+
const { apiKey, baseUrl, model, quota } = request.body ?? {};
|
|
1891
1940
|
if (!providerName) {
|
|
1892
1941
|
return reply.status(400).send({ error: `Invalid provider: ${request.params.name}. Must be one of: gemini, openai, claude, local` });
|
|
1893
1942
|
}
|
|
@@ -1921,7 +1970,20 @@ async function settingsRoutes(app, opts) {
|
|
|
1921
1970
|
if (!opts.onProviderUpdate) {
|
|
1922
1971
|
return reply.status(501).send({ error: "Provider configuration updates are not supported in this deployment" });
|
|
1923
1972
|
}
|
|
1924
|
-
|
|
1973
|
+
if (quota !== void 0) {
|
|
1974
|
+
if (typeof quota !== "object" || quota === null) {
|
|
1975
|
+
return reply.status(400).send({ error: { code: "VALIDATION_ERROR", message: "quota must be an object" } });
|
|
1976
|
+
}
|
|
1977
|
+
for (const [key, val] of Object.entries(quota)) {
|
|
1978
|
+
if (!["maxConcurrency", "maxRequestsPerMinute", "maxRequestsPerDay"].includes(key)) {
|
|
1979
|
+
return reply.status(400).send({ error: { code: "VALIDATION_ERROR", message: `Unknown quota field: ${key}` } });
|
|
1980
|
+
}
|
|
1981
|
+
if (typeof val !== "number" || !Number.isInteger(val) || val <= 0) {
|
|
1982
|
+
return reply.status(400).send({ error: { code: "VALIDATION_ERROR", message: `${key} must be a positive integer` } });
|
|
1983
|
+
}
|
|
1984
|
+
}
|
|
1985
|
+
}
|
|
1986
|
+
const result = opts.onProviderUpdate(name, apiKey ?? "", model, baseUrl, quota);
|
|
1925
1987
|
if (!result) {
|
|
1926
1988
|
return reply.status(500).send({ error: "Failed to update provider configuration" });
|
|
1927
1989
|
}
|
|
@@ -2089,6 +2151,9 @@ import crypto11 from "crypto";
|
|
|
2089
2151
|
import { eq as eq11 } from "drizzle-orm";
|
|
2090
2152
|
var VALID_EVENTS = ["citation.lost", "citation.gained", "run.completed", "run.failed"];
|
|
2091
2153
|
async function notificationRoutes(app) {
|
|
2154
|
+
app.get("/notifications/events", async (_request, reply) => {
|
|
2155
|
+
return reply.send(VALID_EVENTS);
|
|
2156
|
+
});
|
|
2092
2157
|
app.post("/projects/:name/notifications", async (request, reply) => {
|
|
2093
2158
|
const project = resolveProjectSafe6(app, request.params.name, reply);
|
|
2094
2159
|
if (!project) return;
|
|
@@ -2592,7 +2657,7 @@ function normalizeResult2(raw) {
|
|
|
2592
2657
|
};
|
|
2593
2658
|
}
|
|
2594
2659
|
function buildPrompt2(keyword) {
|
|
2595
|
-
return
|
|
2660
|
+
return keyword;
|
|
2596
2661
|
}
|
|
2597
2662
|
function extractResponseText(response) {
|
|
2598
2663
|
try {
|
|
@@ -3967,16 +4032,17 @@ async function createServer(opts) {
|
|
|
3967
4032
|
app.log.error({ runId, err }, "Job runner failed");
|
|
3968
4033
|
});
|
|
3969
4034
|
},
|
|
3970
|
-
onProviderUpdate: (providerName, apiKey, model, baseUrl) => {
|
|
4035
|
+
onProviderUpdate: (providerName, apiKey, model, baseUrl, incomingQuota) => {
|
|
3971
4036
|
const name = providerName;
|
|
3972
4037
|
if (!(name in adapterMap)) return null;
|
|
3973
4038
|
if (!opts.config.providers) opts.config.providers = {};
|
|
3974
4039
|
const existing = opts.config.providers[name];
|
|
4040
|
+
const mergedQuota = incomingQuota ? { ...existing?.quota ?? DEFAULT_QUOTA, ...incomingQuota } : existing?.quota;
|
|
3975
4041
|
opts.config.providers[name] = {
|
|
3976
4042
|
apiKey: apiKey || existing?.apiKey,
|
|
3977
4043
|
baseUrl: baseUrl || existing?.baseUrl,
|
|
3978
4044
|
model: model || existing?.model,
|
|
3979
|
-
quota:
|
|
4045
|
+
quota: mergedQuota
|
|
3980
4046
|
};
|
|
3981
4047
|
try {
|
|
3982
4048
|
saveConfig(opts.config);
|
|
@@ -4138,6 +4204,7 @@ function parseKeywordResponse(raw, count) {
|
|
|
4138
4204
|
|
|
4139
4205
|
export {
|
|
4140
4206
|
providerQuotaPolicySchema,
|
|
4207
|
+
notificationEventSchema,
|
|
4141
4208
|
apiKeys,
|
|
4142
4209
|
createClient,
|
|
4143
4210
|
migrate,
|