@kindgi/agents 0.0.0-bootstrap.0 → 0.1.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/LICENSE +201 -0
- package/README.md +131 -2
- package/dist/agent-turn-flow.d.ts +57 -0
- package/dist/agent-turn-flow.d.ts.map +1 -0
- package/dist/agent-turn-flow.js +172 -0
- package/dist/agent-turn-flow.js.map +1 -0
- package/dist/conversation-binding.d.ts +111 -0
- package/dist/conversation-binding.d.ts.map +1 -0
- package/dist/conversation-binding.js +4 -0
- package/dist/conversation-binding.js.map +1 -0
- package/dist/define.d.ts +180 -0
- package/dist/define.d.ts.map +1 -0
- package/dist/define.js +361 -0
- package/dist/define.js.map +1 -0
- package/dist/errors.d.ts +62 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +4 -0
- package/dist/errors.js.map +1 -0
- package/dist/guardrails-gate.d.ts +169 -0
- package/dist/guardrails-gate.d.ts.map +1 -0
- package/dist/guardrails-gate.js +202 -0
- package/dist/guardrails-gate.js.map +1 -0
- package/dist/handlers/budget-check.d.ts +22 -0
- package/dist/handlers/budget-check.d.ts.map +1 -0
- package/dist/handlers/budget-check.js +109 -0
- package/dist/handlers/budget-check.js.map +1 -0
- package/dist/handlers/build-initial-messages.d.ts +17 -0
- package/dist/handlers/build-initial-messages.d.ts.map +1 -0
- package/dist/handlers/build-initial-messages.js +86 -0
- package/dist/handlers/build-initial-messages.js.map +1 -0
- package/dist/handlers/compose-result.d.ts +10 -0
- package/dist/handlers/compose-result.d.ts.map +1 -0
- package/dist/handlers/compose-result.js +79 -0
- package/dist/handlers/compose-result.js.map +1 -0
- package/dist/handlers/constants.d.ts +8 -0
- package/dist/handlers/constants.d.ts.map +1 -0
- package/dist/handlers/constants.js +10 -0
- package/dist/handlers/constants.js.map +1 -0
- package/dist/handlers/context.d.ts +210 -0
- package/dist/handlers/context.d.ts.map +1 -0
- package/dist/handlers/context.js +4 -0
- package/dist/handlers/context.js.map +1 -0
- package/dist/handlers/dispatch-tools.d.ts +15 -0
- package/dist/handlers/dispatch-tools.d.ts.map +1 -0
- package/dist/handlers/dispatch-tools.js +511 -0
- package/dist/handlers/dispatch-tools.js.map +1 -0
- package/dist/handlers/errors.d.ts +133 -0
- package/dist/handlers/errors.d.ts.map +1 -0
- package/dist/handlers/errors.js +134 -0
- package/dist/handlers/errors.js.map +1 -0
- package/dist/handlers/evaluate-guardrails.d.ts +14 -0
- package/dist/handlers/evaluate-guardrails.d.ts.map +1 -0
- package/dist/handlers/evaluate-guardrails.js +128 -0
- package/dist/handlers/evaluate-guardrails.js.map +1 -0
- package/dist/handlers/final-iteration.d.ts +7 -0
- package/dist/handlers/final-iteration.d.ts.map +1 -0
- package/dist/handlers/final-iteration.js +26 -0
- package/dist/handlers/final-iteration.js.map +1 -0
- package/dist/handlers/index.d.ts +5 -0
- package/dist/handlers/index.d.ts.map +1 -0
- package/dist/handlers/index.js +41 -0
- package/dist/handlers/index.js.map +1 -0
- package/dist/handlers/model-call.d.ts +13 -0
- package/dist/handlers/model-call.d.ts.map +1 -0
- package/dist/handlers/model-call.js +136 -0
- package/dist/handlers/model-call.js.map +1 -0
- package/dist/handlers/persist-final-message.d.ts +14 -0
- package/dist/handlers/persist-final-message.d.ts.map +1 -0
- package/dist/handlers/persist-final-message.js +54 -0
- package/dist/handlers/persist-final-message.js.map +1 -0
- package/dist/handlers/persist-provenance.d.ts +12 -0
- package/dist/handlers/persist-provenance.d.ts.map +1 -0
- package/dist/handlers/persist-provenance.js +34 -0
- package/dist/handlers/persist-provenance.js.map +1 -0
- package/dist/handlers/persist-user-message.d.ts +15 -0
- package/dist/handlers/persist-user-message.d.ts.map +1 -0
- package/dist/handlers/persist-user-message.js +59 -0
- package/dist/handlers/persist-user-message.js.map +1 -0
- package/dist/handlers/public-types.d.ts +201 -0
- package/dist/handlers/public-types.d.ts.map +1 -0
- package/dist/handlers/public-types.js +4 -0
- package/dist/handlers/public-types.js.map +1 -0
- package/dist/handlers/rehydrate.d.ts +8 -0
- package/dist/handlers/rehydrate.d.ts.map +1 -0
- package/dist/handlers/rehydrate.js +94 -0
- package/dist/handlers/rehydrate.js.map +1 -0
- package/dist/handlers/render-prompt.d.ts +12 -0
- package/dist/handlers/render-prompt.d.ts.map +1 -0
- package/dist/handlers/render-prompt.js +41 -0
- package/dist/handlers/render-prompt.js.map +1 -0
- package/dist/handlers/resolve-tools.d.ts +10 -0
- package/dist/handlers/resolve-tools.d.ts.map +1 -0
- package/dist/handlers/resolve-tools.js +55 -0
- package/dist/handlers/resolve-tools.js.map +1 -0
- package/dist/handlers/result-shape.d.ts +94 -0
- package/dist/handlers/result-shape.d.ts.map +1 -0
- package/dist/handlers/result-shape.js +19 -0
- package/dist/handlers/result-shape.js.map +1 -0
- package/dist/handlers/run-retrievals.d.ts +10 -0
- package/dist/handlers/run-retrievals.d.ts.map +1 -0
- package/dist/handlers/run-retrievals.js +64 -0
- package/dist/handlers/run-retrievals.js.map +1 -0
- package/dist/handlers/run-snapshot.d.ts +4 -0
- package/dist/handlers/run-snapshot.d.ts.map +1 -0
- package/dist/handlers/run-snapshot.js +26 -0
- package/dist/handlers/run-snapshot.js.map +1 -0
- package/dist/handlers/setup.d.ts +25 -0
- package/dist/handlers/setup.d.ts.map +1 -0
- package/dist/handlers/setup.js +231 -0
- package/dist/handlers/setup.js.map +1 -0
- package/dist/handlers/structured-output.d.ts +38 -0
- package/dist/handlers/structured-output.d.ts.map +1 -0
- package/dist/handlers/structured-output.js +89 -0
- package/dist/handlers/structured-output.js.map +1 -0
- package/dist/handlers/tool-errors.d.ts +56 -0
- package/dist/handlers/tool-errors.d.ts.map +1 -0
- package/dist/handlers/tool-errors.js +73 -0
- package/dist/handlers/tool-errors.js.map +1 -0
- package/dist/handlers/tool-hitl.d.ts +45 -0
- package/dist/handlers/tool-hitl.d.ts.map +1 -0
- package/dist/handlers/tool-hitl.js +81 -0
- package/dist/handlers/tool-hitl.js.map +1 -0
- package/dist/handlers/turn-environment.d.ts +26 -0
- package/dist/handlers/turn-environment.d.ts.map +1 -0
- package/dist/handlers/turn-environment.js +154 -0
- package/dist/handlers/turn-environment.js.map +1 -0
- package/dist/hitl-policy.d.ts +45 -0
- package/dist/hitl-policy.d.ts.map +1 -0
- package/dist/hitl-policy.js +74 -0
- package/dist/hitl-policy.js.map +1 -0
- package/dist/index.d.ts +31 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +19 -0
- package/dist/index.js.map +1 -0
- package/dist/invoke.d.ts +36 -0
- package/dist/invoke.d.ts.map +1 -0
- package/dist/invoke.js +228 -0
- package/dist/invoke.js.map +1 -0
- package/dist/migrations-dir.d.ts +11 -0
- package/dist/migrations-dir.d.ts.map +1 -0
- package/dist/migrations-dir.js +14 -0
- package/dist/migrations-dir.js.map +1 -0
- package/dist/project-run-result.d.ts +23 -0
- package/dist/project-run-result.d.ts.map +1 -0
- package/dist/project-run-result.js +116 -0
- package/dist/project-run-result.js.map +1 -0
- package/dist/prompt.d.ts +83 -0
- package/dist/prompt.d.ts.map +1 -0
- package/dist/prompt.js +119 -0
- package/dist/prompt.js.map +1 -0
- package/dist/provenance-emit.d.ts +44 -0
- package/dist/provenance-emit.d.ts.map +1 -0
- package/dist/provenance-emit.js +51 -0
- package/dist/provenance-emit.js.map +1 -0
- package/dist/registry.d.ts +38 -0
- package/dist/registry.d.ts.map +1 -0
- package/dist/registry.js +125 -0
- package/dist/registry.js.map +1 -0
- package/dist/retrieval.d.ts +47 -0
- package/dist/retrieval.d.ts.map +1 -0
- package/dist/retrieval.js +155 -0
- package/dist/retrieval.js.map +1 -0
- package/dist/run-snapshot-binding.d.ts +77 -0
- package/dist/run-snapshot-binding.d.ts.map +1 -0
- package/dist/run-snapshot-binding.js +4 -0
- package/dist/run-snapshot-binding.js.map +1 -0
- package/dist/schema.d.ts +497 -0
- package/dist/schema.d.ts.map +1 -0
- package/dist/schema.js +133 -0
- package/dist/schema.js.map +1 -0
- package/dist/streaming.d.ts +118 -0
- package/dist/streaming.d.ts.map +1 -0
- package/dist/streaming.js +17 -0
- package/dist/streaming.js.map +1 -0
- package/dist/tenant-policy.d.ts +16 -0
- package/dist/tenant-policy.d.ts.map +1 -0
- package/dist/tenant-policy.js +77 -0
- package/dist/tenant-policy.js.map +1 -0
- package/dist/types.d.ts +435 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +4 -0
- package/dist/types.js.map +1 -0
- package/dist/versioning.d.ts +29 -0
- package/dist/versioning.d.ts.map +1 -0
- package/dist/versioning.js +58 -0
- package/dist/versioning.js.map +1 -0
- package/migrations/0000_sparkling_talkback.sql +18 -0
- package/migrations/0001_tired_warhawk.sql +16 -0
- package/migrations/0002_violet_ezekiel.sql +2 -0
- package/migrations/meta/0000_snapshot.json +172 -0
- package/migrations/meta/0001_snapshot.json +275 -0
- package/migrations/meta/0002_snapshot.json +287 -0
- package/migrations/meta/_journal.json +27 -0
- package/package.json +76 -4
- package/src/agent-turn-flow.ts +183 -0
- package/src/conversation-binding.ts +147 -0
- package/src/define.ts +572 -0
- package/src/errors.ts +80 -0
- package/src/guardrails-gate.ts +342 -0
- package/src/handlers/budget-check.ts +143 -0
- package/src/handlers/build-initial-messages.ts +103 -0
- package/src/handlers/compose-result.ts +90 -0
- package/src/handlers/constants.ts +10 -0
- package/src/handlers/context.ts +226 -0
- package/src/handlers/dispatch-tools.ts +633 -0
- package/src/handlers/errors.ts +282 -0
- package/src/handlers/evaluate-guardrails.ts +153 -0
- package/src/handlers/final-iteration.ts +30 -0
- package/src/handlers/index.ts +63 -0
- package/src/handlers/model-call.ts +151 -0
- package/src/handlers/persist-final-message.ts +67 -0
- package/src/handlers/persist-provenance.ts +39 -0
- package/src/handlers/persist-user-message.ts +70 -0
- package/src/handlers/public-types.ts +209 -0
- package/src/handlers/rehydrate.ts +161 -0
- package/src/handlers/render-prompt.ts +46 -0
- package/src/handlers/resolve-tools.ts +68 -0
- package/src/handlers/result-shape.ts +113 -0
- package/src/handlers/run-retrievals.ts +77 -0
- package/src/handlers/run-snapshot.ts +44 -0
- package/src/handlers/setup.ts +269 -0
- package/src/handlers/structured-output.ts +117 -0
- package/src/handlers/tool-errors.ts +122 -0
- package/src/handlers/tool-hitl.ts +126 -0
- package/src/handlers/turn-environment.ts +191 -0
- package/src/hitl-policy.ts +128 -0
- package/src/index.ts +154 -0
- package/src/invoke.ts +299 -0
- package/src/migrations-dir.ts +17 -0
- package/src/project-run-result.ts +131 -0
- package/src/prompt.ts +185 -0
- package/src/provenance-emit.ts +100 -0
- package/src/registry.ts +164 -0
- package/src/retrieval.ts +219 -0
- package/src/run-snapshot-binding.ts +87 -0
- package/src/schema.ts +154 -0
- package/src/streaming.ts +153 -0
- package/src/tenant-policy.ts +78 -0
- package/src/types.ts +453 -0
- package/src/versioning.ts +77 -0
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
2
|
+
// Copyright (C) 2026 Kindgi Inc.
|
|
3
|
+
import { compileInlineSchema } from '@kindgi/schema';
|
|
4
|
+
/** Default number of repair attempts. */
|
|
5
|
+
export const DEFAULT_MAX_REPAIRS = 1;
|
|
6
|
+
/** Marks the messages this module adds, so they can be counted. */
|
|
7
|
+
const REPAIR_MARKER = '[kindgi:output-repair]';
|
|
8
|
+
/**
|
|
9
|
+
* The answer's text as JSON. Accepts a bare JSON value or one fenced
|
|
10
|
+
* as ```json … ``` (models often fence it).
|
|
11
|
+
*/
|
|
12
|
+
export function parseJsonAnswer(content) {
|
|
13
|
+
if (typeof content !== 'string') {
|
|
14
|
+
return { kind: 'invalid', errors: ['the answer is not text'] };
|
|
15
|
+
}
|
|
16
|
+
const text = unfence(content.trim());
|
|
17
|
+
if (text.length === 0)
|
|
18
|
+
return { kind: 'invalid', errors: ['the answer is empty'] };
|
|
19
|
+
try {
|
|
20
|
+
return { kind: 'ok', value: JSON.parse(text) };
|
|
21
|
+
}
|
|
22
|
+
catch (cause) {
|
|
23
|
+
return {
|
|
24
|
+
kind: 'invalid',
|
|
25
|
+
errors: [
|
|
26
|
+
`the answer is not valid JSON (${cause instanceof Error ? cause.message : String(cause)})`,
|
|
27
|
+
],
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
function unfence(text) {
|
|
32
|
+
const fenced = /^```(?:json)?\s*\n([\s\S]*?)\n?```$/i.exec(text);
|
|
33
|
+
return fenced?.[1]?.trim() ?? text;
|
|
34
|
+
}
|
|
35
|
+
export function outputChecker(spec) {
|
|
36
|
+
const compiled = compileInlineSchema(spec.schema);
|
|
37
|
+
if (compiled.kind === 'err') {
|
|
38
|
+
// `defineAgent` compiles the schema, so this is an agent built by hand.
|
|
39
|
+
const reason = compiled.error.message;
|
|
40
|
+
return {
|
|
41
|
+
check: () => ({ kind: 'invalid', errors: [`the output schema is invalid: ${reason}`] }),
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
const validator = compiled.value;
|
|
45
|
+
return {
|
|
46
|
+
check(content) {
|
|
47
|
+
const parsed = parseJsonAnswer(content);
|
|
48
|
+
if (parsed.kind === 'invalid')
|
|
49
|
+
return parsed;
|
|
50
|
+
const validated = validator.validate(parsed.value);
|
|
51
|
+
if (validated.kind === 'ok')
|
|
52
|
+
return parsed;
|
|
53
|
+
return { kind: 'invalid', errors: describeErrors(validated.error.errors) };
|
|
54
|
+
},
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
/** Ajv errors as `path message` lines the model can act on. */
|
|
58
|
+
function describeErrors(errors) {
|
|
59
|
+
const list = errors.map((raw) => {
|
|
60
|
+
const e = raw;
|
|
61
|
+
const where = e.instancePath === undefined || e.instancePath === '' ? '(root)' : e.instancePath;
|
|
62
|
+
return `${where} ${e.message ?? 'is invalid'}`;
|
|
63
|
+
});
|
|
64
|
+
return list.length > 0 ? list : ['the answer does not match the schema'];
|
|
65
|
+
}
|
|
66
|
+
/** Whether a message is one of this module's repair requests. */
|
|
67
|
+
export function isRepairMessage(m) {
|
|
68
|
+
return m.role === 'user' && typeof m.content === 'string' && m.content.startsWith(REPAIR_MARKER);
|
|
69
|
+
}
|
|
70
|
+
/** How many repairs this turn has asked for so far. */
|
|
71
|
+
export function repairsSoFar(messages) {
|
|
72
|
+
return messages.filter(isRepairMessage).length;
|
|
73
|
+
}
|
|
74
|
+
/** The message asking the model to fix its answer. */
|
|
75
|
+
export function repairMessage(spec, errors) {
|
|
76
|
+
const name = spec.name ?? 'output';
|
|
77
|
+
return {
|
|
78
|
+
role: 'user',
|
|
79
|
+
content: [
|
|
80
|
+
REPAIR_MARKER,
|
|
81
|
+
`Your answer must be the ${name} as JSON matching this JSON Schema, and nothing else:`,
|
|
82
|
+
JSON.stringify(spec.schema),
|
|
83
|
+
'It did not fit:',
|
|
84
|
+
...errors.map((e) => `- ${e}`),
|
|
85
|
+
`Reply again with only the corrected ${name} JSON.`,
|
|
86
|
+
].join('\n'),
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
//# sourceMappingURL=structured-output.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"structured-output.js","sourceRoot":"","sources":["../../src/handlers/structured-output.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Retrying failed tool calls. A failure the turn's policy retries goes
|
|
3
|
+
* back to the model as the call's result — what failed and why — and
|
|
4
|
+
* the turn continues; the model can correct the call. Each retry costs a
|
|
5
|
+
* step, so `budget.maxSteps` still bounds the turn. A failure the policy
|
|
6
|
+
* doesn't retry, or one past `maxRetries`, fails the turn as before.
|
|
7
|
+
*
|
|
8
|
+
* Retries are counted from the turn's messages (the results this module
|
|
9
|
+
* writes carry a marker), so a replayed turn counts the same.
|
|
10
|
+
*/
|
|
11
|
+
import type { ModelMessage } from '@kindgi/capabilities';
|
|
12
|
+
import { type ToolErrorKind, type ToolErrorsSpec } from '@kindgi/policy-contract';
|
|
13
|
+
/** Without an agent setting: one retry, for failures where nothing ran. */
|
|
14
|
+
export declare const DEFAULT_TOOL_ERRORS: Required<ToolErrorsSpec>;
|
|
15
|
+
/** The policy a turn applies. */
|
|
16
|
+
export interface ToolErrorPolicy {
|
|
17
|
+
readonly maxRetries: number;
|
|
18
|
+
readonly retryOn: ReadonlySet<ToolErrorKind>;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* The agent's setting (or the default), capped by the tenant's
|
|
22
|
+
* `tool-errors` policy: the fewer retries, and only the kinds both
|
|
23
|
+
* allow — like every tenant policy, it can only make the turn stricter.
|
|
24
|
+
*/
|
|
25
|
+
export declare function effectiveToolErrorPolicy(agent: ToolErrorsSpec | undefined, tenantCap: ToolErrorsSpec | undefined): ToolErrorPolicy;
|
|
26
|
+
/**
|
|
27
|
+
* Which kind of failure a tool call's error is: arguments that failed
|
|
28
|
+
* the input schema, a tool the agent doesn't have, or a tool that ran
|
|
29
|
+
* and failed.
|
|
30
|
+
*/
|
|
31
|
+
export declare function toolErrorKindOf(error: {
|
|
32
|
+
readonly code: string;
|
|
33
|
+
readonly cause?: unknown;
|
|
34
|
+
}): ToolErrorKind;
|
|
35
|
+
/** Marks the results this module writes, so they can be counted. */
|
|
36
|
+
declare const RETRY_MARKER = "tool-error-retry";
|
|
37
|
+
/** What the model sees for a failed call it may retry. */
|
|
38
|
+
export interface ToolErrorResult {
|
|
39
|
+
readonly kindgi: typeof RETRY_MARKER;
|
|
40
|
+
readonly status: 'failed';
|
|
41
|
+
readonly error: {
|
|
42
|
+
readonly kind: ToolErrorKind;
|
|
43
|
+
readonly message: string;
|
|
44
|
+
readonly issues?: readonly unknown[];
|
|
45
|
+
};
|
|
46
|
+
readonly instruction: string;
|
|
47
|
+
}
|
|
48
|
+
export declare function toolErrorResult(kind: ToolErrorKind, message: string, issues: readonly unknown[] | undefined): ToolErrorResult;
|
|
49
|
+
/**
|
|
50
|
+
* Retries this turn has taken: the marked tool results after the turn's
|
|
51
|
+
* user message. Earlier turns' results come back as history; they don't
|
|
52
|
+
* count.
|
|
53
|
+
*/
|
|
54
|
+
export declare function toolRetriesSoFar(messages: readonly ModelMessage[]): number;
|
|
55
|
+
export {};
|
|
56
|
+
//# sourceMappingURL=tool-errors.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tool-errors.d.ts","sourceRoot":"","sources":["../../src/handlers/tool-errors.ts"],"names":[],"mappings":"AAGA;;;;;;;;;GASG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AACzD,OAAO,EAAoB,KAAK,aAAa,EAAE,KAAK,cAAc,EAAE,MAAM,yBAAyB,CAAC;AAIpG,2EAA2E;AAC3E,eAAO,MAAM,mBAAmB,EAAE,QAAQ,CAAC,cAAc,CAGxD,CAAC;AAEF,iCAAiC;AACjC,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,OAAO,EAAE,WAAW,CAAC,aAAa,CAAC,CAAC;CAC9C;AAED;;;;GAIG;AACH,wBAAgB,wBAAwB,CACtC,KAAK,EAAE,cAAc,GAAG,SAAS,EACjC,SAAS,EAAE,cAAc,GAAG,SAAS,GACpC,eAAe,CAQjB;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE;IACrC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,KAAK,CAAC,EAAE,OAAO,CAAC;CAC1B,GAAG,aAAa,CAIhB;AAED,oEAAoE;AACpE,QAAA,MAAM,YAAY,qBAAqB,CAAC;AAExC,0DAA0D;AAC1D,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,MAAM,EAAE,OAAO,YAAY,CAAC;IACrC,QAAQ,CAAC,MAAM,EAAE,QAAQ,CAAC;IAC1B,QAAQ,CAAC,KAAK,EAAE;QACd,QAAQ,CAAC,IAAI,EAAE,aAAa,CAAC;QAC7B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;QACzB,QAAQ,CAAC,MAAM,CAAC,EAAE,SAAS,OAAO,EAAE,CAAC;KACtC,CAAC;IACF,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;CAC9B;AAQD,wBAAgB,eAAe,CAC7B,IAAI,EAAE,aAAa,EACnB,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,SAAS,OAAO,EAAE,GAAG,SAAS,GACrC,eAAe,CAOjB;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,SAAS,YAAY,EAAE,GAAG,MAAM,CAU1E"}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
2
|
+
// Copyright (C) 2026 Kindgi Inc.
|
|
3
|
+
import { TOOL_ERROR_KINDS } from '@kindgi/policy-contract';
|
|
4
|
+
import { isRepairMessage } from './structured-output.js';
|
|
5
|
+
/** Without an agent setting: one retry, for failures where nothing ran. */
|
|
6
|
+
export const DEFAULT_TOOL_ERRORS = {
|
|
7
|
+
maxRetries: 1,
|
|
8
|
+
retryOn: ['invalid-arguments', 'unknown-tool'],
|
|
9
|
+
};
|
|
10
|
+
/**
|
|
11
|
+
* The agent's setting (or the default), capped by the tenant's
|
|
12
|
+
* `tool-errors` policy: the fewer retries, and only the kinds both
|
|
13
|
+
* allow — like every tenant policy, it can only make the turn stricter.
|
|
14
|
+
*/
|
|
15
|
+
export function effectiveToolErrorPolicy(agent, tenantCap) {
|
|
16
|
+
const maxRetries = Math.min(agent?.maxRetries ?? DEFAULT_TOOL_ERRORS.maxRetries, tenantCap?.maxRetries ?? Number.POSITIVE_INFINITY);
|
|
17
|
+
const allowed = new Set(tenantCap?.retryOn ?? TOOL_ERROR_KINDS);
|
|
18
|
+
const retryOn = (agent?.retryOn ?? DEFAULT_TOOL_ERRORS.retryOn).filter((k) => allowed.has(k));
|
|
19
|
+
return { maxRetries, retryOn: new Set(retryOn) };
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Which kind of failure a tool call's error is: arguments that failed
|
|
23
|
+
* the input schema, a tool the agent doesn't have, or a tool that ran
|
|
24
|
+
* and failed.
|
|
25
|
+
*/
|
|
26
|
+
export function toolErrorKindOf(error) {
|
|
27
|
+
if (error.code === 'unresolved-tool')
|
|
28
|
+
return 'unknown-tool';
|
|
29
|
+
const inner = error.cause?.code;
|
|
30
|
+
return inner === 'input-validation-failed' ? 'invalid-arguments' : 'tool-error';
|
|
31
|
+
}
|
|
32
|
+
/** Marks the results this module writes, so they can be counted. */
|
|
33
|
+
const RETRY_MARKER = 'tool-error-retry';
|
|
34
|
+
const INSTRUCTIONS = {
|
|
35
|
+
'invalid-arguments': "Fix the arguments to match the tool's input schema and call it again.",
|
|
36
|
+
'unknown-tool': 'Call one of the tools you were given instead.',
|
|
37
|
+
'tool-error': 'The tool failed. Call it again if a retry makes sense, or answer without it.',
|
|
38
|
+
};
|
|
39
|
+
export function toolErrorResult(kind, message, issues) {
|
|
40
|
+
return {
|
|
41
|
+
kindgi: RETRY_MARKER,
|
|
42
|
+
status: 'failed',
|
|
43
|
+
error: { kind, message, ...(issues !== undefined && { issues }) },
|
|
44
|
+
instruction: INSTRUCTIONS[kind],
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Retries this turn has taken: the marked tool results after the turn's
|
|
49
|
+
* user message. Earlier turns' results come back as history; they don't
|
|
50
|
+
* count.
|
|
51
|
+
*/
|
|
52
|
+
export function toolRetriesSoFar(messages) {
|
|
53
|
+
let start = 0;
|
|
54
|
+
for (let i = messages.length - 1; i >= 0; i -= 1) {
|
|
55
|
+
const m = messages[i];
|
|
56
|
+
if (m !== undefined && m.role === 'user' && !isRepairMessage(m)) {
|
|
57
|
+
start = i + 1;
|
|
58
|
+
break;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
return messages.slice(start).filter(isRetryResult).length;
|
|
62
|
+
}
|
|
63
|
+
function isRetryResult(m) {
|
|
64
|
+
if (m.role !== 'tool')
|
|
65
|
+
return false;
|
|
66
|
+
try {
|
|
67
|
+
return JSON.parse(m.content).kindgi === RETRY_MARKER;
|
|
68
|
+
}
|
|
69
|
+
catch {
|
|
70
|
+
return false;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
//# sourceMappingURL=tool-errors.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tool-errors.js","sourceRoot":"","sources":["../../src/handlers/tool-errors.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import type { Tool } from '@kindgi/tools';
|
|
2
|
+
import type { Agent, ToolHitlMode } from '../types.js';
|
|
3
|
+
export interface ResolvedToolHitl {
|
|
4
|
+
readonly mode: ToolHitlMode;
|
|
5
|
+
readonly requiredRole: 'standard' | 'senior' | 'admin';
|
|
6
|
+
}
|
|
7
|
+
export declare function resolveToolHitl(agent: Agent, tool: Tool): ResolvedToolHitl;
|
|
8
|
+
/**
|
|
9
|
+
* Deterministic hash of tool arguments — used as the cache key for
|
|
10
|
+
* `ask_on_first_use`. Sorted-key JSON so reordered args don't produce
|
|
11
|
+
* a different hash.
|
|
12
|
+
*/
|
|
13
|
+
export declare function hashToolArgs(args: unknown): string;
|
|
14
|
+
/**
|
|
15
|
+
* Deterministic waitpoint token for a tool-call gate. Includes both
|
|
16
|
+
* the model-generated call id (unique per iteration) AND the args hash
|
|
17
|
+
* so kernel flow replay lands on the same token, and a re-issued
|
|
18
|
+
* tool-call in a later iteration gets its own gate.
|
|
19
|
+
*/
|
|
20
|
+
export declare function computeToolCallWaitToken(input: {
|
|
21
|
+
readonly runId: string;
|
|
22
|
+
readonly callId: string;
|
|
23
|
+
readonly argsHash: string;
|
|
24
|
+
}): string;
|
|
25
|
+
/**
|
|
26
|
+
* Shape the tool-level waitpoint resolves to when the reviewer decides.
|
|
27
|
+
* Same shape as session-gate decisions — the approvals-complete route
|
|
28
|
+
* materializes it identically.
|
|
29
|
+
*/
|
|
30
|
+
export interface ToolHitlDecision {
|
|
31
|
+
readonly decided: 'approve' | 'reject';
|
|
32
|
+
readonly rationale?: string;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* In-conversation cache of decisions for `ask_on_first_use`. Persisted
|
|
36
|
+
* on `agent_conversations.metadata.hitlToolDecisions` — a flat map of
|
|
37
|
+
* `${toolId}:${argsHash}` → decision. Read/write goes through the
|
|
38
|
+
* conversation row's metadata via the standard update path.
|
|
39
|
+
*/
|
|
40
|
+
export interface ToolDecisionCacheKey {
|
|
41
|
+
readonly toolId: string;
|
|
42
|
+
readonly argsHash: string;
|
|
43
|
+
}
|
|
44
|
+
export declare function cacheKeyFor(key: ToolDecisionCacheKey): string;
|
|
45
|
+
//# sourceMappingURL=tool-hitl.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tool-hitl.d.ts","sourceRoot":"","sources":["../../src/handlers/tool-hitl.ts"],"names":[],"mappings":"AAsBA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,eAAe,CAAC;AAE1C,OAAO,KAAK,EAAE,KAAK,EAAE,YAAY,EAAgB,MAAM,aAAa,CAAC;AAErE,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,IAAI,EAAE,YAAY,CAAC;IAC5B,QAAQ,CAAC,YAAY,EAAE,UAAU,GAAG,QAAQ,GAAG,OAAO,CAAC;CACxD;AAED,wBAAgB,eAAe,CAAC,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,IAAI,GAAG,gBAAgB,CAkC1E;AAED;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,OAAO,GAAG,MAAM,CAElD;AAWD;;;;;GAKG;AACH,wBAAgB,wBAAwB,CAAC,KAAK,EAAE;IAC9C,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;CAC3B,GAAG,MAAM,CAKT;AAED;;;;GAIG;AACH,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,OAAO,EAAE,SAAS,GAAG,QAAQ,CAAC;IACvC,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;CAC7B;AAED;;;;;GAKG;AACH,MAAM,WAAW,oBAAoB;IACnC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;CAC3B;AAED,wBAAgB,WAAW,CAAC,GAAG,EAAE,oBAAoB,GAAG,MAAM,CAE7D"}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
2
|
+
// Copyright (C) 2026 Kindgi Inc.
|
|
3
|
+
//
|
|
4
|
+
// Tool-level HITL — resolves the effective `ToolHitlMode` for a given
|
|
5
|
+
// (agent, tool) pair. Consumed by `dispatch-tools.ts` to
|
|
6
|
+
// decide whether a tool call parks the run on a kernel waitpoint before
|
|
7
|
+
// dispatch.
|
|
8
|
+
//
|
|
9
|
+
// Resolution order (narrower wins, framework default is fail-open):
|
|
10
|
+
// 1. `agent.conversationPolicy.hitl.tools.overrides[toolId]` — exact match
|
|
11
|
+
// 2. `agent.conversationPolicy.hitl.tools.default` — agent-wide default
|
|
12
|
+
// 3. per-tool default from `Tool.mutating` — safe fallback
|
|
13
|
+
// - `mutating: false` → `never_ask`
|
|
14
|
+
// - `mutating: true` or absent → `ask_on_first_use` (defaults safer)
|
|
15
|
+
//
|
|
16
|
+
// The effective-policy resolver (`hitl-policy.ts`) layers the tenant
|
|
17
|
+
// cap on top.
|
|
18
|
+
//
|
|
19
|
+
import { createHash } from 'node:crypto';
|
|
20
|
+
export function resolveToolHitl(agent, tool) {
|
|
21
|
+
const hitl = agent.conversationPolicy?.hitl;
|
|
22
|
+
const toolsPolicy = hitl?.tools;
|
|
23
|
+
const defaultRole = hitl?.defaultReviewerRole ?? 'standard';
|
|
24
|
+
// Opt-in: agents that don't declare `hitl.tools` get no tool-level
|
|
25
|
+
// gates. Matches the design's "fail-open" default — HITL is opt-in
|
|
26
|
+
// at the agent level, not implicit.
|
|
27
|
+
if (toolsPolicy === undefined) {
|
|
28
|
+
return { mode: 'never_ask', requiredRole: defaultRole };
|
|
29
|
+
}
|
|
30
|
+
// 1. Explicit override for this toolId.
|
|
31
|
+
const rawOverride = toolsPolicy.overrides?.[tool.id];
|
|
32
|
+
if (rawOverride !== undefined) {
|
|
33
|
+
const rule = typeof rawOverride === 'string' ? { mode: rawOverride } : rawOverride;
|
|
34
|
+
return {
|
|
35
|
+
mode: rule.mode,
|
|
36
|
+
requiredRole: rule.requiredRole ?? defaultRole,
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
// 2. Agent-wide default.
|
|
40
|
+
if (toolsPolicy.default !== undefined) {
|
|
41
|
+
return { mode: toolsPolicy.default, requiredRole: defaultRole };
|
|
42
|
+
}
|
|
43
|
+
// 3. Per-tool default from Tool.mutating — only reached when
|
|
44
|
+
// `hitl.tools` is present (opt-in) but neither an override nor a
|
|
45
|
+
// default matches. Read-only tools skip the gate; mutating tools
|
|
46
|
+
// ask on first use.
|
|
47
|
+
const mode = tool.mutating === false ? 'never_ask' : 'ask_on_first_use';
|
|
48
|
+
return { mode, requiredRole: defaultRole };
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Deterministic hash of tool arguments — used as the cache key for
|
|
52
|
+
* `ask_on_first_use`. Sorted-key JSON so reordered args don't produce
|
|
53
|
+
* a different hash.
|
|
54
|
+
*/
|
|
55
|
+
export function hashToolArgs(args) {
|
|
56
|
+
return createHash('sha256').update(canonicalStringify(args)).digest('hex').slice(0, 40);
|
|
57
|
+
}
|
|
58
|
+
function canonicalStringify(value) {
|
|
59
|
+
if (value === null || typeof value !== 'object')
|
|
60
|
+
return JSON.stringify(value);
|
|
61
|
+
if (Array.isArray(value))
|
|
62
|
+
return `[${value.map(canonicalStringify).join(',')}]`;
|
|
63
|
+
const entries = Object.entries(value).sort(([a], [b]) => a.localeCompare(b));
|
|
64
|
+
return `{${entries.map(([k, v]) => `${JSON.stringify(k)}:${canonicalStringify(v)}`).join(',')}}`;
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Deterministic waitpoint token for a tool-call gate. Includes both
|
|
68
|
+
* the model-generated call id (unique per iteration) AND the args hash
|
|
69
|
+
* so kernel flow replay lands on the same token, and a re-issued
|
|
70
|
+
* tool-call in a later iteration gets its own gate.
|
|
71
|
+
*/
|
|
72
|
+
export function computeToolCallWaitToken(input) {
|
|
73
|
+
return createHash('sha256')
|
|
74
|
+
.update(`tool-call:${input.runId}:${input.callId}:${input.argsHash}`)
|
|
75
|
+
.digest('hex')
|
|
76
|
+
.slice(0, 40);
|
|
77
|
+
}
|
|
78
|
+
export function cacheKeyFor(key) {
|
|
79
|
+
return `${key.toolId}:${key.argsHash}`;
|
|
80
|
+
}
|
|
81
|
+
//# sourceMappingURL=tool-hitl.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tool-hitl.js","sourceRoot":"","sources":["../../src/handlers/tool-hitl.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { type EffectiveHitlPolicy } from '../hitl-policy.js';
|
|
2
|
+
import type { Conversation } from '../types.js';
|
|
3
|
+
import type { TurnContext } from './context.js';
|
|
4
|
+
/** The conversation the turn runs in: open, and opened with this agent version. */
|
|
5
|
+
export declare function loadTurnConversation(ctx: TurnContext): Promise<Conversation>;
|
|
6
|
+
/** The model a turn was routed to, as `setup` journals it. */
|
|
7
|
+
export interface PinnedRoute {
|
|
8
|
+
readonly providerId: string;
|
|
9
|
+
readonly model: string;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Resolve the turn's guardrails, tools, tenant policy, tool-error policy
|
|
13
|
+
* and model onto `ctx`. With `pinned`, the route is that provider and
|
|
14
|
+
* model, still under the tenant's current policy; one no longer
|
|
15
|
+
* registered or allowed fails the turn.
|
|
16
|
+
*/
|
|
17
|
+
export declare function resolveTurnEnvironment(ctx: TurnContext, pinned?: PinnedRoute): Promise<PinnedRoute & {
|
|
18
|
+
readonly toolCount: number;
|
|
19
|
+
}>;
|
|
20
|
+
/**
|
|
21
|
+
* The turn's approval rules: the agent's, held to the tenant's `hitl`
|
|
22
|
+
* policy. A policy that can't be evaluated fails the turn — running
|
|
23
|
+
* without it would skip the tenant's approvals.
|
|
24
|
+
*/
|
|
25
|
+
export declare function resolveTurnHitlPolicy(ctx: TurnContext): Promise<EffectiveHitlPolicy>;
|
|
26
|
+
//# sourceMappingURL=turn-environment.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"turn-environment.d.ts","sourceRoot":"","sources":["../../src/handlers/turn-environment.ts"],"names":[],"mappings":"AAkBA,OAAO,EAAE,KAAK,mBAAmB,EAA8B,MAAM,mBAAmB,CAAC;AAEzF,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAChD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAKhD,mFAAmF;AACnF,wBAAsB,oBAAoB,CAAC,GAAG,EAAE,WAAW,GAAG,OAAO,CAAC,YAAY,CAAC,CA4BlF;AAED,8DAA8D;AAC9D,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;CACxB;AAED;;;;;GAKG;AACH,wBAAsB,sBAAsB,CAC1C,GAAG,EAAE,WAAW,EAChB,MAAM,CAAC,EAAE,WAAW,GACnB,OAAO,CAAC,WAAW,GAAG;IAAE,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAA;CAAE,CAAC,CAkFvD;AAED;;;;GAIG;AACH,wBAAsB,qBAAqB,CAAC,GAAG,EAAE,WAAW,GAAG,OAAO,CAAC,mBAAmB,CAAC,CAiB1F"}
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
2
|
+
// Copyright (C) 2026 Kindgi Inc.
|
|
3
|
+
/**
|
|
4
|
+
* What a turn runs against: its conversation, and the guardrails, tools,
|
|
5
|
+
* policies and model it resolves at the start. `setup` resolves them
|
|
6
|
+
* once per turn; a resumed turn resolves them again (see
|
|
7
|
+
* `rehydrateTurnContext`), pinned to the model `setup` routed to, since
|
|
8
|
+
* the kernel doesn't re-run a step that already completed and these live
|
|
9
|
+
* on the in-memory `TurnContext`.
|
|
10
|
+
*/
|
|
11
|
+
import { route } from '@kindgi/capabilities';
|
|
12
|
+
import { resolveGuardrails } from '../guardrails-gate.js';
|
|
13
|
+
import { resolveEffectiveHitlPolicy } from '../hitl-policy.js';
|
|
14
|
+
import { mergeTenantPolicies } from '../tenant-policy.js';
|
|
15
|
+
import { throwAgentTurnFailure } from './errors.js';
|
|
16
|
+
import { resolveTurnTools } from './resolve-tools.js';
|
|
17
|
+
import { effectiveToolErrorPolicy } from './tool-errors.js';
|
|
18
|
+
/** The conversation the turn runs in: open, and opened with this agent version. */
|
|
19
|
+
export async function loadTurnConversation(ctx) {
|
|
20
|
+
const conv = await ctx.bindings.conversationBinding.getConversation(ctx.input.tenantId, ctx.input.conversationId);
|
|
21
|
+
if (conv.kind === 'err')
|
|
22
|
+
throwAgentTurnFailure(conv.error);
|
|
23
|
+
if (conv.value.closedAt !== undefined) {
|
|
24
|
+
const err = {
|
|
25
|
+
code: 'conversation-closed',
|
|
26
|
+
message: `Conversation "${ctx.input.conversationId}" is closed`,
|
|
27
|
+
conversationId: ctx.input.conversationId,
|
|
28
|
+
};
|
|
29
|
+
throwAgentTurnFailure(err);
|
|
30
|
+
}
|
|
31
|
+
if (conv.value.agentId !== ctx.input.agent.id ||
|
|
32
|
+
conv.value.agentVersion !== ctx.input.agent.version) {
|
|
33
|
+
throwAgentTurnFailure({
|
|
34
|
+
code: 'agent-version-mismatch',
|
|
35
|
+
message: `Conversation opened with ${conv.value.agentId}@${conv.value.agentVersion}; invoked with ${ctx.input.agent.id}@${ctx.input.agent.version}`,
|
|
36
|
+
conversationId: ctx.input.conversationId,
|
|
37
|
+
expectedVersion: conv.value.agentVersion,
|
|
38
|
+
actualVersion: ctx.input.agent.version,
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
ctx.conversation = conv.value;
|
|
42
|
+
return conv.value;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Resolve the turn's guardrails, tools, tenant policy, tool-error policy
|
|
46
|
+
* and model onto `ctx`. With `pinned`, the route is that provider and
|
|
47
|
+
* model, still under the tenant's current policy; one no longer
|
|
48
|
+
* registered or allowed fails the turn.
|
|
49
|
+
*/
|
|
50
|
+
export async function resolveTurnEnvironment(ctx, pinned) {
|
|
51
|
+
const invResolution = resolveGuardrails(ctx.input.agent, ctx.bindings);
|
|
52
|
+
if (invResolution.missing.length > 0) {
|
|
53
|
+
throwAgentTurnFailure({
|
|
54
|
+
code: 'unresolved-guardrail',
|
|
55
|
+
message: `Agent "${ctx.input.agent.id}" references guardrails not in the registry: ${invResolution.missing.join(', ')}`,
|
|
56
|
+
guardrailIds: invResolution.missing,
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
ctx.guardrails = invResolution.resolved;
|
|
60
|
+
// This turn's tools come from the tenant's own registry — never a
|
|
61
|
+
// registry shared across concurrent turns of other tenants.
|
|
62
|
+
const tenantTools = await ctx.bindings.toolRegistry.forTenant(ctx.input.tenantId);
|
|
63
|
+
ctx.tools = resolveTurnTools(tenantTools, ctx.input.agent);
|
|
64
|
+
const capability = ctx.input.agent.capabilities[0];
|
|
65
|
+
if (capability === undefined) {
|
|
66
|
+
throwAgentTurnFailure({
|
|
67
|
+
code: 'capability-routing-failed',
|
|
68
|
+
message: `Agent "${ctx.input.agent.id}" has no capabilities declared`,
|
|
69
|
+
cause: null,
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
// Merge the static tenant policy with the one derived from the
|
|
73
|
+
// policy registry (if wired); the result is at least as strict as
|
|
74
|
+
// each (see `mergeTenantPolicies`).
|
|
75
|
+
const derivedPolicy = ctx.bindings.policyRegistry !== undefined
|
|
76
|
+
? await ctx.bindings.policyRegistry.evaluate('model-routing', { tenantId: ctx.input.tenantId })
|
|
77
|
+
: undefined;
|
|
78
|
+
const effectivePolicy = mergeTenantPolicies(ctx.bindings.tenantPolicy, derivedPolicy);
|
|
79
|
+
if (effectivePolicy !== undefined)
|
|
80
|
+
ctx.tenantPolicy = effectivePolicy;
|
|
81
|
+
ctx.toolErrorPolicy = await resolveToolErrorPolicy(ctx);
|
|
82
|
+
// Storage-backed registries need an async hydration
|
|
83
|
+
// step before the sync `list(tenantId)` call — they read persisted
|
|
84
|
+
// providers from `ProviderRegistryBinding` and instantiate each via
|
|
85
|
+
// its adapter factory. In-memory implementations (dev-echo,
|
|
86
|
+
// tests) leave `hydrate` undefined and this is a no-op.
|
|
87
|
+
if (ctx.bindings.providerRegistry.hydrate !== undefined) {
|
|
88
|
+
await ctx.bindings.providerRegistry.hydrate(ctx.input.tenantId);
|
|
89
|
+
}
|
|
90
|
+
// A pinned route narrows the policy to exactly that provider and model.
|
|
91
|
+
const routingPolicy = pinned === undefined
|
|
92
|
+
? effectivePolicy
|
|
93
|
+
: mergeTenantPolicies(effectivePolicy, {
|
|
94
|
+
tenantId: ctx.input.tenantId,
|
|
95
|
+
providers: { allow: [pinned.providerId] },
|
|
96
|
+
models: { allow: [pinned.model] },
|
|
97
|
+
});
|
|
98
|
+
const routed = route({
|
|
99
|
+
capability,
|
|
100
|
+
providers: ctx.bindings.providerRegistry.list(ctx.input.tenantId),
|
|
101
|
+
...(routingPolicy !== undefined && { tenantPolicy: routingPolicy }),
|
|
102
|
+
...(ctx.input.agent.preferredProvider !== undefined && {
|
|
103
|
+
preferredProvider: ctx.input.agent.preferredProvider,
|
|
104
|
+
}),
|
|
105
|
+
...(ctx.input.agent.preferredModel !== undefined && {
|
|
106
|
+
preferredModel: ctx.input.agent.preferredModel,
|
|
107
|
+
}),
|
|
108
|
+
});
|
|
109
|
+
if (routed.kind === 'err') {
|
|
110
|
+
throwAgentTurnFailure({
|
|
111
|
+
code: 'capability-routing-failed',
|
|
112
|
+
message: pinned === undefined
|
|
113
|
+
? routed.error.message
|
|
114
|
+
: `The turn was routed to ${pinned.providerId}/${pinned.model}, which is no longer registered or allowed: ${routed.error.message}`,
|
|
115
|
+
cause: routed.error,
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
ctx.provider = routed.value.provider;
|
|
119
|
+
ctx.model = routed.value.model;
|
|
120
|
+
return {
|
|
121
|
+
providerId: routed.value.provider.metadata.id,
|
|
122
|
+
model: routed.value.model.name,
|
|
123
|
+
toolCount: ctx.tools.definitions.length,
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* The turn's approval rules: the agent's, held to the tenant's `hitl`
|
|
128
|
+
* policy. A policy that can't be evaluated fails the turn — running
|
|
129
|
+
* without it would skip the tenant's approvals.
|
|
130
|
+
*/
|
|
131
|
+
export async function resolveTurnHitlPolicy(ctx) {
|
|
132
|
+
let tenant;
|
|
133
|
+
if (ctx.bindings.policyRegistry !== undefined) {
|
|
134
|
+
try {
|
|
135
|
+
tenant = await ctx.bindings.policyRegistry.evaluate('hitl', { tenantId: ctx.input.tenantId });
|
|
136
|
+
}
|
|
137
|
+
catch (cause) {
|
|
138
|
+
throwAgentTurnFailure({
|
|
139
|
+
code: 'tenant-policy-unavailable',
|
|
140
|
+
message: `The tenant's hitl policy could not be applied: ${cause instanceof Error ? cause.message : String(cause)}`,
|
|
141
|
+
policyKind: 'hitl',
|
|
142
|
+
});
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
return resolveEffectiveHitlPolicy({ tenant, agent: ctx.input.agent });
|
|
146
|
+
}
|
|
147
|
+
/** The agent's `toolErrors`, capped by the tenant's `tool-errors` policy. */
|
|
148
|
+
async function resolveToolErrorPolicy(ctx) {
|
|
149
|
+
const cap = ctx.bindings.policyRegistry !== undefined
|
|
150
|
+
? await ctx.bindings.policyRegistry.evaluate('tool-errors', { tenantId: ctx.input.tenantId })
|
|
151
|
+
: undefined;
|
|
152
|
+
return effectiveToolErrorPolicy(ctx.input.agent.toolErrors, cap);
|
|
153
|
+
}
|
|
154
|
+
//# sourceMappingURL=turn-environment.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"turn-environment.js","sourceRoot":"","sources":["../../src/handlers/turn-environment.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { type HitlSpec } from '@kindgi/policy-contract';
|
|
2
|
+
import type { Agent, ToolHitlMode, ToolHitlRule } from './types.js';
|
|
3
|
+
export interface EffectiveHitlPolicy {
|
|
4
|
+
/**
|
|
5
|
+
* Session-turn count gate. Absent = no session gate.
|
|
6
|
+
* Merged from `agent.conversationPolicy.hitl.afterTurns` and
|
|
7
|
+
* `agent.conversationPolicy.hitlAfterTurns` (either fires;
|
|
8
|
+
* `hitl.afterTurns` wins when both are set).
|
|
9
|
+
*/
|
|
10
|
+
readonly turn?: {
|
|
11
|
+
readonly afterTurns: number;
|
|
12
|
+
};
|
|
13
|
+
/**
|
|
14
|
+
* Tool-level policy. Absent = no tool gates (agents opt in
|
|
15
|
+
* explicitly). Same shape as `agent.conversationPolicy.hitl.tools`,
|
|
16
|
+
* with string overrides normalized to rules and tenant overrides
|
|
17
|
+
* applied; the per-tool default (from `Tool.mutating`) is applied at
|
|
18
|
+
* dispatch time.
|
|
19
|
+
*/
|
|
20
|
+
readonly tools?: {
|
|
21
|
+
readonly default?: ToolHitlMode;
|
|
22
|
+
readonly overrides: ReadonlyMap<string, ToolHitlRule>;
|
|
23
|
+
};
|
|
24
|
+
/**
|
|
25
|
+
* The tenant's per-tool rules: a floor under the agent's gate for
|
|
26
|
+
* that tool. A tool's gate is the stricter of the two; tools the
|
|
27
|
+
* tenant names nothing for keep the agent's.
|
|
28
|
+
*/
|
|
29
|
+
readonly toolFloors?: ReadonlyMap<string, ToolHitlRule>;
|
|
30
|
+
readonly defaultReviewerRole: 'standard' | 'senior' | 'admin';
|
|
31
|
+
/** Millisecond timeout used at enqueue time. */
|
|
32
|
+
readonly timeoutMs: number;
|
|
33
|
+
readonly onTimeout: 'auto-approve' | 'auto-reject' | 'escalate';
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Compute the effective HITL policy for a given (tenant, agent) pair:
|
|
37
|
+
* framework defaults overlaid with the agent's policy, then held to the
|
|
38
|
+
* tenant's `hitl` policy (only stricter). `tenant: undefined` — the
|
|
39
|
+
* tenant has none.
|
|
40
|
+
*/
|
|
41
|
+
export declare function resolveEffectiveHitlPolicy(input: {
|
|
42
|
+
readonly tenant: HitlSpec | undefined;
|
|
43
|
+
readonly agent: Agent;
|
|
44
|
+
}): EffectiveHitlPolicy;
|
|
45
|
+
//# sourceMappingURL=hitl-policy.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hitl-policy.d.ts","sourceRoot":"","sources":["../src/hitl-policy.ts"],"names":[],"mappings":"AAmBA,OAAO,EAAE,KAAK,QAAQ,EAA4B,MAAM,yBAAyB,CAAC;AAElF,OAAO,KAAK,EAAE,KAAK,EAA0B,YAAY,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAE5F,MAAM,WAAW,mBAAmB;IAClC;;;;;OAKG;IACH,QAAQ,CAAC,IAAI,CAAC,EAAE;QAAE,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAA;KAAE,CAAC;IAChD;;;;;;OAMG;IACH,QAAQ,CAAC,KAAK,CAAC,EAAE;QACf,QAAQ,CAAC,OAAO,CAAC,EAAE,YAAY,CAAC;QAChC,QAAQ,CAAC,SAAS,EAAE,WAAW,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC;KACvD,CAAC;IACF;;;;OAIG;IACH,QAAQ,CAAC,UAAU,CAAC,EAAE,WAAW,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC;IACxD,QAAQ,CAAC,mBAAmB,EAAE,UAAU,GAAG,QAAQ,GAAG,OAAO,CAAC;IAC9D,gDAAgD;IAChD,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,SAAS,EAAE,cAAc,GAAG,aAAa,GAAG,UAAU,CAAC;CACjE;AAYD;;;;;GAKG;AACH,wBAAgB,0BAA0B,CAAC,KAAK,EAAE;IAChD,QAAQ,CAAC,MAAM,EAAE,QAAQ,GAAG,SAAS,CAAC;IACtC,QAAQ,CAAC,KAAK,EAAE,KAAK,CAAC;CACvB,GAAG,mBAAmB,CAsDtB"}
|