@kindgi/api 0.1.2 → 0.1.4-rc.0

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.
Files changed (250) hide show
  1. package/dist/agent-binding.d.ts +18 -4
  2. package/dist/agent-binding.d.ts.map +1 -1
  3. package/dist/agent-pins.d.ts +48 -0
  4. package/dist/agent-pins.d.ts.map +1 -0
  5. package/dist/agent-pins.js +102 -0
  6. package/dist/agent-pins.js.map +1 -0
  7. package/dist/app.d.ts +22 -0
  8. package/dist/app.d.ts.map +1 -1
  9. package/dist/app.js +22 -3
  10. package/dist/app.js.map +1 -1
  11. package/dist/block-binding.d.ts +132 -0
  12. package/dist/block-binding.d.ts.map +1 -0
  13. package/dist/block-binding.js +4 -0
  14. package/dist/block-binding.js.map +1 -0
  15. package/dist/block-pins.d.ts +22 -0
  16. package/dist/block-pins.d.ts.map +1 -0
  17. package/dist/block-pins.js +112 -0
  18. package/dist/block-pins.js.map +1 -0
  19. package/dist/cost-binding.d.ts +100 -5
  20. package/dist/cost-binding.d.ts.map +1 -1
  21. package/dist/cost-binding.js +10 -0
  22. package/dist/cost-binding.js.map +1 -1
  23. package/dist/deploy-versions.d.ts +58 -0
  24. package/dist/deploy-versions.d.ts.map +1 -0
  25. package/dist/deploy-versions.js +91 -0
  26. package/dist/deploy-versions.js.map +1 -0
  27. package/dist/deployment-binding.d.ts +24 -3
  28. package/dist/deployment-binding.d.ts.map +1 -1
  29. package/dist/derive-agent-version.d.ts +69 -0
  30. package/dist/derive-agent-version.d.ts.map +1 -0
  31. package/dist/derive-agent-version.js +139 -0
  32. package/dist/derive-agent-version.js.map +1 -0
  33. package/dist/errors.d.ts.map +1 -1
  34. package/dist/errors.js +17 -0
  35. package/dist/errors.js.map +1 -1
  36. package/dist/eval-case-binding.d.ts +65 -0
  37. package/dist/eval-case-binding.d.ts.map +1 -0
  38. package/dist/eval-case-binding.js +4 -0
  39. package/dist/eval-case-binding.js.map +1 -0
  40. package/dist/eval-run-binding.d.ts +30 -0
  41. package/dist/eval-run-binding.d.ts.map +1 -1
  42. package/dist/eval-run-dispatcher.d.ts +38 -3
  43. package/dist/eval-run-dispatcher.d.ts.map +1 -1
  44. package/dist/eval-run-dispatcher.js +21 -15
  45. package/dist/eval-run-dispatcher.js.map +1 -1
  46. package/dist/eval-suite-binding.d.ts +1 -1
  47. package/dist/eval-suite-binding.d.ts.map +1 -1
  48. package/dist/eval-suite-binding.js +2 -0
  49. package/dist/eval-suite-binding.js.map +1 -1
  50. package/dist/flow-binding.d.ts +10 -4
  51. package/dist/flow-binding.d.ts.map +1 -1
  52. package/dist/flow-pins.d.ts +36 -0
  53. package/dist/flow-pins.d.ts.map +1 -0
  54. package/dist/flow-pins.js +81 -0
  55. package/dist/flow-pins.js.map +1 -0
  56. package/dist/hitl-binding.d.ts +20 -5
  57. package/dist/hitl-binding.d.ts.map +1 -1
  58. package/dist/index.d.ts +19 -8
  59. package/dist/index.d.ts.map +1 -1
  60. package/dist/index.js +8 -2
  61. package/dist/index.js.map +1 -1
  62. package/dist/judged-dispatcher.d.ts +134 -0
  63. package/dist/judged-dispatcher.d.ts.map +1 -0
  64. package/dist/judged-dispatcher.js +297 -0
  65. package/dist/judged-dispatcher.js.map +1 -0
  66. package/dist/judged-items.d.ts +86 -0
  67. package/dist/judged-items.d.ts.map +1 -0
  68. package/dist/judged-items.js +184 -0
  69. package/dist/judged-items.js.map +1 -0
  70. package/dist/judgment-binding.d.ts +316 -0
  71. package/dist/judgment-binding.d.ts.map +1 -0
  72. package/dist/judgment-binding.js +19 -0
  73. package/dist/judgment-binding.js.map +1 -0
  74. package/dist/middleware/auth.d.ts +3 -2
  75. package/dist/middleware/auth.d.ts.map +1 -1
  76. package/dist/middleware/auth.js.map +1 -1
  77. package/dist/middleware/idempotency.d.ts +5 -1
  78. package/dist/middleware/idempotency.d.ts.map +1 -1
  79. package/dist/middleware/idempotency.js +8 -1
  80. package/dist/middleware/idempotency.js.map +1 -1
  81. package/dist/openapi/generate.d.ts.map +1 -1
  82. package/dist/openapi/generate.js +4 -1
  83. package/dist/openapi/generate.js.map +1 -1
  84. package/dist/openapi/operations.d.ts.map +1 -1
  85. package/dist/openapi/operations.js +543 -24
  86. package/dist/openapi/operations.js.map +1 -1
  87. package/dist/openapi/schemas.d.ts +58 -0
  88. package/dist/openapi/schemas.d.ts.map +1 -1
  89. package/dist/openapi/schemas.js +1058 -27
  90. package/dist/openapi/schemas.js.map +1 -1
  91. package/dist/provenance-binding.d.ts +27 -1
  92. package/dist/provenance-binding.d.ts.map +1 -1
  93. package/dist/provenance-binding.js.map +1 -1
  94. package/dist/provider-binding.d.ts +12 -7
  95. package/dist/provider-binding.d.ts.map +1 -1
  96. package/dist/reviewer-binding.d.ts +10 -2
  97. package/dist/reviewer-binding.d.ts.map +1 -1
  98. package/dist/reviewer-role.d.ts +13 -0
  99. package/dist/reviewer-role.d.ts.map +1 -0
  100. package/dist/reviewer-role.js +27 -0
  101. package/dist/reviewer-role.js.map +1 -0
  102. package/dist/routes/agents.d.ts +9 -1
  103. package/dist/routes/agents.d.ts.map +1 -1
  104. package/dist/routes/agents.js +175 -11
  105. package/dist/routes/agents.js.map +1 -1
  106. package/dist/routes/approvals.d.ts +5 -4
  107. package/dist/routes/approvals.d.ts.map +1 -1
  108. package/dist/routes/approvals.js +52 -16
  109. package/dist/routes/approvals.js.map +1 -1
  110. package/dist/routes/blocks.d.ts +19 -0
  111. package/dist/routes/blocks.d.ts.map +1 -0
  112. package/dist/routes/blocks.js +281 -0
  113. package/dist/routes/blocks.js.map +1 -0
  114. package/dist/routes/conversations.d.ts +7 -1
  115. package/dist/routes/conversations.d.ts.map +1 -1
  116. package/dist/routes/conversations.js +41 -1
  117. package/dist/routes/conversations.js.map +1 -1
  118. package/dist/routes/cost.d.ts.map +1 -1
  119. package/dist/routes/cost.js +142 -11
  120. package/dist/routes/cost.js.map +1 -1
  121. package/dist/routes/deployments.d.ts +3 -0
  122. package/dist/routes/deployments.d.ts.map +1 -1
  123. package/dist/routes/deployments.js +208 -55
  124. package/dist/routes/deployments.js.map +1 -1
  125. package/dist/routes/eval-comparison.d.ts +14 -0
  126. package/dist/routes/eval-comparison.d.ts.map +1 -0
  127. package/dist/routes/eval-comparison.js +87 -0
  128. package/dist/routes/eval-comparison.js.map +1 -0
  129. package/dist/routes/eval-runs.d.ts.map +1 -1
  130. package/dist/routes/eval-runs.js +8 -0
  131. package/dist/routes/eval-runs.js.map +1 -1
  132. package/dist/routes/flows.d.ts +13 -1
  133. package/dist/routes/flows.d.ts.map +1 -1
  134. package/dist/routes/flows.js +44 -3
  135. package/dist/routes/flows.js.map +1 -1
  136. package/dist/routes/hierarchy-errors.d.ts +35 -0
  137. package/dist/routes/hierarchy-errors.d.ts.map +1 -0
  138. package/dist/routes/hierarchy-errors.js +39 -0
  139. package/dist/routes/hierarchy-errors.js.map +1 -0
  140. package/dist/routes/identity.d.ts +7 -0
  141. package/dist/routes/identity.d.ts.map +1 -1
  142. package/dist/routes/identity.js +3 -2
  143. package/dist/routes/identity.js.map +1 -1
  144. package/dist/routes/judged-suites.d.ts +20 -0
  145. package/dist/routes/judged-suites.d.ts.map +1 -0
  146. package/dist/routes/judged-suites.js +272 -0
  147. package/dist/routes/judged-suites.js.map +1 -0
  148. package/dist/routes/judgment-context.d.ts +22 -0
  149. package/dist/routes/judgment-context.d.ts.map +1 -0
  150. package/dist/routes/judgment-context.js +88 -0
  151. package/dist/routes/judgment-context.js.map +1 -0
  152. package/dist/routes/judgment-flow-context.d.ts +32 -0
  153. package/dist/routes/judgment-flow-context.d.ts.map +1 -0
  154. package/dist/routes/judgment-flow-context.js +195 -0
  155. package/dist/routes/judgment-flow-context.js.map +1 -0
  156. package/dist/routes/judgments.d.ts +41 -0
  157. package/dist/routes/judgments.d.ts.map +1 -0
  158. package/dist/routes/judgments.js +566 -0
  159. package/dist/routes/judgments.js.map +1 -0
  160. package/dist/routes/orgs.d.ts +5 -2
  161. package/dist/routes/orgs.d.ts.map +1 -1
  162. package/dist/routes/orgs.js +38 -22
  163. package/dist/routes/orgs.js.map +1 -1
  164. package/dist/routes/policies.d.ts.map +1 -1
  165. package/dist/routes/policies.js +12 -1
  166. package/dist/routes/policies.js.map +1 -1
  167. package/dist/routes/projects.d.ts +10 -2
  168. package/dist/routes/projects.d.ts.map +1 -1
  169. package/dist/routes/projects.js +87 -79
  170. package/dist/routes/projects.js.map +1 -1
  171. package/dist/routes/provenance.d.ts.map +1 -1
  172. package/dist/routes/provenance.js +32 -1
  173. package/dist/routes/provenance.js.map +1 -1
  174. package/dist/routes/providers.d.ts.map +1 -1
  175. package/dist/routes/providers.js +6 -1
  176. package/dist/routes/providers.js.map +1 -1
  177. package/dist/routes/runs.d.ts +0 -7
  178. package/dist/routes/runs.d.ts.map +1 -1
  179. package/dist/routes/runs.js +65 -20
  180. package/dist/routes/runs.js.map +1 -1
  181. package/dist/routes/scope-params.d.ts +16 -1
  182. package/dist/routes/scope-params.d.ts.map +1 -1
  183. package/dist/routes/scope-params.js +28 -0
  184. package/dist/routes/scope-params.js.map +1 -1
  185. package/dist/routes/teams.d.ts +6 -2
  186. package/dist/routes/teams.d.ts.map +1 -1
  187. package/dist/routes/teams.js +77 -73
  188. package/dist/routes/teams.js.map +1 -1
  189. package/dist/types.d.ts +4 -3
  190. package/dist/types.d.ts.map +1 -1
  191. package/dist/webhook-endpoint-binding.d.ts +11 -0
  192. package/dist/webhook-endpoint-binding.d.ts.map +1 -1
  193. package/dist/webhook-endpoint-binding.js.map +1 -1
  194. package/openapi.json +13316 -9299
  195. package/package.json +21 -21
  196. package/src/agent-binding.ts +19 -4
  197. package/src/agent-pins.ts +147 -0
  198. package/src/app.ts +76 -3
  199. package/src/block-binding.ts +137 -0
  200. package/src/block-pins.ts +148 -0
  201. package/src/cost-binding.ts +116 -5
  202. package/src/deploy-versions.ts +157 -0
  203. package/src/deployment-binding.ts +27 -3
  204. package/src/derive-agent-version.ts +206 -0
  205. package/src/errors.ts +17 -0
  206. package/src/eval-case-binding.ts +71 -0
  207. package/src/eval-run-binding.ts +33 -0
  208. package/src/eval-run-dispatcher.ts +57 -16
  209. package/src/eval-suite-binding.ts +2 -0
  210. package/src/flow-binding.ts +11 -4
  211. package/src/flow-pins.ts +113 -0
  212. package/src/hitl-binding.ts +20 -4
  213. package/src/index.ts +88 -2
  214. package/src/judged-dispatcher.ts +507 -0
  215. package/src/judged-items.ts +263 -0
  216. package/src/judgment-binding.ts +349 -0
  217. package/src/middleware/auth.ts +3 -2
  218. package/src/middleware/idempotency.ts +7 -1
  219. package/src/openapi/generate.ts +7 -1
  220. package/src/openapi/operations.ts +615 -24
  221. package/src/openapi/schemas.ts +1157 -22
  222. package/src/provenance-binding.ts +42 -1
  223. package/src/provider-binding.ts +12 -7
  224. package/src/reviewer-binding.ts +10 -2
  225. package/src/reviewer-role.ts +35 -0
  226. package/src/routes/agents.ts +243 -19
  227. package/src/routes/approvals.ts +70 -19
  228. package/src/routes/blocks.ts +362 -0
  229. package/src/routes/conversations.ts +57 -1
  230. package/src/routes/cost.ts +159 -21
  231. package/src/routes/deployments.ts +266 -56
  232. package/src/routes/eval-comparison.ts +101 -0
  233. package/src/routes/eval-runs.ts +11 -0
  234. package/src/routes/flows.ts +63 -5
  235. package/src/routes/hierarchy-errors.ts +51 -0
  236. package/src/routes/identity.ts +10 -2
  237. package/src/routes/judged-suites.ts +363 -0
  238. package/src/routes/judgment-context.ts +128 -0
  239. package/src/routes/judgment-flow-context.ts +245 -0
  240. package/src/routes/judgments.ts +743 -0
  241. package/src/routes/orgs.ts +44 -27
  242. package/src/routes/policies.ts +19 -0
  243. package/src/routes/projects.ts +106 -95
  244. package/src/routes/provenance.ts +48 -1
  245. package/src/routes/providers.ts +5 -0
  246. package/src/routes/runs.ts +79 -22
  247. package/src/routes/scope-params.ts +35 -1
  248. package/src/routes/teams.ts +96 -90
  249. package/src/types.ts +4 -3
  250. package/src/webhook-endpoint-binding.ts +11 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kindgi/api",
3
- "version": "0.1.2",
3
+ "version": "0.1.4-rc.0",
4
4
  "description": "REST + SSE HTTP surface for Kindgi™. createApp assembles a Hono app serving the /v1/* REST API (bearer or session-token auth; OpenAPI 3.1 document at /v1/openapi.json) and an optional S3-compatible /s3/* surface (SigV4), over caller-plugged bindings for the runtime (runs, agents, flows, HITL, supervisor) and for storage. Route conventions: docs/API-ROUTE-CONVENTIONS.md.",
5
5
  "license": "Apache-2.0",
6
6
  "repository": {
@@ -32,30 +32,30 @@
32
32
  "openapi.json"
33
33
  ],
34
34
  "dependencies": {
35
- "@kindgi/agents": "0.1.2",
36
- "@kindgi/audit-events": "0.1.2",
37
- "@kindgi/compliance": "0.1.2",
38
- "@kindgi/authz": "0.1.2",
39
- "@kindgi/blob-binding": "0.1.2",
40
- "@kindgi/capabilities": "0.1.2",
41
- "@kindgi/crypto": "0.1.2",
42
- "@kindgi/flow": "0.1.2",
43
- "@kindgi/guardrails": "0.1.2",
44
- "@kindgi/memory": "0.1.2",
45
- "@kindgi/platform": "0.1.2",
46
- "@kindgi/provenance": "0.1.2",
47
- "@kindgi/runtime": "0.1.2",
48
- "@kindgi/policy-contract": "0.1.2",
49
- "@kindgi/schema": "0.1.2",
50
- "@kindgi/tools": "0.1.2",
51
- "@kindgi/types": "0.1.2",
35
+ "@kindgi/agents": "0.1.4-rc.0",
36
+ "@kindgi/audit-events": "0.1.4-rc.0",
37
+ "@kindgi/compliance": "0.1.4-rc.0",
38
+ "@kindgi/authz": "0.1.4-rc.0",
39
+ "@kindgi/blob-binding": "0.1.4-rc.0",
40
+ "@kindgi/capabilities": "0.1.4-rc.0",
41
+ "@kindgi/crypto": "0.1.4-rc.0",
42
+ "@kindgi/flow": "0.1.4-rc.0",
43
+ "@kindgi/guardrails": "0.1.4-rc.0",
44
+ "@kindgi/memory": "0.1.4-rc.0",
45
+ "@kindgi/platform": "0.1.4-rc.0",
46
+ "@kindgi/provenance": "0.1.4-rc.0",
47
+ "@kindgi/runtime": "0.1.4-rc.0",
48
+ "@kindgi/policy-contract": "0.1.4-rc.0",
49
+ "@kindgi/schema": "0.1.4-rc.0",
50
+ "@kindgi/tools": "0.1.4-rc.0",
51
+ "@kindgi/types": "0.1.4-rc.0",
52
52
  "@scalar/hono-api-reference": "^0.12.2",
53
53
  "hono": "^4.6.14"
54
54
  },
55
55
  "devDependencies": {
56
- "@kindgi/audit-events-inmemory": "0.1.2",
57
- "@kindgi/specs": "0.1.2",
58
- "@kindgi/testing": "0.1.2",
56
+ "@kindgi/audit-events-inmemory": "0.1.4-rc.0",
57
+ "@kindgi/specs": "0.1.4-rc.0",
58
+ "@kindgi/testing": "0.1.4-rc.0",
59
59
  "@types/aws4": "^1.11.6",
60
60
  "@types/node": "^22.10.5",
61
61
  "aws4": "^1.13.2",
@@ -36,11 +36,13 @@ export interface AgentRegistryBinding {
36
36
  get(input: AgentGetInput): Promise<Agent | null>;
37
37
  /**
38
38
  * Specific `(agentId, version)` lookup, or `null` if unknown.
39
- * Returns tombstoned versions too (unlike `list` / `get` which
40
- * filter them) — the specific-version lookup is used by provenance
41
- * paths that need to resolve historical run references.
39
+ * Returns unregistered (tombstoned) versions too, unlike `list` /
40
+ * `get` which filter them, with `unregisteredAt` set. Unregister stops
41
+ * a version being *chosen*, not the pins that hold it: a resumed run,
42
+ * provenance, and a flow version that pins it read it, while a new run
43
+ * that names it is refused.
42
44
  */
43
- getVersion(input: AgentGetVersionInput): Promise<Agent | null>;
45
+ getVersion(input: AgentGetVersionInput): Promise<AgentVersionRecord | null>;
44
46
  /**
45
47
  * Head-row existence check. Returns `true` iff the agent id has been
46
48
  * registered in the tenant (regardless of whether any versions are
@@ -88,6 +90,14 @@ export interface AgentRegistryBinding {
88
90
  reinstateVersion(input: AgentReinstateVersionInput): Promise<AgentReinstateVersionOutcome>;
89
91
  }
90
92
 
93
+ /** An agent version as `getVersion` reads it: `unregisteredAt` is set when it's unregistered. */
94
+ export type AgentVersionRecord = Agent & {
95
+ /** ISO-8601; present only on an unregistered version. */
96
+ readonly unregisteredAt?: string;
97
+ /** The project the version belongs to, when the store records it (a derived version is published there). */
98
+ readonly projectId?: ProjectId;
99
+ };
100
+
91
101
  export interface AgentListInput {
92
102
  readonly tenantId: TenantId;
93
103
  readonly limit: number;
@@ -149,6 +159,11 @@ export interface AgentPublishInput {
149
159
  * silently falls back to Default.
150
160
  */
151
161
  readonly projectId: ProjectId;
162
+ /**
163
+ * The version to store, as given. When the route pinned it, it
164
+ * carries `pins` and `pinsDigest` (the exact block versions its runs
165
+ * use); a binding stores and returns them with the rest.
166
+ */
152
167
  readonly agent: Agent;
153
168
  /**
154
169
  * REQUIRED. Called inside the binding's write transaction after the
@@ -0,0 +1,147 @@
1
+ // SPDX-License-Identifier: Apache-2.0
2
+ // Copyright (C) 2026 Kindgi Inc.
3
+
4
+ import { type Agent, type AgentId, type AgentPins, pinsDigest } from '@kindgi/agents';
5
+ import type { TupleEnqueueHook } from '@kindgi/authz';
6
+ import { pickVersion } from '@kindgi/tools';
7
+ import type { Cursor, ProjectId, TenantId, ToolId } from '@kindgi/types';
8
+
9
+ import type { AgentRegistryBinding } from './agent-binding.js';
10
+ import type { BlockRegistryBinding } from './block-binding.js';
11
+ import { resolveBlockPins } from './block-pins.js';
12
+ import { type DeployedVersionOutcome, deployVersion } from './deploy-versions.js';
13
+ import type { ToolRegistryBinding } from './tool-binding.js';
14
+
15
+ /** One block reference that matched no published version. */
16
+ export interface UnpinnableRef {
17
+ /** JSON pointer into the definition, e.g. `/tools/<i>/version`. */
18
+ readonly path: string;
19
+ readonly message: string;
20
+ }
21
+
22
+ export type AgentPinsOutcome =
23
+ | { readonly kind: 'ok'; readonly pins: AgentPins }
24
+ | { readonly kind: 'unpinnable'; readonly issues: readonly UnpinnableRef[] };
25
+
26
+ /** Page size for reading a tool's versions. */
27
+ const VERSIONS_PAGE = 200;
28
+
29
+ /**
30
+ * Resolve an agent's tool ranges to the exact versions a version of it
31
+ * runs (its `pins`), when the version is published.
32
+ *
33
+ * Each range is picked by `pickVersion` over the tool's active versions,
34
+ * the same versions and the same rule a run resolves against, so the pin
35
+ * is the version a run would have picked at that moment. A range that
36
+ * matches nothing (the tool isn't published, or no version is in range)
37
+ * makes the agent unpinnable: the caller refuses the publish, naming
38
+ * each such tool, rather than store a partly pinned version.
39
+ */
40
+ export async function resolveAgentPins(
41
+ tools: ToolRegistryBinding,
42
+ tenantId: TenantId,
43
+ agent: Agent,
44
+ blocks?: BlockRegistryBinding,
45
+ ): Promise<AgentPinsOutcome> {
46
+ const pinned: Record<string, string> = {};
47
+ const issues: UnpinnableRef[] = [];
48
+ const versionsOf = new Map<string, readonly string[]>();
49
+ for (const [i, ref] of agent.tools.entries()) {
50
+ let available = versionsOf.get(ref.id);
51
+ if (available === undefined) {
52
+ available = await activeToolVersions(tools, tenantId, ref.id as ToolId);
53
+ versionsOf.set(ref.id, available);
54
+ }
55
+ const pick = pickVersion(available, ref.version);
56
+ if (pick.kind === 'ok') {
57
+ pinned[ref.id] = pick.version;
58
+ continue;
59
+ }
60
+ issues.push({
61
+ path: `/tools/${i}/version`,
62
+ message:
63
+ available.length === 0
64
+ ? `tool "${ref.id}" has no published version; publish the tool first`
65
+ : `tool "${ref.id}" has no published version in "${ref.version}" (published: ${available.join(', ')}); publish one in range first, or change the range`,
66
+ });
67
+ }
68
+ // The data blocks it references, by the same rule (`resolveBlockPins`).
69
+ const blockPins = await resolveBlockPins(blocks, tenantId, agent);
70
+ issues.push(...blockPins.issues);
71
+ if (issues.length > 0) return { kind: 'unpinnable', issues };
72
+ return {
73
+ kind: 'ok',
74
+ pins: { tools: pinned, prompts: blockPins.prompts, settings: blockPins.settings },
75
+ };
76
+ }
77
+
78
+ /** Every active version of a tool, newest first; none when it isn't published. */
79
+ export async function activeToolVersions(
80
+ tools: ToolRegistryBinding,
81
+ tenantId: TenantId,
82
+ toolId: ToolId,
83
+ ): Promise<readonly string[]> {
84
+ const versions: string[] = [];
85
+ let cursor: Cursor | undefined;
86
+ do {
87
+ const page = await tools.listVersions({
88
+ tenantId,
89
+ toolId,
90
+ limit: VERSIONS_PAGE,
91
+ ...(cursor !== undefined && { cursor }),
92
+ });
93
+ for (const manifest of page.data) versions.push(manifest.version as unknown as string);
94
+ cursor = page.nextCursor;
95
+ } while (cursor !== undefined);
96
+ return versions;
97
+ }
98
+
99
+ export interface PublishDeployedAgentInput {
100
+ readonly agents: AgentRegistryBinding;
101
+ readonly tenantId: TenantId;
102
+ readonly projectId: ProjectId;
103
+ /** The agent as the pack defines it, with no pins. */
104
+ readonly agent: Agent;
105
+ readonly pins: AgentPins;
106
+ readonly enqueueTuples: TupleEnqueueHook;
107
+ }
108
+
109
+ /** Register a deployed agent with its pins, by the deploy rule (`deployVersion`). */
110
+ export async function publishDeployedAgent(
111
+ input: PublishDeployedAgentInput,
112
+ ): Promise<DeployedVersionOutcome> {
113
+ const { agents, tenantId, projectId, agent, pins, enqueueTuples } = input;
114
+ return deployVersion<Agent>({
115
+ label: `agent "${agent.id as unknown as string}"`,
116
+ definition: agent,
117
+ pins,
118
+ pinsDigest: pinsDigest(pins),
119
+ existing: await activeAgentVersions(agents, tenantId, agent.id),
120
+ publish: async (version) => {
121
+ const outcome = await agents.publish({ tenantId, projectId, agent: version, enqueueTuples });
122
+ if (outcome.kind === 'ok') return 'ok';
123
+ return outcome.kind === 'project-not-found' ? 'skipped' : 'taken';
124
+ },
125
+ });
126
+ }
127
+
128
+ /** Every active version of an agent. */
129
+ export async function activeAgentVersions(
130
+ agents: AgentRegistryBinding,
131
+ tenantId: TenantId,
132
+ agentId: AgentId,
133
+ ): Promise<readonly Agent[]> {
134
+ const versions: Agent[] = [];
135
+ let cursor: Cursor | undefined;
136
+ do {
137
+ const page = await agents.listVersions({
138
+ tenantId,
139
+ agentId,
140
+ limit: VERSIONS_PAGE,
141
+ ...(cursor !== undefined && { cursor }),
142
+ });
143
+ versions.push(...page.data);
144
+ cursor = page.nextCursor;
145
+ } while (cursor !== undefined);
146
+ return versions;
147
+ }
package/src/app.ts CHANGED
@@ -26,11 +26,13 @@ import type { MemoryQueryBinding } from '@kindgi/memory';
26
26
  import type { PolicyRegistryBinding } from '@kindgi/policy-contract';
27
27
  import type { AdapterRegistryBinding } from './adapter-binding.js';
28
28
  import type { AgentRegistryBinding } from './agent-binding.js';
29
+ import type { BlockRegistryBinding } from './block-binding.js';
29
30
  import type { CapabilityRegistryBinding } from './capability-binding.js';
30
31
  import type { CostBinding } from './cost-binding.js';
31
32
  import type { DeploymentBinding } from './deployment-binding.js';
32
33
  import type { EnvBinding } from './env-binding.js';
33
34
  import type { WireErrorBody } from './errors.js';
35
+ import type { EvalCaseStoreBinding } from './eval-case-binding.js';
34
36
  import type { EvalRunBinding } from './eval-run-binding.js';
35
37
  import type { EvalSuiteRegistryBinding } from './eval-suite-binding.js';
36
38
  import type { EventBusBinding } from './event-bus-binding.js';
@@ -45,6 +47,7 @@ import type {
45
47
  RefreshTokenFn,
46
48
  } from './identity-provider-binding.js';
47
49
  import type { ImageRegistryBinding } from './image-registry-binding.js';
50
+ import type { JudgmentRegistryBinding } from './judgment-binding.js';
48
51
  import type { MCPClientProbeBinding, MCPEndpointRegistryBinding } from './mcp-endpoint-binding.js';
49
52
  import type { MemoryBinding } from './memory-binding.js';
50
53
  import { type TokenResolver, bearerAuthMiddleware } from './middleware/auth.js';
@@ -79,6 +82,7 @@ import { approvalsRouter } from './routes/approvals.js';
79
82
  import { artifactsRouter } from './routes/artifacts.js';
80
83
  import { auditRouter } from './routes/audit.js';
81
84
  import { authRouters } from './routes/auth.js';
85
+ import { blocksRouter } from './routes/blocks.js';
82
86
  import { capabilitiesRouter } from './routes/capabilities.js';
83
87
  import { complianceRouter } from './routes/compliance.js';
84
88
  import { conversationsRouter } from './routes/conversations.js';
@@ -91,6 +95,8 @@ import { eventTriggersRouter } from './routes/event-triggers.js';
91
95
  import { flowsRouter } from './routes/flows.js';
92
96
  import { guardrailsRouter } from './routes/guardrails.js';
93
97
  import { identityRouter } from './routes/identity.js';
98
+ import { judgedSuitesRouter } from './routes/judged-suites.js';
99
+ import { judgeClassesRouter, judgmentsRouter } from './routes/judgments.js';
94
100
  import { mcpRouter } from './routes/mcp.js';
95
101
  import { memoryRouter } from './routes/memory.js';
96
102
  import { observationsRouter } from './routes/observations.js';
@@ -571,6 +577,12 @@ export interface CreateAppInput {
571
577
  * — new kinds require a spec + validator update in tandem.
572
578
  */
573
579
  readonly evalSuiteRegistry?: EvalSuiteRegistryBinding;
580
+ /**
581
+ * Data blocks (`/v1/blocks`): versioned prompts and settings that agent
582
+ * versions pin. Mounted when supplied. Authorized through each block's
583
+ * project; the binding writes no authorization tuples.
584
+ */
585
+ readonly blockRegistry?: BlockRegistryBinding;
574
586
  /**
575
587
  * Optional. When present alongside `evalSuiteRegistry`, mounts the
576
588
  * evaluation-run data-plane surface: `POST /v1/eval-suites/:suiteId/runs`
@@ -584,6 +596,19 @@ export interface CreateAppInput {
584
596
  * `422 dispatcher-not-registered`.
585
597
  */
586
598
  readonly evalRunBinding?: EvalRunBinding;
599
+ /**
600
+ * Optional. Mounts judgments, yes or no with an optional reason about
601
+ * one item of a run's output (`/v1/judgments`), and the judge classes
602
+ * they're recorded under, each with a weight (`/v1/judge-classes`).
603
+ * Caller-plugged: the API package doesn't own their storage.
604
+ */
605
+ readonly judgmentRegistry?: JudgmentRegistryBinding;
606
+ /**
607
+ * Optional. With `evalSuiteRegistry` and `judgmentRegistry`, mounts test
608
+ * sets built from judgments: `POST /v1/eval-suites/:suiteId/versions/from-judgments`
609
+ * and `GET /v1/eval-suites/:suiteId/versions/:version/cases`.
610
+ */
611
+ readonly evalCaseStore?: EvalCaseStoreBinding;
587
612
  /**
588
613
  * Optional. Push-based pub/sub binding used by SSE endpoints to
589
614
  * deliver run events without polling. When present, `GET
@@ -955,7 +980,10 @@ export function createApp(input: CreateAppInput): Hono<AppEnv> {
955
980
  authorizer,
956
981
  ),
957
982
  );
958
- v1.route('/conversations', conversationsRouter(input.conversationBinding, runBinding));
983
+ v1.route(
984
+ '/conversations',
985
+ conversationsRouter(input.conversationBinding, runBinding, input.projectBinding),
986
+ );
959
987
  if (publicRunTokenLimits !== undefined) {
960
988
  v1.route(
961
989
  '/tokens/public',
@@ -999,10 +1027,22 @@ export function createApp(input: CreateAppInput): Hono<AppEnv> {
999
1027
  v1.route('/observations', observationsRouter(input.supervisor));
1000
1028
  }
1001
1029
  if (input.agentRegistry !== undefined) {
1002
- v1.route('/agents', agentsRouter(input.agentRegistry, authorizer));
1030
+ v1.route(
1031
+ '/agents',
1032
+ agentsRouter(input.agentRegistry, authorizer, input.toolRegistry, input.blockRegistry),
1033
+ );
1003
1034
  }
1004
1035
  if (input.flowRegistry !== undefined) {
1005
- v1.route('/flows', flowsRouter(input.flowRegistry, authorizer));
1036
+ v1.route(
1037
+ '/flows',
1038
+ flowsRouter(
1039
+ input.flowRegistry,
1040
+ authorizer,
1041
+ input.toolRegistry !== undefined && input.agentRegistry !== undefined
1042
+ ? { tools: input.toolRegistry, agents: input.agentRegistry }
1043
+ : undefined,
1044
+ ),
1045
+ );
1006
1046
  }
1007
1047
  if (input.toolRegistry !== undefined) {
1008
1048
  v1.route('/tools', toolsRouter(input.toolRegistry, authorizer, input.onToolWrite));
@@ -1070,6 +1110,7 @@ export function createApp(input: CreateAppInput): Hono<AppEnv> {
1070
1110
  identityRouter({
1071
1111
  ...(input.identityDirectory !== undefined && { directory: input.identityDirectory }),
1072
1112
  ...(input.sessionStore !== undefined && { sessionStore: input.sessionStore }),
1113
+ ...(input.reviewerBinding !== undefined && { reviewerBinding: input.reviewerBinding }),
1073
1114
  }),
1074
1115
  );
1075
1116
  if (input.cost !== undefined) {
@@ -1096,6 +1137,37 @@ export function createApp(input: CreateAppInput): Hono<AppEnv> {
1096
1137
  if (input.evalSuiteRegistry !== undefined) {
1097
1138
  v1.route('/eval-suites', evalSuitesRouter(input.evalSuiteRegistry, authorizer));
1098
1139
  }
1140
+ if (input.blockRegistry !== undefined) {
1141
+ v1.route('/blocks', blocksRouter(input.blockRegistry, authorizer));
1142
+ }
1143
+ if (input.judgmentRegistry !== undefined) {
1144
+ v1.route(
1145
+ '/judgments',
1146
+ judgmentsRouter(
1147
+ input.judgmentRegistry,
1148
+ runBinding,
1149
+ authorizer,
1150
+ input.conversationBinding,
1151
+ input.flowRegistry,
1152
+ ),
1153
+ );
1154
+ v1.route('/judge-classes', judgeClassesRouter(input.judgmentRegistry, authorizer));
1155
+ }
1156
+ if (
1157
+ input.evalSuiteRegistry !== undefined &&
1158
+ input.judgmentRegistry !== undefined &&
1159
+ input.evalCaseStore !== undefined
1160
+ ) {
1161
+ v1.route(
1162
+ '/eval-suites',
1163
+ judgedSuitesRouter(
1164
+ input.evalSuiteRegistry,
1165
+ input.judgmentRegistry,
1166
+ input.evalCaseStore,
1167
+ authorizer,
1168
+ ),
1169
+ );
1170
+ }
1099
1171
  // ---------- platform hierarchy ----------
1100
1172
  // Mounts are independent: `/v1/orgs`, `/v1/teams`, `/v1/projects`,
1101
1173
  // `/v1/tenant`. Each requires its own binding. Team + Project
@@ -1187,6 +1259,7 @@ export function createApp(input: CreateAppInput): Hono<AppEnv> {
1187
1259
  signingKeyRegistry: input.signingKeyRegistry,
1188
1260
  imageRegistry: input.imageRegistry,
1189
1261
  ...(input.toolRegistry !== undefined && { toolRegistry: input.toolRegistry }),
1262
+ ...(input.blockRegistry !== undefined && { blockRegistry: input.blockRegistry }),
1190
1263
  ...(input.guardrailRegistry !== undefined && {
1191
1264
  guardrailRegistry: input.guardrailRegistry,
1192
1265
  }),
@@ -0,0 +1,137 @@
1
+ // SPDX-License-Identifier: Apache-2.0
2
+ // Copyright (C) 2026 Kindgi Inc.
3
+
4
+ import type { BlockDefinition, BlockKind } from '@kindgi/agents';
5
+ import type { Scope } from '@kindgi/platform';
6
+ import type { Cursor, ProjectId, TenantId } from '@kindgi/types';
7
+
8
+ /**
9
+ * Caller-plugged surface for the data-block registry: prompts and
10
+ * settings, versioned like tools (a head plus immutable versions, with
11
+ * unregister and reinstate). The API package does not own persistence;
12
+ * a deployment wires a store (a database, or in-memory in tests).
13
+ *
14
+ * A block belongs to one project, and is authorized through it: reading
15
+ * one is `read` on its project, publishing, unregistering or
16
+ * reinstating is `write` on it. There are no per-block grants, so the
17
+ * binding writes no authorization tuples.
18
+ *
19
+ * Every method is tenant-scoped.
20
+ */
21
+ export interface BlockRegistryBinding {
22
+ /** Each block's latest active version, by id, cursor-paginated. */
23
+ list(input: BlockListInput): Promise<BlockPage>;
24
+ /** A block's latest active version, or `null` (never published, or every version unregistered). */
25
+ get(input: BlockGetInput): Promise<BlockRecord | null>;
26
+ /**
27
+ * A specific version, or `null` if it was never published. An
28
+ * unregistered version is returned too, with `unregisteredAt`: the
29
+ * agent versions that pin it still read it.
30
+ */
31
+ getVersion(input: BlockGetVersionInput): Promise<BlockRecord | null>;
32
+ /** A block's versions, newest published first; unregistered ones only with `includeTombstoned`. */
33
+ listVersions(input: BlockListVersionsInput): Promise<BlockPage>;
34
+ /**
35
+ * Publish a validated block version into a project. A version that's
36
+ * taken is `already-registered` (versions never change); a block's
37
+ * versions all live in its first version's project
38
+ * (`project-mismatch` otherwise).
39
+ */
40
+ publish(input: BlockPublishInput): Promise<BlockPublishOutcome>;
41
+ /** Soft-unregister a version: `{ unregistered: false }` when unknown or already unregistered. */
42
+ unregister(input: BlockVersionInput): Promise<{ readonly unregistered: boolean }>;
43
+ /** Reinstate an unregistered version, unchanged; idempotent. */
44
+ reinstateVersion(input: BlockVersionInput): Promise<BlockReinstateOutcome>;
45
+ }
46
+
47
+ /** A block version as the registry holds it. */
48
+ export type BlockRecord = BlockDefinition & {
49
+ /** The project the block belongs to: its authorization comes from there. */
50
+ readonly projectId: ProjectId;
51
+ /** ISO-8601. */
52
+ readonly publishedAt: string;
53
+ /** ISO-8601; present only on an unregistered version. */
54
+ readonly unregisteredAt?: string;
55
+ };
56
+
57
+ export interface BlockListInput {
58
+ readonly tenantId: TenantId;
59
+ readonly limit: number;
60
+ readonly cursor?: Cursor;
61
+ /** Exact match on `kind`. */
62
+ readonly blockKind?: BlockKind;
63
+ /** Prefix match on the block id. */
64
+ readonly nameFilter?: string;
65
+ /**
66
+ * Narrow to a scope, as the other registries' lists do. Absent: every
67
+ * block in the tenant. A block always belongs to one project:
68
+ * - `{ kind: 'project', projectId }`: that project's blocks;
69
+ * - `{ kind: 'org', orgId }`: the blocks of every project in that org;
70
+ * - `{ kind: 'tenant' }`: every block in the tenant.
71
+ */
72
+ readonly scope?: Scope;
73
+ }
74
+
75
+ export interface BlockGetInput {
76
+ readonly tenantId: TenantId;
77
+ readonly blockId: string;
78
+ }
79
+
80
+ export interface BlockGetVersionInput {
81
+ readonly tenantId: TenantId;
82
+ readonly blockId: string;
83
+ readonly version: string;
84
+ }
85
+
86
+ export interface BlockListVersionsInput {
87
+ readonly tenantId: TenantId;
88
+ readonly blockId: string;
89
+ readonly limit: number;
90
+ readonly cursor?: Cursor;
91
+ /** Include unregistered versions (each with `unregisteredAt`). Default `false`. */
92
+ readonly includeTombstoned?: boolean;
93
+ }
94
+
95
+ export interface BlockPublishInput {
96
+ readonly tenantId: TenantId;
97
+ /** The project to publish into. REQUIRED; the store never falls back to Default. */
98
+ readonly projectId: ProjectId;
99
+ readonly block: BlockDefinition;
100
+ }
101
+
102
+ export interface BlockVersionInput {
103
+ readonly tenantId: TenantId;
104
+ readonly blockId: string;
105
+ readonly version: string;
106
+ }
107
+
108
+ export interface BlockPage {
109
+ readonly data: readonly BlockRecord[];
110
+ readonly nextCursor?: Cursor;
111
+ }
112
+
113
+ export type BlockPublishOutcome =
114
+ | { readonly kind: 'ok'; readonly blockId: string; readonly version: string }
115
+ | { readonly kind: 'already-registered'; readonly blockId: string; readonly version: string }
116
+ | {
117
+ /** The `projectId` isn't a project in this tenant. */
118
+ readonly kind: 'project-not-found';
119
+ readonly blockId: string;
120
+ readonly projectId: ProjectId;
121
+ }
122
+ | {
123
+ /** The block's earlier versions live in another project: a block belongs to one project. */
124
+ readonly kind: 'project-mismatch';
125
+ readonly blockId: string;
126
+ /** The project the block belongs to. */
127
+ readonly projectId: ProjectId;
128
+ };
129
+
130
+ export type BlockReinstateOutcome =
131
+ | {
132
+ readonly kind: 'ok';
133
+ readonly blockId: string;
134
+ readonly version: string;
135
+ readonly wasTombstoned: boolean;
136
+ }
137
+ | { readonly kind: 'not-found'; readonly blockId: string; readonly version: string };