@konneal/engine 0.2.130 → 0.2.132
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/{ask-5D2TYRXH.js → ask-XAJDCNFU.js} +2 -2
- package/dist/{chunk-A4A26BCV.js → chunk-26VW4ZXU.js} +10 -1
- package/dist/{chunk-AIL7MJS3.js → chunk-DNDQQYDT.js} +1 -1
- package/dist/openapi-surface.gen.d.ts +1 -1
- package/dist/openapi-types.d.ts +76 -0
- package/dist/{search-6LP755Q7.js → search-544LVPGG.js} +1 -1
- package/dist/worker_public/src/index.js +26 -3
- package/dist/worker_public/src/refusal.js +1 -1
- package/package.json +1 -1
- package/workers/worker_public/openapi.yaml +23 -0
- package/workers/worker_public/src/index.ts +16 -0
- package/workers/worker_public/src/openapi-surface.gen.ts +12 -0
- package/workers/worker_public/src/refusal.ts +9 -0
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import {
|
|
2
2
|
handleAsk
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-DNDQQYDT.js";
|
|
4
4
|
import "./chunk-J6LBR6GI.js";
|
|
5
5
|
import "./chunk-7AXXR7GD.js";
|
|
6
6
|
import "./chunk-TH5XGPD5.js";
|
|
7
7
|
import "./chunk-W7J5SFXJ.js";
|
|
8
|
-
import "./chunk-
|
|
8
|
+
import "./chunk-26VW4ZXU.js";
|
|
9
9
|
import "./chunk-4NXH5ZI6.js";
|
|
10
10
|
import "./chunk-VT7DR6NQ.js";
|
|
11
11
|
import "./chunk-GBGRHXRU.js";
|
|
@@ -24,7 +24,16 @@ function refusalPatterns(publisher) {
|
|
|
24
24
|
// verb is the guard, a scope DISCUSSION inside a real answer
|
|
25
25
|
// ("this exemption is outside the scope of R 60") never matches
|
|
26
26
|
/\bI don[’']?t have (?:any )?information on [^.]{0,80}(?:that[’']?s|—)?\s*(?:general|common) knowledge\b/i,
|
|
27
|
-
/\b(?:that[’']?s|this is) (?:just )?(?:general|common) knowledge[^.]{0,80}(?:outside|beyond|not covered)\b/i
|
|
27
|
+
/\b(?:that[’']?s|this is) (?:just )?(?:general|common) knowledge[^.]{0,80}(?:outside|beyond|not covered)\b/i,
|
|
28
|
+
// the redirect-only openers (2026-10-11 smoke): the model swaps the
|
|
29
|
+
// pinned sentence for a scope OFFER — "I'm happy to help with
|
|
30
|
+
// questions about OIML … instead." / "I can answer questions about
|
|
31
|
+
// OIML … — such as OIML B 20:2024 …". Anchored at the answer's
|
|
32
|
+
// start (a real answer never OPENS with the redirect — the
|
|
33
|
+
// redirect TAIL after content survives untouched), the publisher
|
|
34
|
+
// token profile-driven.
|
|
35
|
+
new RegExp(`^\\s*I(?:['\u2019]m| am) happy to help with questions about ${publisher}\\b[^\\n]{0,220}?\\binstead\\b`, "i"),
|
|
36
|
+
new RegExp(`^\\s*I can (?:answer|help with) questions about ${publisher}\\b[^\\n]{0,220}?\\bpublications\\b`, "i")
|
|
28
37
|
],
|
|
29
38
|
// the misplaced-pin wall's subset: every pattern here carries a
|
|
30
39
|
// first-person refusal verb ("I don't have information", "I can't
|
|
@@ -3,7 +3,7 @@ export interface OpenApiRoute {
|
|
|
3
3
|
pattern: string;
|
|
4
4
|
operationId: string;
|
|
5
5
|
}
|
|
6
|
-
export type OpenApiOperationId = "askAnonymous" | "askKeyed" | "search" | "searchKeyed" | "verify" | "verifyKeyed" | "research" | "researchKeyed" | "mcp" | "datasets" | "keyUsage" | "health" | "listConversations" | "createConversation" | "getConversation" | "renameConversation" | "deleteConversation" | "appendMessage" | "shareConversation" | "getShared" | "uploadAttachment" | "listAttachments" | "getAttachment" | "deleteAttachment" | "listMemories" | "createMemory" | "deleteMemory" | "listProjects" | "createProject" | "deleteProject" | "listProjectFiles" | "attachProjectFile" | "detachProjectFile" | "laneQuery" | "laneKeyed" | "feedback" | "adminEnrich" | "adminEnrichAlias" | "adminSection" | "adminFamilySummary" | "adminSectionAlias" | "adminFamilySummaryAlias" | "adminVectors" | "adminCaption" | "adminJudge" | "adminJudgeAlias" | "adminRevokeKey" | "authMe" | "authLogin" | "authCallback" | "authLogout" | "authLogoutLink" | "adminStats" | "adminListKeys" | "adminCreateKey";
|
|
6
|
+
export type OpenApiOperationId = "credits" | "creditsAlias" | "askAnonymous" | "askKeyed" | "search" | "searchKeyed" | "verify" | "verifyKeyed" | "research" | "researchKeyed" | "mcp" | "datasets" | "keyUsage" | "health" | "listConversations" | "createConversation" | "getConversation" | "renameConversation" | "deleteConversation" | "appendMessage" | "shareConversation" | "getShared" | "uploadAttachment" | "listAttachments" | "getAttachment" | "deleteAttachment" | "listMemories" | "createMemory" | "deleteMemory" | "listProjects" | "createProject" | "deleteProject" | "listProjectFiles" | "attachProjectFile" | "detachProjectFile" | "laneQuery" | "laneKeyed" | "feedback" | "adminEnrich" | "adminEnrichAlias" | "adminSection" | "adminFamilySummary" | "adminSectionAlias" | "adminFamilySummaryAlias" | "adminVectors" | "adminCaption" | "adminJudge" | "adminJudgeAlias" | "adminRevokeKey" | "authMe" | "authLogin" | "authCallback" | "authLogout" | "authLogoutLink" | "adminStats" | "adminListKeys" | "adminCreateKey";
|
|
7
7
|
export declare const OPENAPI_SURFACE: readonly (Omit<OpenApiRoute, "operationId"> & {
|
|
8
8
|
operationId: OpenApiOperationId;
|
|
9
9
|
})[];
|
package/dist/openapi-types.d.ts
CHANGED
|
@@ -6,6 +6,46 @@
|
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
8
|
export interface paths {
|
|
9
|
+
"/api/credits": {
|
|
10
|
+
parameters: {
|
|
11
|
+
query?: never;
|
|
12
|
+
header?: never;
|
|
13
|
+
path?: never;
|
|
14
|
+
cookie?: never;
|
|
15
|
+
};
|
|
16
|
+
/**
|
|
17
|
+
* The caller's daily credit balance
|
|
18
|
+
* @description Returns the credits the caller has left today — resolved by the same tiering as ask (anonymous by IP, member by session, key by its owner member's shared cap). 1 credit ≈ 1000 tokens of consumption; the UI's meter reads this.
|
|
19
|
+
*/
|
|
20
|
+
get: operations["credits"];
|
|
21
|
+
put?: never;
|
|
22
|
+
post?: never;
|
|
23
|
+
delete?: never;
|
|
24
|
+
options?: never;
|
|
25
|
+
head?: never;
|
|
26
|
+
patch?: never;
|
|
27
|
+
trace?: never;
|
|
28
|
+
};
|
|
29
|
+
"/v1/credits": {
|
|
30
|
+
parameters: {
|
|
31
|
+
query?: never;
|
|
32
|
+
header?: never;
|
|
33
|
+
path?: never;
|
|
34
|
+
cookie?: never;
|
|
35
|
+
};
|
|
36
|
+
/**
|
|
37
|
+
* The caller's daily credit balance (the authenticated path)
|
|
38
|
+
* @description The same balance, authenticated by session or key.
|
|
39
|
+
*/
|
|
40
|
+
get: operations["creditsAlias"];
|
|
41
|
+
put?: never;
|
|
42
|
+
post?: never;
|
|
43
|
+
delete?: never;
|
|
44
|
+
options?: never;
|
|
45
|
+
head?: never;
|
|
46
|
+
patch?: never;
|
|
47
|
+
trace?: never;
|
|
48
|
+
};
|
|
9
49
|
"/api/ask": {
|
|
10
50
|
parameters: {
|
|
11
51
|
query?: never;
|
|
@@ -998,6 +1038,42 @@ export interface components {
|
|
|
998
1038
|
}
|
|
999
1039
|
export type $defs = Record<string, never>;
|
|
1000
1040
|
export interface operations {
|
|
1041
|
+
credits: {
|
|
1042
|
+
parameters: {
|
|
1043
|
+
query?: never;
|
|
1044
|
+
header?: never;
|
|
1045
|
+
path?: never;
|
|
1046
|
+
cookie?: never;
|
|
1047
|
+
};
|
|
1048
|
+
requestBody?: never;
|
|
1049
|
+
responses: {
|
|
1050
|
+
/** @description The balance. */
|
|
1051
|
+
200: {
|
|
1052
|
+
headers: {
|
|
1053
|
+
[name: string]: unknown;
|
|
1054
|
+
};
|
|
1055
|
+
content?: never;
|
|
1056
|
+
};
|
|
1057
|
+
};
|
|
1058
|
+
};
|
|
1059
|
+
creditsAlias: {
|
|
1060
|
+
parameters: {
|
|
1061
|
+
query?: never;
|
|
1062
|
+
header?: never;
|
|
1063
|
+
path?: never;
|
|
1064
|
+
cookie?: never;
|
|
1065
|
+
};
|
|
1066
|
+
requestBody?: never;
|
|
1067
|
+
responses: {
|
|
1068
|
+
/** @description The balance. */
|
|
1069
|
+
200: {
|
|
1070
|
+
headers: {
|
|
1071
|
+
[name: string]: unknown;
|
|
1072
|
+
};
|
|
1073
|
+
content?: never;
|
|
1074
|
+
};
|
|
1075
|
+
};
|
|
1076
|
+
};
|
|
1001
1077
|
askAnonymous: {
|
|
1002
1078
|
parameters: {
|
|
1003
1079
|
query?: never;
|
|
@@ -4,7 +4,7 @@ import {
|
|
|
4
4
|
handleMemories,
|
|
5
5
|
scoreFaithfulness,
|
|
6
6
|
scoreJudge
|
|
7
|
-
} from "../../chunk-
|
|
7
|
+
} from "../../chunk-DNDQQYDT.js";
|
|
8
8
|
import {
|
|
9
9
|
TOOLS_REGISTRY,
|
|
10
10
|
bindModelNode,
|
|
@@ -16,6 +16,8 @@ import {
|
|
|
16
16
|
import {
|
|
17
17
|
buildMessages,
|
|
18
18
|
citations,
|
|
19
|
+
clientIp,
|
|
20
|
+
creditBudget,
|
|
19
21
|
editionNote,
|
|
20
22
|
fill,
|
|
21
23
|
ftsMatchQuery,
|
|
@@ -52,7 +54,7 @@ import {
|
|
|
52
54
|
} from "../../chunk-W7J5SFXJ.js";
|
|
53
55
|
import {
|
|
54
56
|
canonicalRefusal
|
|
55
|
-
} from "../../chunk-
|
|
57
|
+
} from "../../chunk-26VW4ZXU.js";
|
|
56
58
|
import {
|
|
57
59
|
entitlementScope,
|
|
58
60
|
standardKeysFrom
|
|
@@ -1050,7 +1052,7 @@ async function callToolOnce(env, ctx, _req, tier, key, name, args, t0) {
|
|
|
1050
1052
|
const r = await runTool({ ...env, DB: env.DB }, { name, args }, "mcp");
|
|
1051
1053
|
payload = r ? { tool: r.name, query: r.query, result: r.output } : { error: { message: `tool ${name} returned nothing for the given arguments` } };
|
|
1052
1054
|
} else {
|
|
1053
|
-
const res = name === "ask" ? await (await import("../../ask-
|
|
1055
|
+
const res = name === "ask" ? await (await import("../../ask-XAJDCNFU.js")).handleAsk(env, ctx, inner, tier, key) : await (await import("../../search-544LVPGG.js")).handleSearch(env, ctx, inner, tier, key);
|
|
1054
1056
|
payload = await res.json().catch(() => ({ error: { message: "tool transport failed", status: res.status } }));
|
|
1055
1057
|
}
|
|
1056
1058
|
telemetry(env, ctx, tier, `mcp:${name}`, null, !payload?.error, JSON.stringify(payload).length, await sha256Hex(`${name}:${JSON.stringify(args ?? {})}`), void 0, void 0, { durationMs: Date.now() - t0 });
|
|
@@ -1087,6 +1089,16 @@ function matchRoute(routes, method, path) {
|
|
|
1087
1089
|
|
|
1088
1090
|
// workers/worker_public/src/openapi-surface.gen.ts
|
|
1089
1091
|
var OPENAPI_SURFACE = [
|
|
1092
|
+
{
|
|
1093
|
+
"method": "GET",
|
|
1094
|
+
"pattern": "/api/credits",
|
|
1095
|
+
"operationId": "credits"
|
|
1096
|
+
},
|
|
1097
|
+
{
|
|
1098
|
+
"method": "GET",
|
|
1099
|
+
"pattern": "/v1/credits",
|
|
1100
|
+
"operationId": "creditsAlias"
|
|
1101
|
+
},
|
|
1090
1102
|
{
|
|
1091
1103
|
"method": "POST",
|
|
1092
1104
|
"pattern": "/api/ask",
|
|
@@ -1496,6 +1508,15 @@ async function mcpRoute(c) {
|
|
|
1496
1508
|
if (t instanceof Response) return t;
|
|
1497
1509
|
return withCors(await handleMcp(c.env, c.ctx, c.req, t.tier, t.key), corsHeaders(c.req));
|
|
1498
1510
|
}
|
|
1511
|
+
async function creditsRoute(c) {
|
|
1512
|
+
const t = await tierFor(c);
|
|
1513
|
+
if (t instanceof Response) return t;
|
|
1514
|
+
const key = t.key;
|
|
1515
|
+
const memberKey = t.tier === "key" ? key?.owner_sub ?? null : null;
|
|
1516
|
+
const bucketId = memberKey ? `sub:${memberKey}` : t.tier === "key" ? `key:${key.id}` : clientIp(c.req);
|
|
1517
|
+
const cb = await creditBudget(c.env, bucketId);
|
|
1518
|
+
return withCors(json({ credits: cb }), corsHeaders(c.req));
|
|
1519
|
+
}
|
|
1499
1520
|
async function askRoute(c) {
|
|
1500
1521
|
const t = await tierFor(c);
|
|
1501
1522
|
if (t instanceof Response) return t;
|
|
@@ -1785,6 +1806,8 @@ var INFRA_ROUTES = [
|
|
|
1785
1806
|
];
|
|
1786
1807
|
var OPENAPI_HANDLERS = {
|
|
1787
1808
|
askAnonymous: askRoute,
|
|
1809
|
+
credits: creditsRoute,
|
|
1810
|
+
creditsAlias: creditsRoute,
|
|
1788
1811
|
askKeyed: askRoute,
|
|
1789
1812
|
search: searchRoute,
|
|
1790
1813
|
searchKeyed: searchRoute,
|
package/package.json
CHANGED
|
@@ -27,7 +27,7 @@
|
|
|
27
27
|
"playwright": "^1.62.1",
|
|
28
28
|
"yaml": "^2.9.1"
|
|
29
29
|
},
|
|
30
|
-
"version": "0.2.
|
|
30
|
+
"version": "0.2.132",
|
|
31
31
|
"description": "The Konneal engine: the publisher-agnostic build pipeline and API plane for standards intelligence (retrieval, answer contract, verdicts, evaluation).",
|
|
32
32
|
"license": "BSD-3-Clause",
|
|
33
33
|
"type": "module",
|
|
@@ -58,6 +58,29 @@ tags:
|
|
|
58
58
|
the index-maintenance battery (enrichment, section units, vectors
|
|
59
59
|
and figure captions).
|
|
60
60
|
paths:
|
|
61
|
+
/api/credits:
|
|
62
|
+
get:
|
|
63
|
+
tags: [Service]
|
|
64
|
+
summary: The caller's daily credit balance
|
|
65
|
+
description: >-
|
|
66
|
+
Returns the credits the caller has left today — resolved by the
|
|
67
|
+
same tiering as ask (anonymous by IP, member by session, key by
|
|
68
|
+
its owner member's shared cap). 1 credit ≈ 1000 tokens of
|
|
69
|
+
consumption; the UI's meter reads this.
|
|
70
|
+
operationId: credits
|
|
71
|
+
responses:
|
|
72
|
+
'200':
|
|
73
|
+
description: The balance.
|
|
74
|
+
/v1/credits:
|
|
75
|
+
get:
|
|
76
|
+
tags: [Service]
|
|
77
|
+
summary: The caller's daily credit balance (the authenticated path)
|
|
78
|
+
description: The same balance, authenticated by session or key.
|
|
79
|
+
operationId: creditsAlias
|
|
80
|
+
security: [{ bearerAuth: [] }]
|
|
81
|
+
responses:
|
|
82
|
+
'200':
|
|
83
|
+
description: The balance.
|
|
61
84
|
/api/ask:
|
|
62
85
|
post:
|
|
63
86
|
tags: [Ask]
|
|
@@ -20,6 +20,7 @@ import type { Env } from "./env";
|
|
|
20
20
|
import { portModelRunner } from "./env.ts";
|
|
21
21
|
export type { Env };
|
|
22
22
|
import { json, err, corsHeaders, withCors, readJson, authenticate, type ApiKey } from "./lib/http";
|
|
23
|
+
import { creditBudget, clientIp } from "./quota";
|
|
23
24
|
|
|
24
25
|
import { handleSearch } from "./search";
|
|
25
26
|
import { handleEnrich, handleSectionUnit, handleCaption, handleVectors, handleJudge, handleCreateKey, handleListKeys, handleRevokeKey, handleKeyUsage, handleFamilySummary } from "./admin";
|
|
@@ -215,6 +216,19 @@ async function mcpRoute(c: RouteContext): Promise<Response> {
|
|
|
215
216
|
return withCors(await handleMcp(c.env, c.ctx, c.req, t.tier, t.key), corsHeaders(c.req));
|
|
216
217
|
}
|
|
217
218
|
|
|
219
|
+
/** The caller's daily credit balance (2026-10-11): the meter the UI
|
|
220
|
+
* shows — resolved by the same tiering as ask (anon by IP, member by
|
|
221
|
+
* session, key by its owner member's shared cap). */
|
|
222
|
+
async function creditsRoute(c: RouteContext): Promise<Response> {
|
|
223
|
+
const t = await tierFor(c);
|
|
224
|
+
if (t instanceof Response) return t;
|
|
225
|
+
const key = t.key;
|
|
226
|
+
const memberKey = t.tier === "key" ? key?.owner_sub ?? null : null;
|
|
227
|
+
const bucketId = memberKey ? `sub:${memberKey}` : t.tier === "key" ? `key:${key!.id}` : clientIp(c.req);
|
|
228
|
+
const cb = await creditBudget(c.env, bucketId);
|
|
229
|
+
return withCors(json({ credits: cb }), corsHeaders(c.req));
|
|
230
|
+
}
|
|
231
|
+
|
|
218
232
|
async function askRoute(c: RouteContext): Promise<Response> {
|
|
219
233
|
const t = await tierFor(c);
|
|
220
234
|
if (t instanceof Response) return t;
|
|
@@ -571,6 +585,8 @@ const INFRA_ROUTES: Route[] = [
|
|
|
571
585
|
|
|
572
586
|
const OPENAPI_HANDLERS: Record<OpenApiOperationId, RouteHandler> = {
|
|
573
587
|
askAnonymous: askRoute,
|
|
588
|
+
credits: creditsRoute,
|
|
589
|
+
creditsAlias: creditsRoute,
|
|
574
590
|
askKeyed: askRoute,
|
|
575
591
|
search: searchRoute,
|
|
576
592
|
searchKeyed: searchRoute,
|
|
@@ -7,6 +7,8 @@ export interface OpenApiRoute {
|
|
|
7
7
|
}
|
|
8
8
|
|
|
9
9
|
export type OpenApiOperationId =
|
|
10
|
+
| "credits"
|
|
11
|
+
| "creditsAlias"
|
|
10
12
|
| "askAnonymous"
|
|
11
13
|
| "askKeyed"
|
|
12
14
|
| "search"
|
|
@@ -64,6 +66,16 @@ export type OpenApiOperationId =
|
|
|
64
66
|
| "adminCreateKey"
|
|
65
67
|
|
|
66
68
|
export const OPENAPI_SURFACE: readonly (Omit<OpenApiRoute, "operationId"> & { operationId: OpenApiOperationId })[] = [
|
|
69
|
+
{
|
|
70
|
+
"method": "GET",
|
|
71
|
+
"pattern": "/api/credits",
|
|
72
|
+
"operationId": "credits"
|
|
73
|
+
},
|
|
74
|
+
{
|
|
75
|
+
"method": "GET",
|
|
76
|
+
"pattern": "/v1/credits",
|
|
77
|
+
"operationId": "creditsAlias"
|
|
78
|
+
},
|
|
67
79
|
{
|
|
68
80
|
"method": "POST",
|
|
69
81
|
"pattern": "/api/ask",
|
|
@@ -29,6 +29,15 @@ function refusalPatterns(publisher: string): { variant: RegExp; drift: RegExp[];
|
|
|
29
29
|
// ("this exemption is outside the scope of R 60") never matches
|
|
30
30
|
/\bI don[’']?t have (?:any )?information on [^.]{0,80}(?:that[’']?s|—)?\s*(?:general|common) knowledge\b/i,
|
|
31
31
|
/\b(?:that[’']?s|this is) (?:just )?(?:general|common) knowledge[^.]{0,80}(?:outside|beyond|not covered)\b/i,
|
|
32
|
+
// the redirect-only openers (2026-10-11 smoke): the model swaps the
|
|
33
|
+
// pinned sentence for a scope OFFER — "I'm happy to help with
|
|
34
|
+
// questions about OIML … instead." / "I can answer questions about
|
|
35
|
+
// OIML … — such as OIML B 20:2024 …". Anchored at the answer's
|
|
36
|
+
// start (a real answer never OPENS with the redirect — the
|
|
37
|
+
// redirect TAIL after content survives untouched), the publisher
|
|
38
|
+
// token profile-driven.
|
|
39
|
+
new RegExp(`^\\s*I(?:['’]m| am) happy to help with questions about ${publisher}\\b[^\\n]{0,220}?\\binstead\\b`, "i"),
|
|
40
|
+
new RegExp(`^\\s*I can (?:answer|help with) questions about ${publisher}\\b[^\\n]{0,220}?\\bpublications\\b`, "i"),
|
|
32
41
|
],
|
|
33
42
|
// the misplaced-pin wall's subset: every pattern here carries a
|
|
34
43
|
// first-person refusal verb ("I don't have information", "I can't
|