@kindgi/api 0.1.3 → 0.1.4-rc.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/dist/agent-binding.d.ts +26 -4
- package/dist/agent-binding.d.ts.map +1 -1
- package/dist/agent-pins.d.ts +48 -0
- package/dist/agent-pins.d.ts.map +1 -0
- package/dist/agent-pins.js +102 -0
- package/dist/agent-pins.js.map +1 -0
- package/dist/app.d.ts +22 -0
- package/dist/app.d.ts.map +1 -1
- package/dist/app.js +27 -3
- package/dist/app.js.map +1 -1
- package/dist/block-binding.d.ts +132 -0
- package/dist/block-binding.d.ts.map +1 -0
- package/dist/block-binding.js +4 -0
- package/dist/block-binding.js.map +1 -0
- package/dist/block-pins.d.ts +22 -0
- package/dist/block-pins.d.ts.map +1 -0
- package/dist/block-pins.js +112 -0
- package/dist/block-pins.js.map +1 -0
- package/dist/cost-binding.d.ts +20 -1
- package/dist/cost-binding.d.ts.map +1 -1
- package/dist/cost-binding.js +4 -0
- package/dist/cost-binding.js.map +1 -1
- package/dist/deploy-versions.d.ts +60 -0
- package/dist/deploy-versions.d.ts.map +1 -0
- package/dist/deploy-versions.js +91 -0
- package/dist/deploy-versions.js.map +1 -0
- package/dist/deployment-binding.d.ts +24 -3
- package/dist/deployment-binding.d.ts.map +1 -1
- package/dist/derive-agent-version.d.ts +77 -0
- package/dist/derive-agent-version.d.ts.map +1 -0
- package/dist/derive-agent-version.js +149 -0
- package/dist/derive-agent-version.js.map +1 -0
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js +18 -0
- package/dist/errors.js.map +1 -1
- package/dist/eval-case-binding.d.ts +65 -0
- package/dist/eval-case-binding.d.ts.map +1 -0
- package/dist/eval-case-binding.js +4 -0
- package/dist/eval-case-binding.js.map +1 -0
- package/dist/eval-run-binding.d.ts +37 -0
- package/dist/eval-run-binding.d.ts.map +1 -1
- package/dist/eval-run-binding.js.map +1 -1
- package/dist/eval-run-dispatcher.d.ts +41 -3
- package/dist/eval-run-dispatcher.d.ts.map +1 -1
- package/dist/eval-run-dispatcher.js +21 -15
- package/dist/eval-run-dispatcher.js.map +1 -1
- package/dist/eval-suite-binding.d.ts +1 -1
- package/dist/eval-suite-binding.d.ts.map +1 -1
- package/dist/eval-suite-binding.js +2 -0
- package/dist/eval-suite-binding.js.map +1 -1
- package/dist/flow-binding.d.ts +18 -4
- package/dist/flow-binding.d.ts.map +1 -1
- package/dist/flow-pins.d.ts +36 -0
- package/dist/flow-pins.d.ts.map +1 -0
- package/dist/flow-pins.js +81 -0
- package/dist/flow-pins.js.map +1 -0
- package/dist/guardrail-binding.d.ts +8 -0
- package/dist/guardrail-binding.d.ts.map +1 -1
- package/dist/handler-binding.d.ts +3 -0
- package/dist/handler-binding.d.ts.map +1 -1
- package/dist/index.d.ts +18 -6
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +8 -2
- package/dist/index.js.map +1 -1
- package/dist/judged-dispatcher.d.ts +138 -0
- package/dist/judged-dispatcher.d.ts.map +1 -0
- package/dist/judged-dispatcher.js +308 -0
- package/dist/judged-dispatcher.js.map +1 -0
- package/dist/judged-items.d.ts +86 -0
- package/dist/judged-items.d.ts.map +1 -0
- package/dist/judged-items.js +184 -0
- package/dist/judged-items.js.map +1 -0
- package/dist/judgment-binding.d.ts +316 -0
- package/dist/judgment-binding.d.ts.map +1 -0
- package/dist/judgment-binding.js +19 -0
- package/dist/judgment-binding.js.map +1 -0
- package/dist/openapi/generate.d.ts.map +1 -1
- package/dist/openapi/generate.js +4 -1
- package/dist/openapi/generate.js.map +1 -1
- package/dist/openapi/operations.d.ts.map +1 -1
- package/dist/openapi/operations.js +482 -13
- package/dist/openapi/operations.js.map +1 -1
- package/dist/openapi/schemas.d.ts +46 -0
- package/dist/openapi/schemas.d.ts.map +1 -1
- package/dist/openapi/schemas.js +1350 -175
- package/dist/openapi/schemas.js.map +1 -1
- package/dist/provider-binding.d.ts +12 -7
- package/dist/provider-binding.d.ts.map +1 -1
- package/dist/registry-read-only.d.ts +32 -0
- package/dist/registry-read-only.d.ts.map +1 -0
- package/dist/registry-read-only.js +22 -0
- package/dist/registry-read-only.js.map +1 -0
- package/dist/routes/agents.d.ts +9 -1
- package/dist/routes/agents.d.ts.map +1 -1
- package/dist/routes/agents.js +181 -11
- package/dist/routes/agents.js.map +1 -1
- package/dist/routes/blocks.d.ts +19 -0
- package/dist/routes/blocks.d.ts.map +1 -0
- package/dist/routes/blocks.js +306 -0
- package/dist/routes/blocks.js.map +1 -0
- package/dist/routes/cost.d.ts.map +1 -1
- package/dist/routes/cost.js +47 -2
- package/dist/routes/cost.js.map +1 -1
- package/dist/routes/deployments.d.ts +3 -0
- package/dist/routes/deployments.d.ts.map +1 -1
- package/dist/routes/deployments.js +224 -55
- package/dist/routes/deployments.js.map +1 -1
- package/dist/routes/eval-comparison.d.ts +15 -0
- package/dist/routes/eval-comparison.d.ts.map +1 -0
- package/dist/routes/eval-comparison.js +123 -0
- package/dist/routes/eval-comparison.js.map +1 -0
- package/dist/routes/eval-runs.d.ts +7 -1
- package/dist/routes/eval-runs.d.ts.map +1 -1
- package/dist/routes/eval-runs.js +42 -3
- package/dist/routes/eval-runs.js.map +1 -1
- package/dist/routes/eval-versions.d.ts +25 -0
- package/dist/routes/eval-versions.d.ts.map +1 -0
- package/dist/routes/eval-versions.js +66 -0
- package/dist/routes/eval-versions.js.map +1 -0
- package/dist/routes/flows.d.ts +13 -1
- package/dist/routes/flows.d.ts.map +1 -1
- package/dist/routes/flows.js +48 -3
- package/dist/routes/flows.js.map +1 -1
- package/dist/routes/guardrails.d.ts.map +1 -1
- package/dist/routes/guardrails.js +4 -0
- package/dist/routes/guardrails.js.map +1 -1
- package/dist/routes/hierarchy-errors.d.ts +45 -0
- package/dist/routes/hierarchy-errors.d.ts.map +1 -0
- package/dist/routes/hierarchy-errors.js +47 -0
- package/dist/routes/hierarchy-errors.js.map +1 -0
- package/dist/routes/judged-suites.d.ts +20 -0
- package/dist/routes/judged-suites.d.ts.map +1 -0
- package/dist/routes/judged-suites.js +272 -0
- package/dist/routes/judged-suites.js.map +1 -0
- package/dist/routes/judgment-context.d.ts +22 -0
- package/dist/routes/judgment-context.d.ts.map +1 -0
- package/dist/routes/judgment-context.js +88 -0
- package/dist/routes/judgment-context.js.map +1 -0
- package/dist/routes/judgment-flow-context.d.ts +32 -0
- package/dist/routes/judgment-flow-context.d.ts.map +1 -0
- package/dist/routes/judgment-flow-context.js +195 -0
- package/dist/routes/judgment-flow-context.js.map +1 -0
- package/dist/routes/judgments.d.ts +41 -0
- package/dist/routes/judgments.d.ts.map +1 -0
- package/dist/routes/judgments.js +566 -0
- package/dist/routes/judgments.js.map +1 -0
- package/dist/routes/orgs.d.ts +5 -2
- package/dist/routes/orgs.d.ts.map +1 -1
- package/dist/routes/orgs.js +38 -22
- package/dist/routes/orgs.js.map +1 -1
- package/dist/routes/policies.d.ts.map +1 -1
- package/dist/routes/policies.js +12 -1
- package/dist/routes/policies.js.map +1 -1
- package/dist/routes/projects.d.ts +10 -2
- package/dist/routes/projects.d.ts.map +1 -1
- package/dist/routes/projects.js +94 -80
- package/dist/routes/projects.js.map +1 -1
- package/dist/routes/providers.d.ts.map +1 -1
- package/dist/routes/providers.js +6 -1
- package/dist/routes/providers.js.map +1 -1
- package/dist/routes/runs.js +25 -3
- package/dist/routes/runs.js.map +1 -1
- package/dist/routes/teams.d.ts +6 -2
- package/dist/routes/teams.d.ts.map +1 -1
- package/dist/routes/teams.js +83 -73
- package/dist/routes/teams.js.map +1 -1
- package/dist/routes/tools.d.ts.map +1 -1
- package/dist/routes/tools.js +4 -0
- package/dist/routes/tools.js.map +1 -1
- package/dist/tool-binding.d.ts +8 -0
- package/dist/tool-binding.d.ts.map +1 -1
- package/openapi.json +14253 -10099
- package/package.json +21 -21
- package/src/agent-binding.ts +28 -4
- package/src/agent-pins.ts +147 -0
- package/src/app.ts +81 -3
- package/src/block-binding.ts +137 -0
- package/src/block-pins.ts +148 -0
- package/src/cost-binding.ts +21 -1
- package/src/deploy-versions.ts +157 -0
- package/src/deployment-binding.ts +27 -3
- package/src/derive-agent-version.ts +217 -0
- package/src/errors.ts +18 -0
- package/src/eval-case-binding.ts +71 -0
- package/src/eval-run-binding.ts +40 -0
- package/src/eval-run-dispatcher.ts +60 -16
- package/src/eval-suite-binding.ts +2 -0
- package/src/flow-binding.ts +20 -4
- package/src/flow-pins.ts +113 -0
- package/src/guardrail-binding.ts +9 -0
- package/src/handler-binding.ts +3 -0
- package/src/index.ts +86 -2
- package/src/judged-dispatcher.ts +530 -0
- package/src/judged-items.ts +263 -0
- package/src/judgment-binding.ts +349 -0
- package/src/openapi/generate.ts +7 -1
- package/src/openapi/operations.ts +579 -13
- package/src/openapi/schemas.ts +1408 -128
- package/src/provider-binding.ts +12 -7
- package/src/registry-read-only.ts +43 -0
- package/src/routes/agents.ts +252 -19
- package/src/routes/blocks.ts +387 -0
- package/src/routes/cost.ts +55 -1
- package/src/routes/deployments.ts +291 -56
- package/src/routes/eval-comparison.ts +135 -0
- package/src/routes/eval-runs.ts +57 -3
- package/src/routes/eval-versions.ts +110 -0
- package/src/routes/flows.ts +70 -5
- package/src/routes/guardrails.ts +7 -0
- package/src/routes/hierarchy-errors.ts +60 -0
- package/src/routes/judged-suites.ts +363 -0
- package/src/routes/judgment-context.ts +128 -0
- package/src/routes/judgment-flow-context.ts +245 -0
- package/src/routes/judgments.ts +743 -0
- package/src/routes/orgs.ts +44 -27
- package/src/routes/policies.ts +19 -0
- package/src/routes/projects.ts +118 -96
- package/src/routes/providers.ts +5 -0
- package/src/routes/runs.ts +29 -3
- package/src/routes/teams.ts +104 -90
- package/src/routes/tools.ts +7 -0
- package/src/tool-binding.ts +9 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kindgi/api",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.4-rc.1",
|
|
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.
|
|
36
|
-
"@kindgi/audit-events": "0.1.
|
|
37
|
-
"@kindgi/compliance": "0.1.
|
|
38
|
-
"@kindgi/authz": "0.1.
|
|
39
|
-
"@kindgi/blob-binding": "0.1.
|
|
40
|
-
"@kindgi/capabilities": "0.1.
|
|
41
|
-
"@kindgi/crypto": "0.1.
|
|
42
|
-
"@kindgi/flow": "0.1.
|
|
43
|
-
"@kindgi/guardrails": "0.1.
|
|
44
|
-
"@kindgi/memory": "0.1.
|
|
45
|
-
"@kindgi/platform": "0.1.
|
|
46
|
-
"@kindgi/provenance": "0.1.
|
|
47
|
-
"@kindgi/runtime": "0.1.
|
|
48
|
-
"@kindgi/policy-contract": "0.1.
|
|
49
|
-
"@kindgi/schema": "0.1.
|
|
50
|
-
"@kindgi/tools": "0.1.
|
|
51
|
-
"@kindgi/types": "0.1.
|
|
35
|
+
"@kindgi/agents": "0.1.4-rc.1",
|
|
36
|
+
"@kindgi/audit-events": "0.1.4-rc.1",
|
|
37
|
+
"@kindgi/compliance": "0.1.4-rc.1",
|
|
38
|
+
"@kindgi/authz": "0.1.4-rc.1",
|
|
39
|
+
"@kindgi/blob-binding": "0.1.4-rc.1",
|
|
40
|
+
"@kindgi/capabilities": "0.1.4-rc.1",
|
|
41
|
+
"@kindgi/crypto": "0.1.4-rc.1",
|
|
42
|
+
"@kindgi/flow": "0.1.4-rc.1",
|
|
43
|
+
"@kindgi/guardrails": "0.1.4-rc.1",
|
|
44
|
+
"@kindgi/memory": "0.1.4-rc.1",
|
|
45
|
+
"@kindgi/platform": "0.1.4-rc.1",
|
|
46
|
+
"@kindgi/provenance": "0.1.4-rc.1",
|
|
47
|
+
"@kindgi/runtime": "0.1.4-rc.1",
|
|
48
|
+
"@kindgi/policy-contract": "0.1.4-rc.1",
|
|
49
|
+
"@kindgi/schema": "0.1.4-rc.1",
|
|
50
|
+
"@kindgi/tools": "0.1.4-rc.1",
|
|
51
|
+
"@kindgi/types": "0.1.4-rc.1",
|
|
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.
|
|
57
|
-
"@kindgi/specs": "0.1.
|
|
58
|
-
"@kindgi/testing": "0.1.
|
|
56
|
+
"@kindgi/audit-events-inmemory": "0.1.4-rc.1",
|
|
57
|
+
"@kindgi/specs": "0.1.4-rc.1",
|
|
58
|
+
"@kindgi/testing": "0.1.4-rc.1",
|
|
59
59
|
"@types/aws4": "^1.11.6",
|
|
60
60
|
"@types/node": "^22.10.5",
|
|
61
61
|
"aws4": "^1.13.2",
|
package/src/agent-binding.ts
CHANGED
|
@@ -6,6 +6,8 @@ import type { TupleEnqueueHook } from '@kindgi/authz';
|
|
|
6
6
|
import type { Scope } from '@kindgi/platform';
|
|
7
7
|
import type { Cursor, ProjectId, Semver, TenantId } from '@kindgi/types';
|
|
8
8
|
|
|
9
|
+
import type { RegistryReadOnly } from './registry-read-only.js';
|
|
10
|
+
|
|
9
11
|
/**
|
|
10
12
|
* Caller-plugged surface for the agent catalog. Same shape as
|
|
11
13
|
* `TokenAdmin` / `ReviewerBinding` / `RunHandlerBinding`: the API
|
|
@@ -22,6 +24,13 @@ import type { Cursor, ProjectId, Semver, TenantId } from '@kindgi/types';
|
|
|
22
24
|
* cursor round-trips as a string; it never inspects the payload.
|
|
23
25
|
*/
|
|
24
26
|
export interface AgentRegistryBinding {
|
|
27
|
+
/**
|
|
28
|
+
* Set when this registry takes no writes (under `kindgi dev`, the
|
|
29
|
+
* pack's files are the source of its agents): every write is refused
|
|
30
|
+
* with `409 registry-read-only` and this reason, before the binding is
|
|
31
|
+
* called. See `RegistryReadOnly`.
|
|
32
|
+
*/
|
|
33
|
+
readonly readOnly?: RegistryReadOnly;
|
|
25
34
|
/**
|
|
26
35
|
* Cursor-paginated list of agents (latest version per id, sorted by
|
|
27
36
|
* agent id ascending). Optional `nameFilter` is a prefix match on the
|
|
@@ -36,11 +45,13 @@ export interface AgentRegistryBinding {
|
|
|
36
45
|
get(input: AgentGetInput): Promise<Agent | null>;
|
|
37
46
|
/**
|
|
38
47
|
* Specific `(agentId, version)` lookup, or `null` if unknown.
|
|
39
|
-
* Returns tombstoned versions too
|
|
40
|
-
* filter them
|
|
41
|
-
*
|
|
48
|
+
* Returns unregistered (tombstoned) versions too, unlike `list` /
|
|
49
|
+
* `get` which filter them, with `unregisteredAt` set. Unregister stops
|
|
50
|
+
* a version being *chosen*, not the pins that hold it: a resumed run,
|
|
51
|
+
* provenance, and a flow version that pins it read it, while a new run
|
|
52
|
+
* that names it is refused.
|
|
42
53
|
*/
|
|
43
|
-
getVersion(input: AgentGetVersionInput): Promise<
|
|
54
|
+
getVersion(input: AgentGetVersionInput): Promise<AgentVersionRecord | null>;
|
|
44
55
|
/**
|
|
45
56
|
* Head-row existence check. Returns `true` iff the agent id has been
|
|
46
57
|
* registered in the tenant (regardless of whether any versions are
|
|
@@ -88,6 +99,14 @@ export interface AgentRegistryBinding {
|
|
|
88
99
|
reinstateVersion(input: AgentReinstateVersionInput): Promise<AgentReinstateVersionOutcome>;
|
|
89
100
|
}
|
|
90
101
|
|
|
102
|
+
/** An agent version as `getVersion` reads it: `unregisteredAt` is set when it's unregistered. */
|
|
103
|
+
export type AgentVersionRecord = Agent & {
|
|
104
|
+
/** ISO-8601; present only on an unregistered version. */
|
|
105
|
+
readonly unregisteredAt?: string;
|
|
106
|
+
/** The project the version belongs to, when the store records it (a derived version is published there). */
|
|
107
|
+
readonly projectId?: ProjectId;
|
|
108
|
+
};
|
|
109
|
+
|
|
91
110
|
export interface AgentListInput {
|
|
92
111
|
readonly tenantId: TenantId;
|
|
93
112
|
readonly limit: number;
|
|
@@ -149,6 +168,11 @@ export interface AgentPublishInput {
|
|
|
149
168
|
* silently falls back to Default.
|
|
150
169
|
*/
|
|
151
170
|
readonly projectId: ProjectId;
|
|
171
|
+
/**
|
|
172
|
+
* The version to store, as given. When the route pinned it, it
|
|
173
|
+
* carries `pins` and `pinsDigest` (the exact block versions its runs
|
|
174
|
+
* use); a binding stores and returns them with the rest.
|
|
175
|
+
*/
|
|
152
176
|
readonly agent: Agent;
|
|
153
177
|
/**
|
|
154
178
|
* 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
|
|
@@ -1002,10 +1027,22 @@ export function createApp(input: CreateAppInput): Hono<AppEnv> {
|
|
|
1002
1027
|
v1.route('/observations', observationsRouter(input.supervisor));
|
|
1003
1028
|
}
|
|
1004
1029
|
if (input.agentRegistry !== undefined) {
|
|
1005
|
-
v1.route(
|
|
1030
|
+
v1.route(
|
|
1031
|
+
'/agents',
|
|
1032
|
+
agentsRouter(input.agentRegistry, authorizer, input.toolRegistry, input.blockRegistry),
|
|
1033
|
+
);
|
|
1006
1034
|
}
|
|
1007
1035
|
if (input.flowRegistry !== undefined) {
|
|
1008
|
-
v1.route(
|
|
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
|
+
);
|
|
1009
1046
|
}
|
|
1010
1047
|
if (input.toolRegistry !== undefined) {
|
|
1011
1048
|
v1.route('/tools', toolsRouter(input.toolRegistry, authorizer, input.onToolWrite));
|
|
@@ -1100,6 +1137,37 @@ export function createApp(input: CreateAppInput): Hono<AppEnv> {
|
|
|
1100
1137
|
if (input.evalSuiteRegistry !== undefined) {
|
|
1101
1138
|
v1.route('/eval-suites', evalSuitesRouter(input.evalSuiteRegistry, authorizer));
|
|
1102
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
|
+
}
|
|
1103
1171
|
// ---------- platform hierarchy ----------
|
|
1104
1172
|
// Mounts are independent: `/v1/orgs`, `/v1/teams`, `/v1/projects`,
|
|
1105
1173
|
// `/v1/tenant`. Each requires its own binding. Team + Project
|
|
@@ -1191,6 +1259,7 @@ export function createApp(input: CreateAppInput): Hono<AppEnv> {
|
|
|
1191
1259
|
signingKeyRegistry: input.signingKeyRegistry,
|
|
1192
1260
|
imageRegistry: input.imageRegistry,
|
|
1193
1261
|
...(input.toolRegistry !== undefined && { toolRegistry: input.toolRegistry }),
|
|
1262
|
+
...(input.blockRegistry !== undefined && { blockRegistry: input.blockRegistry }),
|
|
1194
1263
|
...(input.guardrailRegistry !== undefined && {
|
|
1195
1264
|
guardrailRegistry: input.guardrailRegistry,
|
|
1196
1265
|
}),
|
|
@@ -1220,7 +1289,16 @@ export function createApp(input: CreateAppInput): Hono<AppEnv> {
|
|
|
1220
1289
|
// `evalSuiteRegistry` binding: the dispatcher itself surfaces
|
|
1221
1290
|
// `suite-not-found` when the caller-plugged binding can't resolve
|
|
1222
1291
|
// the suite id, so the API layer stays consumer-neutral.
|
|
1223
|
-
const evalRuns = evalRunsRouters(
|
|
1292
|
+
const evalRuns = evalRunsRouters(
|
|
1293
|
+
input.evalRunBinding,
|
|
1294
|
+
input.flowRegistry !== undefined
|
|
1295
|
+
? {
|
|
1296
|
+
flows: input.flowRegistry,
|
|
1297
|
+
...(input.agentRegistry !== undefined && { agents: input.agentRegistry }),
|
|
1298
|
+
...(input.toolRegistry !== undefined && { tools: input.toolRegistry }),
|
|
1299
|
+
}
|
|
1300
|
+
: undefined,
|
|
1301
|
+
);
|
|
1224
1302
|
v1.route('/eval-suites', evalRuns.start);
|
|
1225
1303
|
v1.route('/eval-runs', evalRuns.readback);
|
|
1226
1304
|
}
|
|
@@ -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 };
|