@kindgi/api 0.1.3 → 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.
- package/dist/agent-binding.d.ts +18 -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 +20 -2
- 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 +58 -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 +69 -0
- package/dist/derive-agent-version.d.ts.map +1 -0
- package/dist/derive-agent-version.js +139 -0
- package/dist/derive-agent-version.js.map +1 -0
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js +17 -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 +30 -0
- package/dist/eval-run-binding.d.ts.map +1 -1
- package/dist/eval-run-dispatcher.d.ts +38 -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 +10 -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/index.d.ts +17 -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 +134 -0
- package/dist/judged-dispatcher.d.ts.map +1 -0
- package/dist/judged-dispatcher.js +297 -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 +461 -7
- package/dist/openapi/operations.js.map +1 -1
- package/dist/openapi/schemas.d.ts +40 -0
- package/dist/openapi/schemas.d.ts.map +1 -1
- package/dist/openapi/schemas.js +843 -7
- 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/routes/agents.d.ts +9 -1
- package/dist/routes/agents.d.ts.map +1 -1
- package/dist/routes/agents.js +175 -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 +281 -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 +208 -55
- package/dist/routes/deployments.js.map +1 -1
- package/dist/routes/eval-comparison.d.ts +14 -0
- package/dist/routes/eval-comparison.d.ts.map +1 -0
- package/dist/routes/eval-comparison.js +87 -0
- package/dist/routes/eval-comparison.js.map +1 -0
- package/dist/routes/eval-runs.d.ts.map +1 -1
- package/dist/routes/eval-runs.js +8 -0
- package/dist/routes/eval-runs.js.map +1 -1
- package/dist/routes/flows.d.ts +13 -1
- package/dist/routes/flows.d.ts.map +1 -1
- package/dist/routes/flows.js +44 -3
- package/dist/routes/flows.js.map +1 -1
- package/dist/routes/hierarchy-errors.d.ts +35 -0
- package/dist/routes/hierarchy-errors.d.ts.map +1 -0
- package/dist/routes/hierarchy-errors.js +39 -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 +87 -79
- 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 +24 -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 +77 -73
- package/dist/routes/teams.js.map +1 -1
- package/openapi.json +13545 -10103
- package/package.json +21 -21
- package/src/agent-binding.ts +19 -4
- package/src/agent-pins.ts +147 -0
- package/src/app.ts +71 -2
- 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 +206 -0
- package/src/errors.ts +17 -0
- package/src/eval-case-binding.ts +71 -0
- package/src/eval-run-binding.ts +33 -0
- package/src/eval-run-dispatcher.ts +57 -16
- package/src/eval-suite-binding.ts +2 -0
- package/src/flow-binding.ts +11 -4
- package/src/flow-pins.ts +113 -0
- package/src/index.ts +85 -2
- package/src/judged-dispatcher.ts +507 -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 +523 -7
- package/src/openapi/schemas.ts +1009 -88
- package/src/provider-binding.ts +12 -7
- package/src/routes/agents.ts +243 -19
- package/src/routes/blocks.ts +362 -0
- package/src/routes/cost.ts +55 -1
- package/src/routes/deployments.ts +266 -56
- package/src/routes/eval-comparison.ts +101 -0
- package/src/routes/eval-runs.ts +11 -0
- package/src/routes/flows.ts +63 -5
- package/src/routes/hierarchy-errors.ts +51 -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 +106 -95
- package/src/routes/providers.ts +5 -0
- package/src/routes/runs.ts +28 -3
- package/src/routes/teams.ts +96 -90
|
@@ -0,0 +1,245 @@
|
|
|
1
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
2
|
+
// Copyright (C) 2026 Kindgi Inc.
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* What a judged flow run did, kept when it's first judged so it can be
|
|
6
|
+
* replayed faithfully later: every tool call it made, with its result,
|
|
7
|
+
* at its tool nodes, in its agent steps' turns, and in its sub-flows.
|
|
8
|
+
* A replay of the run uses these as the past run's results. Best effort
|
|
9
|
+
* and read-only: a part that can't be read is left out, and the judgment
|
|
10
|
+
* never fails over it.
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
import type { Flow, FlowNode } from '@kindgi/flow';
|
|
14
|
+
import { isFanoutNode, isLoopNode } from '@kindgi/flow';
|
|
15
|
+
import type { KernelRunRecord, RunBinding } from '@kindgi/runtime';
|
|
16
|
+
import type { FlowId, RunId, TenantId } from '@kindgi/types';
|
|
17
|
+
|
|
18
|
+
import type { FlowRegistryBinding } from '../flow-binding.js';
|
|
19
|
+
import type {
|
|
20
|
+
JudgedFlowContext,
|
|
21
|
+
JudgedFlowStep,
|
|
22
|
+
JudgedRunContext,
|
|
23
|
+
JudgedToolCall,
|
|
24
|
+
} from '../judgment-binding.js';
|
|
25
|
+
|
|
26
|
+
/** The most tool calls a judged flow run keeps. */
|
|
27
|
+
export const MAX_JUDGED_FLOW_CALLS = 500;
|
|
28
|
+
/** How deep into sub-flows the capture goes. */
|
|
29
|
+
const MAX_FLOW_DEPTH = 3;
|
|
30
|
+
/** The most child runs read per run. */
|
|
31
|
+
const MAX_CHILDREN = 100;
|
|
32
|
+
|
|
33
|
+
function obj(value: unknown): Record<string, unknown> | undefined {
|
|
34
|
+
return typeof value === 'object' && value !== null && !Array.isArray(value)
|
|
35
|
+
? (value as Record<string, unknown>)
|
|
36
|
+
: undefined;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/** The tool each tool node runs, by node id: in loop bodies and fanout branches too. */
|
|
40
|
+
function toolNodes(flow: Flow | null): ReadonlyMap<string, string> {
|
|
41
|
+
const tools = new Map<string, string>();
|
|
42
|
+
const walk = (nodes: readonly FlowNode[]): void => {
|
|
43
|
+
for (const node of nodes) {
|
|
44
|
+
if (node.kind === 'tool') tools.set(node.id as unknown as string, node.ref);
|
|
45
|
+
else if (isLoopNode(node)) walk(node.body.nodes);
|
|
46
|
+
else if (isFanoutNode(node)) {
|
|
47
|
+
for (const b of node.branches) tools.set(b.handler as unknown as string, b.handler);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
};
|
|
51
|
+
if (flow !== null) walk(flow.nodes);
|
|
52
|
+
return tools;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* The tool calls an agent turn made, with their results, from its
|
|
57
|
+
* output's `appended` messages: each agent message's `toolCalls`, paired
|
|
58
|
+
* with the `tool` message that answered it.
|
|
59
|
+
*/
|
|
60
|
+
export function turnToolCalls(
|
|
61
|
+
output: unknown,
|
|
62
|
+
): readonly { readonly toolId: string; readonly arguments: unknown; readonly result: unknown }[] {
|
|
63
|
+
const appended = obj(output)?.appended;
|
|
64
|
+
if (!Array.isArray(appended)) return [];
|
|
65
|
+
const args = new Map<string, unknown>();
|
|
66
|
+
for (const m of appended) {
|
|
67
|
+
const calls = obj(obj(m)?.content)?.toolCalls;
|
|
68
|
+
if (obj(m)?.role !== 'agent' || !Array.isArray(calls)) continue;
|
|
69
|
+
for (const call of calls) {
|
|
70
|
+
const id = obj(call)?.id;
|
|
71
|
+
if (typeof id === 'string') args.set(id, obj(call)?.arguments);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
return appended.flatMap((m) => {
|
|
75
|
+
const toolCall = obj(obj(m)?.toolCall);
|
|
76
|
+
const toolId = toolCall?.toolId;
|
|
77
|
+
const invocationId = toolCall?.invocationId;
|
|
78
|
+
if (obj(m)?.role !== 'tool' || typeof toolId !== 'string' || typeof invocationId !== 'string') {
|
|
79
|
+
return [];
|
|
80
|
+
}
|
|
81
|
+
return args.has(invocationId)
|
|
82
|
+
? [{ toolId, arguments: args.get(invocationId), result: obj(m)?.content }]
|
|
83
|
+
: [];
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/** Where a step sits: its loop iteration, when it's in a loop body. */
|
|
88
|
+
function scopeOf(loopContext: unknown): string | undefined {
|
|
89
|
+
return loopContext === undefined || loopContext === null
|
|
90
|
+
? undefined
|
|
91
|
+
: JSON.stringify(loopContext);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
class Collector {
|
|
95
|
+
readonly calls: JudgedToolCall[] = [];
|
|
96
|
+
readonly steps: JudgedFlowStep[] = [];
|
|
97
|
+
truncated = false;
|
|
98
|
+
|
|
99
|
+
add(call: JudgedToolCall): void {
|
|
100
|
+
if (this.calls.length >= MAX_JUDGED_FLOW_CALLS) {
|
|
101
|
+
this.truncated = true;
|
|
102
|
+
return;
|
|
103
|
+
}
|
|
104
|
+
this.calls.push(call);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
interface Reader {
|
|
109
|
+
readonly tenantId: TenantId;
|
|
110
|
+
readonly runBinding: RunBinding;
|
|
111
|
+
readonly flows: FlowRegistryBinding | undefined;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/** A flow run's tool nodes' calls: each `step.completed` of a tool node, with its `step.started` input. */
|
|
115
|
+
async function nodeCalls(
|
|
116
|
+
r: Reader,
|
|
117
|
+
c: Collector,
|
|
118
|
+
run: { readonly runId: string; readonly flowId: string; readonly flowVersion: string },
|
|
119
|
+
): Promise<void> {
|
|
120
|
+
const [flow, journal] = await Promise.all([
|
|
121
|
+
r.flows?.getVersion({
|
|
122
|
+
tenantId: r.tenantId,
|
|
123
|
+
flowId: run.flowId as FlowId,
|
|
124
|
+
version: run.flowVersion,
|
|
125
|
+
}) ?? Promise.resolve(null),
|
|
126
|
+
r.runBinding.readJournal(r.tenantId, run.runId as RunId),
|
|
127
|
+
]);
|
|
128
|
+
const tools = toolNodes(flow);
|
|
129
|
+
if (journal.kind === 'err' || tools.size === 0) return;
|
|
130
|
+
const inputs = new Map<string, unknown>();
|
|
131
|
+
for (const e of journal.value) {
|
|
132
|
+
if (typeof e.nodeId !== 'string' || !tools.has(e.nodeId)) continue;
|
|
133
|
+
const payload = obj(e.payload) ?? {};
|
|
134
|
+
const scope = scopeOf(payload.loopContext);
|
|
135
|
+
const key = `${e.nodeId}\u0000${scope ?? ''}`;
|
|
136
|
+
if (e.kind === 'step.started') inputs.set(key, payload.input);
|
|
137
|
+
if (e.kind === 'step.completed') {
|
|
138
|
+
c.add({
|
|
139
|
+
runId: run.runId,
|
|
140
|
+
nodeId: e.nodeId,
|
|
141
|
+
...(scope !== undefined && { scope }),
|
|
142
|
+
toolId: tools.get(e.nodeId) as string,
|
|
143
|
+
arguments: inputs.get(key),
|
|
144
|
+
result: payload.output,
|
|
145
|
+
});
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
/** An agent step's turn: its calls, and what it retrieved. */
|
|
151
|
+
async function stepTurn(r: Reader, c: Collector, child: KernelRunRecord): Promise<void> {
|
|
152
|
+
const agent = child.agent;
|
|
153
|
+
if (agent === undefined) return;
|
|
154
|
+
const output =
|
|
155
|
+
child.output ?? (await r.runBinding.getRun(r.tenantId, child.runId))?.output ?? undefined;
|
|
156
|
+
const nodeId = (child.parentNodeId as unknown as string | null | undefined) ?? undefined;
|
|
157
|
+
const scope = child.parentScope ?? undefined;
|
|
158
|
+
const retrieved = obj(output)?.retrieved;
|
|
159
|
+
c.steps.push({
|
|
160
|
+
runId: child.runId as unknown as string,
|
|
161
|
+
...(nodeId !== undefined && { nodeId }),
|
|
162
|
+
...(scope !== undefined && scope !== '' && { scope }),
|
|
163
|
+
agentId: agent.id,
|
|
164
|
+
agentVersion: agent.version,
|
|
165
|
+
...(retrieved !== undefined && { retrieved }),
|
|
166
|
+
});
|
|
167
|
+
for (const call of turnToolCalls(output)) {
|
|
168
|
+
c.add({
|
|
169
|
+
runId: child.runId as unknown as string,
|
|
170
|
+
...(nodeId !== undefined && { nodeId }),
|
|
171
|
+
...(scope !== undefined && scope !== '' && { scope }),
|
|
172
|
+
...call,
|
|
173
|
+
});
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
/** A run's child runs (agent steps' turns, sub-flows); none when they can't be read. */
|
|
178
|
+
async function childrenOf(r: Reader, runId: string): Promise<readonly KernelRunRecord[]> {
|
|
179
|
+
try {
|
|
180
|
+
const page = await r.runBinding.listRuns({
|
|
181
|
+
tenantId: r.tenantId,
|
|
182
|
+
parent: { runId: runId as RunId },
|
|
183
|
+
limit: MAX_CHILDREN,
|
|
184
|
+
});
|
|
185
|
+
return page.data;
|
|
186
|
+
} catch {
|
|
187
|
+
return [];
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
async function collectRun(
|
|
192
|
+
r: Reader,
|
|
193
|
+
c: Collector,
|
|
194
|
+
run: { readonly runId: string; readonly flowId: string; readonly flowVersion: string },
|
|
195
|
+
depth: number,
|
|
196
|
+
): Promise<void> {
|
|
197
|
+
await nodeCalls(r, c, run).catch(() => undefined);
|
|
198
|
+
for (const child of await childrenOf(r, run.runId)) {
|
|
199
|
+
if (child.agent !== undefined) {
|
|
200
|
+
await stepTurn(r, c, child).catch(() => undefined);
|
|
201
|
+
} else if (depth < MAX_FLOW_DEPTH) {
|
|
202
|
+
await collectRun(
|
|
203
|
+
r,
|
|
204
|
+
c,
|
|
205
|
+
{
|
|
206
|
+
runId: child.runId as unknown as string,
|
|
207
|
+
flowId: child.flowId,
|
|
208
|
+
flowVersion: child.flowVersion,
|
|
209
|
+
},
|
|
210
|
+
depth + 1,
|
|
211
|
+
);
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
/**
|
|
217
|
+
* What a judged flow run did (`context.flow`): its tool calls with their
|
|
218
|
+
* results, and its agent steps' turns. `undefined` when nothing could be
|
|
219
|
+
* read.
|
|
220
|
+
*/
|
|
221
|
+
export async function captureFlowContext(input: {
|
|
222
|
+
readonly tenantId: TenantId;
|
|
223
|
+
readonly run: { readonly runId: string; readonly flowId: string; readonly flowVersion: string };
|
|
224
|
+
readonly runBinding: RunBinding;
|
|
225
|
+
readonly flows: FlowRegistryBinding | undefined;
|
|
226
|
+
}): Promise<JudgedRunContext | undefined> {
|
|
227
|
+
const c = new Collector();
|
|
228
|
+
try {
|
|
229
|
+
await collectRun(
|
|
230
|
+
{ tenantId: input.tenantId, runBinding: input.runBinding, flows: input.flows },
|
|
231
|
+
c,
|
|
232
|
+
input.run,
|
|
233
|
+
0,
|
|
234
|
+
);
|
|
235
|
+
} catch {
|
|
236
|
+
// Best effort: keep what was read.
|
|
237
|
+
}
|
|
238
|
+
if (c.calls.length === 0 && c.steps.length === 0) return undefined;
|
|
239
|
+
const flow: JudgedFlowContext = {
|
|
240
|
+
calls: c.calls,
|
|
241
|
+
steps: c.steps,
|
|
242
|
+
...(c.truncated && { truncated: true }),
|
|
243
|
+
};
|
|
244
|
+
return { flow };
|
|
245
|
+
}
|