@konneal/engine 0.2.130 → 0.2.131

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.
@@ -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
  })[];
@@ -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;
@@ -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,
@@ -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.130",
30
+ "version": "0.2.131",
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",