@aid-framework/ir 0.0.0 → 0.1.39
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 +135 -0
- package/dist/.tsbuildinfo +1 -0
- package/dist/build.d.ts +74 -0
- package/dist/build.d.ts.map +1 -0
- package/dist/build.js +1079 -0
- package/dist/build.js.map +1 -0
- package/dist/capabilities.d.ts +65 -0
- package/dist/capabilities.d.ts.map +1 -0
- package/dist/capabilities.js +176 -0
- package/dist/capabilities.js.map +1 -0
- package/dist/catalog/index.d.ts +36 -0
- package/dist/catalog/index.d.ts.map +1 -0
- package/dist/catalog/index.js +43 -0
- package/dist/catalog/index.js.map +1 -0
- package/dist/catalog/models.json +52 -0
- package/dist/diagnostics.d.ts +90 -0
- package/dist/diagnostics.d.ts.map +1 -0
- package/dist/diagnostics.js +103 -0
- package/dist/diagnostics.js.map +1 -0
- package/dist/gates/agents.d.ts +34 -0
- package/dist/gates/agents.d.ts.map +1 -0
- package/dist/gates/agents.js +233 -0
- package/dist/gates/agents.js.map +1 -0
- package/dist/gates/capability.d.ts +15 -0
- package/dist/gates/capability.d.ts.map +1 -0
- package/dist/gates/capability.js +81 -0
- package/dist/gates/capability.js.map +1 -0
- package/dist/gates/contract.d.ts +35 -0
- package/dist/gates/contract.d.ts.map +1 -0
- package/dist/gates/contract.js +19 -0
- package/dist/gates/contract.js.map +1 -0
- package/dist/gates/cost.d.ts +40 -0
- package/dist/gates/cost.d.ts.map +1 -0
- package/dist/gates/cost.js +167 -0
- package/dist/gates/cost.js.map +1 -0
- package/dist/gates/deploy.d.ts +23 -0
- package/dist/gates/deploy.d.ts.map +1 -0
- package/dist/gates/deploy.js +44 -0
- package/dist/gates/deploy.js.map +1 -0
- package/dist/gates/eval-coverage.d.ts +11 -0
- package/dist/gates/eval-coverage.d.ts.map +1 -0
- package/dist/gates/eval-coverage.js +50 -0
- package/dist/gates/eval-coverage.js.map +1 -0
- package/dist/gates/guardrails.d.ts +24 -0
- package/dist/gates/guardrails.d.ts.map +1 -0
- package/dist/gates/guardrails.js +112 -0
- package/dist/gates/guardrails.js.map +1 -0
- package/dist/gates/hitl.d.ts +17 -0
- package/dist/gates/hitl.d.ts.map +1 -0
- package/dist/gates/hitl.js +40 -0
- package/dist/gates/hitl.js.map +1 -0
- package/dist/gates/index.d.ts +66 -0
- package/dist/gates/index.d.ts.map +1 -0
- package/dist/gates/index.js +77 -0
- package/dist/gates/index.js.map +1 -0
- package/dist/gates/memory.d.ts +13 -0
- package/dist/gates/memory.d.ts.map +1 -0
- package/dist/gates/memory.js +67 -0
- package/dist/gates/memory.js.map +1 -0
- package/dist/gates/normalize.d.ts +26 -0
- package/dist/gates/normalize.d.ts.map +1 -0
- package/dist/gates/normalize.js +228 -0
- package/dist/gates/normalize.js.map +1 -0
- package/dist/gates/orchestration.d.ts +17 -0
- package/dist/gates/orchestration.d.ts.map +1 -0
- package/dist/gates/orchestration.js +46 -0
- package/dist/gates/orchestration.js.map +1 -0
- package/dist/gates/referential.d.ts +12 -0
- package/dist/gates/referential.d.ts.map +1 -0
- package/dist/gates/referential.js +554 -0
- package/dist/gates/referential.js.map +1 -0
- package/dist/gates/security.d.ts +22 -0
- package/dist/gates/security.d.ts.map +1 -0
- package/dist/gates/security.js +225 -0
- package/dist/gates/security.js.map +1 -0
- package/dist/index.d.ts +27 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +19 -0
- package/dist/index.js.map +1 -0
- package/dist/policy/ast.d.ts +61 -0
- package/dist/policy/ast.d.ts.map +1 -0
- package/dist/policy/ast.js +48 -0
- package/dist/policy/ast.js.map +1 -0
- package/dist/policy/index.d.ts +7 -0
- package/dist/policy/index.d.ts.map +1 -0
- package/dist/policy/index.js +4 -0
- package/dist/policy/index.js.map +1 -0
- package/dist/policy/lexer.d.ts +27 -0
- package/dist/policy/lexer.d.ts.map +1 -0
- package/dist/policy/lexer.js +147 -0
- package/dist/policy/lexer.js.map +1 -0
- package/dist/policy/parser.d.ts +15 -0
- package/dist/policy/parser.d.ts.map +1 -0
- package/dist/policy/parser.js +202 -0
- package/dist/policy/parser.js.map +1 -0
- package/dist/predicate/ast.d.ts +125 -0
- package/dist/predicate/ast.d.ts.map +1 -0
- package/dist/predicate/ast.js +111 -0
- package/dist/predicate/ast.js.map +1 -0
- package/dist/predicate/index.d.ts +7 -0
- package/dist/predicate/index.d.ts.map +1 -0
- package/dist/predicate/index.js +4 -0
- package/dist/predicate/index.js.map +1 -0
- package/dist/predicate/lexer.d.ts +30 -0
- package/dist/predicate/lexer.d.ts.map +1 -0
- package/dist/predicate/lexer.js +176 -0
- package/dist/predicate/lexer.js.map +1 -0
- package/dist/predicate/parser.d.ts +16 -0
- package/dist/predicate/parser.d.ts.map +1 -0
- package/dist/predicate/parser.js +317 -0
- package/dist/predicate/parser.js.map +1 -0
- package/dist/schema/ir.schema.json +1144 -0
- package/dist/serialize.d.ts +15 -0
- package/dist/serialize.d.ts.map +1 -0
- package/dist/serialize.js +53 -0
- package/dist/serialize.js.map +1 -0
- package/dist/shapes.d.ts +671 -0
- package/dist/shapes.d.ts.map +1 -0
- package/dist/shapes.js +159 -0
- package/dist/shapes.js.map +1 -0
- package/package.json +44 -14
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The IR layer's diagnostic codes and factories. Codes are namespaced `ir/<slug>`
|
|
3
|
+
* and are part of the public contract, exactly like the spec layer's `spec/*`.
|
|
4
|
+
*/
|
|
5
|
+
import { errorDiagnostic, warningDiagnostic, } from '@aid-framework/spec';
|
|
6
|
+
/** Every diagnostic code this package emits. */
|
|
7
|
+
export const IR_DIAGNOSTIC_CODES = {
|
|
8
|
+
typeUnresolved: 'ir/type-unresolved',
|
|
9
|
+
typeCycle: 'ir/type-cycle',
|
|
10
|
+
refUnresolved: 'ir/ref-unresolved',
|
|
11
|
+
refKindMismatch: 'ir/ref-kind-mismatch',
|
|
12
|
+
evalTargetInvalid: 'ir/eval-target-invalid',
|
|
13
|
+
fallbackCycle: 'ir/fallback-cycle',
|
|
14
|
+
metricToolUnresolved: 'ir/metric-tool-unresolved',
|
|
15
|
+
promptVariableUndeclared: 'ir/prompt-variable-undeclared',
|
|
16
|
+
promptVariableUnused: 'ir/prompt-variable-unused',
|
|
17
|
+
promptInputMissing: 'ir/prompt-input-missing',
|
|
18
|
+
bindingDuplicate: 'ir/binding-duplicate',
|
|
19
|
+
bindingForwardReference: 'ir/binding-forward-reference',
|
|
20
|
+
normalizationIncomplete: 'ir/normalization-incomplete',
|
|
21
|
+
dimensionMismatch: 'ir/dimension-mismatch',
|
|
22
|
+
indexMetricUnknown: 'ir/index-metric-unknown',
|
|
23
|
+
paramExceedsLimit: 'ir/param-exceeds-limit',
|
|
24
|
+
providerUnsupported: 'ir/provider-unsupported',
|
|
25
|
+
targetUnknown: 'ir/target-unknown',
|
|
26
|
+
capabilityUnknown: 'ir/capability-unknown',
|
|
27
|
+
capabilityMissing: 'ir/capability-missing',
|
|
28
|
+
modelCapabilityMissing: 'ir/model-capability-missing',
|
|
29
|
+
costProfileUnknown: 'ir/cost-profile-unknown',
|
|
30
|
+
costBudgetExceeded: 'ir/cost-budget-exceeded',
|
|
31
|
+
securityMissingAuth: 'ir/security-missing-auth',
|
|
32
|
+
securityMissingConfirmation: 'ir/security-missing-confirmation',
|
|
33
|
+
securityRedactionIncomplete: 'ir/security-redaction-incomplete',
|
|
34
|
+
securityUnauthenticatedPath: 'ir/security-unauthenticated-path',
|
|
35
|
+
securityStoreSecret: 'ir/security-store-secret',
|
|
36
|
+
securityInputGuardrail: 'ir/security-input-guardrail',
|
|
37
|
+
agentsRefUnresolved: 'ir/agents-ref-unresolved',
|
|
38
|
+
agentsHandoffCycle: 'ir/agents-handoff-cycle',
|
|
39
|
+
agentsBudget: 'ir/agents-budget',
|
|
40
|
+
agentsBudgetDegrade: 'ir/agents-budget-degrade',
|
|
41
|
+
guardrailCoverage: 'ir/guardrail-coverage',
|
|
42
|
+
guardrailPolicy: 'ir/guardrail-policy',
|
|
43
|
+
hitlSideEffect: 'ir/hitl-side-effect',
|
|
44
|
+
memoryRef: 'ir/memory-ref',
|
|
45
|
+
deployStreaming: 'ir/deploy-streaming',
|
|
46
|
+
orchestrationDeepagents: 'ir/orchestration-deepagents',
|
|
47
|
+
evalUncovered: 'ir/eval-uncovered',
|
|
48
|
+
gateFailed: 'ir/gate-failed',
|
|
49
|
+
policyEmpty: 'ir/policy-empty',
|
|
50
|
+
policySyntax: 'ir/policy-syntax',
|
|
51
|
+
policyUnknownBuiltin: 'ir/policy-unknown-builtin',
|
|
52
|
+
policyUnknownIdentifier: 'ir/policy-unknown-identifier',
|
|
53
|
+
policyUnterminatedString: 'ir/policy-unterminated-string',
|
|
54
|
+
policyUnclosedParen: 'ir/policy-unclosed-paren',
|
|
55
|
+
policyTrailingToken: 'ir/policy-trailing-token',
|
|
56
|
+
policyArity: 'ir/policy-arity',
|
|
57
|
+
policyArgumentType: 'ir/policy-argument-type',
|
|
58
|
+
policyExpected: 'ir/policy-expected',
|
|
59
|
+
predicateEmpty: 'ir/predicate-empty',
|
|
60
|
+
predicateSyntax: 'ir/predicate-syntax',
|
|
61
|
+
predicateUnknownBuiltin: 'ir/predicate-unknown-builtin',
|
|
62
|
+
predicateUnknownPath: 'ir/predicate-unknown-path',
|
|
63
|
+
predicateUnterminatedString: 'ir/predicate-unterminated-string',
|
|
64
|
+
predicateUnclosedParen: 'ir/predicate-unclosed-paren',
|
|
65
|
+
predicateTrailingToken: 'ir/predicate-trailing-token',
|
|
66
|
+
predicateArity: 'ir/predicate-arity',
|
|
67
|
+
predicateExpected: 'ir/predicate-expected',
|
|
68
|
+
predicateNotBoolean: 'ir/predicate-not-boolean',
|
|
69
|
+
};
|
|
70
|
+
/** `C` infers from the `code` field, so call sites need no explicit type argument. */
|
|
71
|
+
export function irError(init) {
|
|
72
|
+
return errorDiagnostic(init);
|
|
73
|
+
}
|
|
74
|
+
export function irWarning(init) {
|
|
75
|
+
return warningDiagnostic(init);
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* The shared init carries only what a factory needs, so the source position a
|
|
79
|
+
* policy error points at is attached to the finished diagnostic instead.
|
|
80
|
+
*/
|
|
81
|
+
export function withPosition(diagnostic, position) {
|
|
82
|
+
const located = { ...diagnostic };
|
|
83
|
+
if (position.file !== undefined)
|
|
84
|
+
located.file = position.file;
|
|
85
|
+
if (position.line !== undefined)
|
|
86
|
+
located.line = position.line;
|
|
87
|
+
if (position.column !== undefined)
|
|
88
|
+
located.column = position.column;
|
|
89
|
+
return located;
|
|
90
|
+
}
|
|
91
|
+
/** 1-based line/column of a 0-based offset, for position-bearing policy errors. */
|
|
92
|
+
export function offsetPosition(source, offset) {
|
|
93
|
+
let line = 1;
|
|
94
|
+
let lineStart = 0;
|
|
95
|
+
for (let index = 0; index < offset && index < source.length; index += 1) {
|
|
96
|
+
if (source[index] === '\n') {
|
|
97
|
+
line += 1;
|
|
98
|
+
lineStart = index + 1;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
return { line, column: offset - lineStart + 1 };
|
|
102
|
+
}
|
|
103
|
+
//# sourceMappingURL=diagnostics.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"diagnostics.js","sourceRoot":"","sources":["../src/diagnostics.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Agents — four separate gates, because they answer four different questions.
|
|
3
|
+
*
|
|
4
|
+
* `agents/refs-resolve`: every name an agent uses exists. An agent whose tool or
|
|
5
|
+
* guardrail does not resolve is not a partially-working agent; it is a runtime
|
|
6
|
+
* failure that would surface only on the first request that reaches the missing
|
|
7
|
+
* branch, so it fails at build time instead.
|
|
8
|
+
*
|
|
9
|
+
* `agents/handoff-cycles`: handoffs form a graph, and a cycle in it is an unbounded
|
|
10
|
+
* transfer loop. Lexical cycles are reported once per cycle, at the agent that closes
|
|
11
|
+
* it, because reporting every member would multiply one defect into N diagnostics.
|
|
12
|
+
*
|
|
13
|
+
* `agents/budgets`: an agent that can take more than one step must say what stops it.
|
|
14
|
+
* Phase 2 L1 has no runtime, so this is the only place a runaway loop can be caught,
|
|
15
|
+
* and "no budget declared" is read as "unbounded", never as "some default".
|
|
16
|
+
*
|
|
17
|
+
* `agents/budget-degrade`: `onBudgetExhausted: degrade` is a promise that a budget
|
|
18
|
+
* breach has somewhere cheaper to go. Degrade only helps against a *cost* ceiling
|
|
19
|
+
* (switching aliases does not make tokens cheaper), and it can only be proven if the
|
|
20
|
+
* model's declared fallbacks contain one whose pinned cost is strictly lower. An
|
|
21
|
+
* agent that asks for degrade without either would fail at run time, on the one path
|
|
22
|
+
* the field was added to survive, so it fails here instead.
|
|
23
|
+
*/
|
|
24
|
+
import type { IR } from '../shapes.js';
|
|
25
|
+
import { type GateOptions, type GateResult } from './contract.js';
|
|
26
|
+
export declare function agentsRefsGate(ir: IR, options: GateOptions): GateResult;
|
|
27
|
+
export declare function agentsHandoffGate(ir: IR, options: GateOptions): GateResult;
|
|
28
|
+
export declare function agentsBudgetGate(ir: IR, options: GateOptions): GateResult;
|
|
29
|
+
/**
|
|
30
|
+
* A degrade request must have somewhere cheaper to go, and that somewhere must be
|
|
31
|
+
* provable from the pinned cost profiles rather than assumed.
|
|
32
|
+
*/
|
|
33
|
+
export declare function agentsBudgetDegradeGate(ir: IR, options: GateOptions): GateResult;
|
|
34
|
+
//# sourceMappingURL=agents.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"agents.d.ts","sourceRoot":"","sources":["../../src/gates/agents.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAGH,OAAO,KAAK,EAAc,EAAE,EAAE,MAAM,cAAc,CAAC;AACnD,OAAO,EAAE,KAAK,WAAW,EAAE,KAAK,UAAU,EAA6B,MAAM,eAAe,CAAC;AAe7F,wBAAgB,cAAc,CAAC,EAAE,EAAE,EAAE,EAAE,OAAO,EAAE,WAAW,GAAG,UAAU,CAuCvE;AAoBD,wBAAgB,iBAAiB,CAAC,EAAE,EAAE,EAAE,EAAE,OAAO,EAAE,WAAW,GAAG,UAAU,CAyC1E;AAED,wBAAgB,gBAAgB,CAAC,EAAE,EAAE,EAAE,EAAE,OAAO,EAAE,WAAW,GAAG,UAAU,CAmDzE;AAED;;;GAGG;AACH,wBAAgB,uBAAuB,CAAC,EAAE,EAAE,EAAE,EAAE,OAAO,EAAE,WAAW,GAAG,UAAU,CAkChF"}
|
|
@@ -0,0 +1,233 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Agents — four separate gates, because they answer four different questions.
|
|
3
|
+
*
|
|
4
|
+
* `agents/refs-resolve`: every name an agent uses exists. An agent whose tool or
|
|
5
|
+
* guardrail does not resolve is not a partially-working agent; it is a runtime
|
|
6
|
+
* failure that would surface only on the first request that reaches the missing
|
|
7
|
+
* branch, so it fails at build time instead.
|
|
8
|
+
*
|
|
9
|
+
* `agents/handoff-cycles`: handoffs form a graph, and a cycle in it is an unbounded
|
|
10
|
+
* transfer loop. Lexical cycles are reported once per cycle, at the agent that closes
|
|
11
|
+
* it, because reporting every member would multiply one defect into N diagnostics.
|
|
12
|
+
*
|
|
13
|
+
* `agents/budgets`: an agent that can take more than one step must say what stops it.
|
|
14
|
+
* Phase 2 L1 has no runtime, so this is the only place a runaway loop can be caught,
|
|
15
|
+
* and "no budget declared" is read as "unbounded", never as "some default".
|
|
16
|
+
*
|
|
17
|
+
* `agents/budget-degrade`: `onBudgetExhausted: degrade` is a promise that a budget
|
|
18
|
+
* breach has somewhere cheaper to go. Degrade only helps against a *cost* ceiling
|
|
19
|
+
* (switching aliases does not make tokens cheaper), and it can only be proven if the
|
|
20
|
+
* model's declared fallbacks contain one whose pinned cost is strictly lower. An
|
|
21
|
+
* agent that asks for degrade without either would fail at run time, on the one path
|
|
22
|
+
* the field was added to survive, so it fails here instead.
|
|
23
|
+
*/
|
|
24
|
+
import { IR_DIAGNOSTIC_CODES } from '../diagnostics.js';
|
|
25
|
+
import { NO_SUPPRESSIONS, reporter } from './contract.js';
|
|
26
|
+
/** What each agent field refers to, so one loop can check all six collections. */
|
|
27
|
+
const REF_FIELDS = [
|
|
28
|
+
{ field: 'instructions', section: 'prompts', kind: 'prompt' },
|
|
29
|
+
{ field: 'model', section: 'models', kind: 'model' },
|
|
30
|
+
{ field: 'retrievers', section: 'retrievers', kind: 'retriever' },
|
|
31
|
+
{ field: 'memory', section: 'memory', kind: 'memory tier' },
|
|
32
|
+
{ field: 'guardrails', section: 'guardrails', kind: 'guardrail' },
|
|
33
|
+
{ field: 'handoffs', section: 'agents', kind: 'agent' },
|
|
34
|
+
{ field: 'delegates', section: 'agents', kind: 'agent' },
|
|
35
|
+
];
|
|
36
|
+
export function agentsRefsGate(ir, options) {
|
|
37
|
+
const diagnostics = [];
|
|
38
|
+
const report = reporter(options);
|
|
39
|
+
for (const { field, section, kind } of REF_FIELDS) {
|
|
40
|
+
const declared = new Set(ir[section].map((entry) => entry.id));
|
|
41
|
+
const available = [...declared].sort();
|
|
42
|
+
for (const agent of ir.agents) {
|
|
43
|
+
const value = agent[field];
|
|
44
|
+
if (Array.isArray(value)) {
|
|
45
|
+
for (const ref of value) {
|
|
46
|
+
if (declared.has(ref))
|
|
47
|
+
continue;
|
|
48
|
+
diagnostics.push(report.error({
|
|
49
|
+
code: IR_DIAGNOSTIC_CODES.agentsRefUnresolved,
|
|
50
|
+
message: `the agents gate rejected "${agent.id}": ${field} names "${ref}", which is not a declared ${kind}`,
|
|
51
|
+
path: ['agents', agent.id, field],
|
|
52
|
+
hint: `declared ${kind}s: ${available.join(', ') || 'none'}`,
|
|
53
|
+
}));
|
|
54
|
+
}
|
|
55
|
+
continue;
|
|
56
|
+
}
|
|
57
|
+
if (typeof value !== 'string' || value === '' || declared.has(value))
|
|
58
|
+
continue;
|
|
59
|
+
diagnostics.push(report.error({
|
|
60
|
+
code: IR_DIAGNOSTIC_CODES.agentsRefUnresolved,
|
|
61
|
+
message: `the agents gate rejected "${agent.id}": ${field} names "${value}", which is not a declared ${kind}`,
|
|
62
|
+
path: ['agents', agent.id, field],
|
|
63
|
+
hint: `declared ${kind}s: ${available.join(', ') || 'none'}`,
|
|
64
|
+
}));
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
checkToolRefs(ir, diagnostics, report);
|
|
68
|
+
return { diagnostics, suppressed: NO_SUPPRESSIONS };
|
|
69
|
+
}
|
|
70
|
+
/** Tools are a field of their own: an agent may use none, but never a phantom one. */
|
|
71
|
+
function checkToolRefs(ir, diagnostics, report) {
|
|
72
|
+
const declared = new Set(ir.tools.map((tool) => tool.id));
|
|
73
|
+
for (const agent of ir.agents) {
|
|
74
|
+
for (const ref of agent.tools) {
|
|
75
|
+
if (declared.has(ref))
|
|
76
|
+
continue;
|
|
77
|
+
diagnostics.push(report.error({
|
|
78
|
+
code: IR_DIAGNOSTIC_CODES.agentsRefUnresolved,
|
|
79
|
+
message: `the agents gate rejected "${agent.id}": tools names "${ref}", which is not a declared tool`,
|
|
80
|
+
path: ['agents', agent.id, 'tools'],
|
|
81
|
+
hint: `declared tools: ${[...declared].sort().join(', ') || 'none'}`,
|
|
82
|
+
}));
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
export function agentsHandoffGate(ir, options) {
|
|
87
|
+
const diagnostics = [];
|
|
88
|
+
const report = reporter(options);
|
|
89
|
+
const byId = new Map(ir.agents.map((agent) => [agent.id, agent]));
|
|
90
|
+
// `visiting` is the DFS stack, `done` the agents whose subtree is proven acyclic.
|
|
91
|
+
const visiting = [];
|
|
92
|
+
const done = new Set();
|
|
93
|
+
const reported = new Set();
|
|
94
|
+
const walk = (agent) => {
|
|
95
|
+
if (done.has(agent.id))
|
|
96
|
+
return;
|
|
97
|
+
visiting.push(agent.id);
|
|
98
|
+
for (const next of agent.handoffs) {
|
|
99
|
+
const target = byId.get(next);
|
|
100
|
+
// A missing handoff target is `agents/refs-resolve`'s diagnostic, not ours.
|
|
101
|
+
if (target === undefined)
|
|
102
|
+
continue;
|
|
103
|
+
const at = visiting.indexOf(next);
|
|
104
|
+
if (at !== -1) {
|
|
105
|
+
const cycle = [...visiting.slice(at), next];
|
|
106
|
+
const key = [...cycle].sort().join('>');
|
|
107
|
+
if (reported.has(key))
|
|
108
|
+
continue;
|
|
109
|
+
reported.add(key);
|
|
110
|
+
diagnostics.push(report.error({
|
|
111
|
+
code: IR_DIAGNOSTIC_CODES.agentsHandoffCycle,
|
|
112
|
+
message: `the agents gate rejected a handoff cycle: ${cycle.join(' -> ')}; a handoff transfers the conversation and never returns, so a cycle is an unbounded transfer`,
|
|
113
|
+
path: ['agents', visiting[at] ?? next, 'handoffs'],
|
|
114
|
+
hint: 'use delegates for a sub-task that returns to the caller, or break the cycle',
|
|
115
|
+
}));
|
|
116
|
+
continue;
|
|
117
|
+
}
|
|
118
|
+
walk(target);
|
|
119
|
+
}
|
|
120
|
+
visiting.pop();
|
|
121
|
+
done.add(agent.id);
|
|
122
|
+
};
|
|
123
|
+
for (const agent of ir.agents)
|
|
124
|
+
walk(agent);
|
|
125
|
+
return { diagnostics, suppressed: NO_SUPPRESSIONS };
|
|
126
|
+
}
|
|
127
|
+
export function agentsBudgetGate(ir, options) {
|
|
128
|
+
const diagnostics = [];
|
|
129
|
+
const report = reporter(options);
|
|
130
|
+
for (const agent of ir.agents) {
|
|
131
|
+
if (!Number.isInteger(agent.maxSteps) || agent.maxSteps < 1) {
|
|
132
|
+
diagnostics.push(report.error({
|
|
133
|
+
code: IR_DIAGNOSTIC_CODES.agentsBudget,
|
|
134
|
+
message: `the agents gate rejected "${agent.id}": maxSteps is ${agent.maxSteps}, so the agent can never complete a step`,
|
|
135
|
+
path: ['agents', agent.id, 'maxSteps'],
|
|
136
|
+
hint: 'set maxSteps to at least 1',
|
|
137
|
+
}));
|
|
138
|
+
}
|
|
139
|
+
if (agent.maxTokensBudget !== undefined && agent.maxTokensBudget < 1) {
|
|
140
|
+
diagnostics.push(report.error({
|
|
141
|
+
code: IR_DIAGNOSTIC_CODES.agentsBudget,
|
|
142
|
+
message: `the agents gate rejected "${agent.id}": maxTokensBudget is ${agent.maxTokensBudget}, which no run can satisfy`,
|
|
143
|
+
path: ['agents', agent.id, 'maxTokensBudget'],
|
|
144
|
+
hint: 'set maxTokensBudget to at least 1, or omit it',
|
|
145
|
+
}));
|
|
146
|
+
}
|
|
147
|
+
if (agent.maxCostBudget !== undefined && !(agent.maxCostBudget > 0)) {
|
|
148
|
+
diagnostics.push(report.error({
|
|
149
|
+
code: IR_DIAGNOSTIC_CODES.agentsBudget,
|
|
150
|
+
message: `the agents gate rejected "${agent.id}": maxCostBudget is ${agent.maxCostBudget}, which no run can satisfy`,
|
|
151
|
+
path: ['agents', agent.id, 'maxCostBudget'],
|
|
152
|
+
hint: 'set maxCostBudget above zero, or omit it',
|
|
153
|
+
}));
|
|
154
|
+
}
|
|
155
|
+
const loopable = agent.maxSteps > 1;
|
|
156
|
+
const bounded = agent.maxTokensBudget !== undefined || agent.maxCostBudget !== undefined;
|
|
157
|
+
if (loopable && !bounded) {
|
|
158
|
+
diagnostics.push(report.error({
|
|
159
|
+
code: IR_DIAGNOSTIC_CODES.agentsBudget,
|
|
160
|
+
message: `the agents gate rejected "${agent.id}": it may take up to ${agent.maxSteps} steps but declares neither maxTokensBudget nor maxCostBudget, so nothing bounds what one run costs`,
|
|
161
|
+
path: ['agents', agent.id, 'maxTokensBudget'],
|
|
162
|
+
hint: 'declare maxTokensBudget or maxCostBudget, or set maxSteps: 1',
|
|
163
|
+
}));
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
return { diagnostics, suppressed: NO_SUPPRESSIONS };
|
|
167
|
+
}
|
|
168
|
+
/**
|
|
169
|
+
* A degrade request must have somewhere cheaper to go, and that somewhere must be
|
|
170
|
+
* provable from the pinned cost profiles rather than assumed.
|
|
171
|
+
*/
|
|
172
|
+
export function agentsBudgetDegradeGate(ir, options) {
|
|
173
|
+
const diagnostics = [];
|
|
174
|
+
const report = reporter(options);
|
|
175
|
+
const models = new Map(ir.models.map((model) => [model.id, model]));
|
|
176
|
+
for (const agent of ir.agents) {
|
|
177
|
+
if (agent.onBudgetExhausted !== 'degrade')
|
|
178
|
+
continue;
|
|
179
|
+
if (agent.maxCostBudget === undefined) {
|
|
180
|
+
diagnostics.push(report.error({
|
|
181
|
+
code: IR_DIAGNOSTIC_CODES.agentsBudgetDegrade,
|
|
182
|
+
message: `the agents gate rejected "${agent.id}": onBudgetExhausted is "degrade" but it declares no maxCostBudget, and switching aliases cannot make a token ceiling cheaper`,
|
|
183
|
+
path: ['agents', agent.id, 'onBudgetExhausted'],
|
|
184
|
+
hint: 'declare maxCostBudget, or set onBudgetExhausted: fail',
|
|
185
|
+
}));
|
|
186
|
+
}
|
|
187
|
+
const model = models.get(agent.model);
|
|
188
|
+
// An unresolved model is `agents/refs-resolve`'s diagnostic, not ours.
|
|
189
|
+
if (model === undefined)
|
|
190
|
+
continue;
|
|
191
|
+
if (cheaperFallbacks(ir, model).length > 0)
|
|
192
|
+
continue;
|
|
193
|
+
diagnostics.push(report.error({
|
|
194
|
+
code: IR_DIAGNOSTIC_CODES.agentsBudgetDegrade,
|
|
195
|
+
message: `the agents gate rejected "${agent.id}": onBudgetExhausted is "degrade" but model "${model.id}" has no fallback alias that is strictly cheaper, so a budget breach would still be a hard failure at run time`,
|
|
196
|
+
path: ['agents', agent.id, 'onBudgetExhausted'],
|
|
197
|
+
hint: degradeHint(model, ir),
|
|
198
|
+
}));
|
|
199
|
+
}
|
|
200
|
+
return { diagnostics, suppressed: NO_SUPPRESSIONS };
|
|
201
|
+
}
|
|
202
|
+
/** Fallback aliases that are strictly cheaper than `model`, in declaration order. */
|
|
203
|
+
function cheaperFallbacks(ir, model) {
|
|
204
|
+
const models = new Map(ir.models.map((entry) => [entry.id, entry]));
|
|
205
|
+
const current = aliasCost(models.get(model.id));
|
|
206
|
+
if (current === undefined)
|
|
207
|
+
return [];
|
|
208
|
+
return model.fallbacks.filter((id) => {
|
|
209
|
+
const candidate = aliasCost(models.get(id));
|
|
210
|
+
return candidate !== undefined && candidate < current;
|
|
211
|
+
});
|
|
212
|
+
}
|
|
213
|
+
function aliasCost(model) {
|
|
214
|
+
if (model?.costProfile === undefined)
|
|
215
|
+
return undefined;
|
|
216
|
+
return model.costProfile.inputPerMTok + model.costProfile.outputPerMTok;
|
|
217
|
+
}
|
|
218
|
+
function degradeHint(model, ir) {
|
|
219
|
+
const models = new Map(ir.models.map((entry) => [entry.id, entry]));
|
|
220
|
+
if (model.fallbacks.length === 0) {
|
|
221
|
+
return `declare at least one cheaper alias in models.${model.id}.fallbacks, or set onBudgetExhausted: fail`;
|
|
222
|
+
}
|
|
223
|
+
const current = aliasCost(models.get(model.id));
|
|
224
|
+
if (current === undefined) {
|
|
225
|
+
return `models.${model.id} has no costProfile, so no fallback can be proven cheaper; declare one, or set onBudgetExhausted: fail`;
|
|
226
|
+
}
|
|
227
|
+
const priced = model.fallbacks.map((id) => {
|
|
228
|
+
const cost = aliasCost(models.get(id));
|
|
229
|
+
return cost === undefined ? `${id} (unpriced)` : `${id} (${cost})`;
|
|
230
|
+
});
|
|
231
|
+
return `fallbacks ${priced.join(', ')} are not cheaper than ${current} (sum of input and output list price); declare a cheaper alias, or set onBudgetExhausted: fail`;
|
|
232
|
+
}
|
|
233
|
+
//# sourceMappingURL=agents.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"agents.js","sourceRoot":"","sources":["../../src/gates/agents.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Gate 3 — capability.
|
|
3
|
+
*
|
|
4
|
+
* A target generator declares the capabilities it implements; the IR derives what it
|
|
5
|
+
* requires from its own content. The gate intersects the two and fails on any unmet
|
|
6
|
+
* requirement, so a generator is never handed work it cannot express.
|
|
7
|
+
*
|
|
8
|
+
* `packages/generator-sdk` does not exist in layer 2, so the declarations arrive as
|
|
9
|
+
* an injected parameter. Layer 3 supplies real generator declarations and nothing
|
|
10
|
+
* else in this module changes.
|
|
11
|
+
*/
|
|
12
|
+
import type { IR } from '../shapes.js';
|
|
13
|
+
import { type GateOptions, type GateResult } from './contract.js';
|
|
14
|
+
export declare function capabilityGate(ir: IR, options: GateOptions): GateResult;
|
|
15
|
+
//# sourceMappingURL=capability.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"capability.d.ts","sourceRoot":"","sources":["../../src/gates/capability.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAQH,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,cAAc,CAAC;AACvC,OAAO,EAAE,KAAK,WAAW,EAAE,KAAK,UAAU,EAAkC,MAAM,eAAe,CAAC;AAMlG,wBAAgB,cAAc,CAAC,EAAE,EAAE,EAAE,EAAE,OAAO,EAAE,WAAW,GAAG,UAAU,CAoDvE"}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Gate 3 — capability.
|
|
3
|
+
*
|
|
4
|
+
* A target generator declares the capabilities it implements; the IR derives what it
|
|
5
|
+
* requires from its own content. The gate intersects the two and fails on any unmet
|
|
6
|
+
* requirement, so a generator is never handed work it cannot express.
|
|
7
|
+
*
|
|
8
|
+
* `packages/generator-sdk` does not exist in layer 2, so the declarations arrive as
|
|
9
|
+
* an injected parameter. Layer 3 supplies real generator declarations and nothing
|
|
10
|
+
* else in this module changes.
|
|
11
|
+
*/
|
|
12
|
+
import { REQUIRED_CAPABILITIES, resolveRequiredCapability, } from '../capabilities.js';
|
|
13
|
+
import { IR_DIAGNOSTIC_CODES } from '../diagnostics.js';
|
|
14
|
+
import { reporter } from './contract.js';
|
|
15
|
+
const SUPPRESSED = [];
|
|
16
|
+
export function capabilityGate(ir, options) {
|
|
17
|
+
const diagnostics = [];
|
|
18
|
+
const report = reporter(options);
|
|
19
|
+
const required = new Set(ir.requiredCapabilities);
|
|
20
|
+
for (const target of ir.project.targets) {
|
|
21
|
+
const declared = options.targetCapabilities[target];
|
|
22
|
+
if (declared === undefined) {
|
|
23
|
+
diagnostics.push(report.error({
|
|
24
|
+
code: IR_DIAGNOSTIC_CODES.targetUnknown,
|
|
25
|
+
message: `the capability gate rejected this target: no capability declaration is registered for "${target}", so nothing it can generate is known`,
|
|
26
|
+
path: ['project', 'targets'],
|
|
27
|
+
hint: `Phase 0 declares ${Object.keys(options.targetCapabilities).join(', ') || 'no targets'}`,
|
|
28
|
+
}));
|
|
29
|
+
continue;
|
|
30
|
+
}
|
|
31
|
+
const capabilities = new Set();
|
|
32
|
+
for (const entry of declared) {
|
|
33
|
+
const resolved = resolveRequiredCapability(entry);
|
|
34
|
+
if (resolved === undefined) {
|
|
35
|
+
diagnostics.push(report.error({
|
|
36
|
+
code: IR_DIAGNOSTIC_CODES.capabilityUnknown,
|
|
37
|
+
message: `the capability gate rejected this declaration: "${entry}" is not a capability of the vocabulary (${REQUIRED_CAPABILITIES.join(', ')})`,
|
|
38
|
+
path: ['project', 'targets'],
|
|
39
|
+
hint: 'declare a capability from the vocabulary, or extend it deliberately',
|
|
40
|
+
}));
|
|
41
|
+
continue;
|
|
42
|
+
}
|
|
43
|
+
capabilities.add(resolved);
|
|
44
|
+
}
|
|
45
|
+
for (const capability of required) {
|
|
46
|
+
if (capabilities.has(capability))
|
|
47
|
+
continue;
|
|
48
|
+
diagnostics.push(report.error({
|
|
49
|
+
code: IR_DIAGNOSTIC_CODES.capabilityMissing,
|
|
50
|
+
message: `the capability gate rejected target "${target}": the IR requires "${capability}", which this target does not declare`,
|
|
51
|
+
path: ['project', 'targets'],
|
|
52
|
+
hint: `declare "${capability}" for "${target}", or drop the feature that needs it`,
|
|
53
|
+
}));
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
checkStructuredOutputModels(ir, diagnostics, report);
|
|
57
|
+
return { diagnostics, suppressed: SUPPRESSED };
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* A structured-output prompt needs a model that can constrain its output, otherwise
|
|
61
|
+
* the schema the IR carries is unenforceable at the only layer that could enforce it.
|
|
62
|
+
*/
|
|
63
|
+
function checkStructuredOutputModels(ir, diagnostics, report) {
|
|
64
|
+
const models = new Map(ir.models.map((model) => [model.id, model]));
|
|
65
|
+
for (const prompt of ir.prompts) {
|
|
66
|
+
if (prompt.output.kind !== 'structured')
|
|
67
|
+
continue;
|
|
68
|
+
const model = models.get(prompt.model);
|
|
69
|
+
if (model === undefined)
|
|
70
|
+
continue;
|
|
71
|
+
if (model.capabilities.includes('json-schema'))
|
|
72
|
+
continue;
|
|
73
|
+
diagnostics.push(report.error({
|
|
74
|
+
code: IR_DIAGNOSTIC_CODES.modelCapabilityMissing,
|
|
75
|
+
message: `the capability gate rejected this prompt: "${prompt.id}" declares structured output, but its model "${model.id}" does not declare the "json-schema" capability`,
|
|
76
|
+
path: ['prompts', prompt.id, 'model'],
|
|
77
|
+
hint: 'bind a model that declares json-schema, or use a text output',
|
|
78
|
+
}));
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
//# sourceMappingURL=capability.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"capability.js","sourceRoot":"","sources":["../../src/gates/capability.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EACL,qBAAqB,EAErB,yBAAyB,GAC1B,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAAE,mBAAmB,EAAqB,MAAM,mBAAmB,CAAC;AAE3E,OAAO,EAAqC,QAAQ,EAAwB,MAAM,eAAe,CAAC;AAElG,MAAM,UAAU,GAAsB,EAAE,CAAC;AAIzC,MAAM,UAAU,cAAc,CAAC,EAAM,EAAE,OAAoB;IACzD,MAAM,WAAW,GAAmB,EAAE,CAAC;IACvC,MAAM,MAAM,GAAG,QAAQ,CAAC,OAAO,CAAC,CAAC;IAEjC,MAAM,QAAQ,GAAG,IAAI,GAAG,CAAqB,EAAE,CAAC,oBAAoB,CAAC,CAAC;IACtE,KAAK,MAAM,MAAM,IAAI,EAAE,CAAC,OAAO,CAAC,OAAO,EAAE,CAAC;QACxC,MAAM,QAAQ,GAAG,OAAO,CAAC,kBAAkB,CAAC,MAAM,CAAC,CAAC;QACpD,IAAI,QAAQ,KAAK,SAAS,EAAE,CAAC;YAC3B,WAAW,CAAC,IAAI,CACd,MAAM,CAAC,KAAK,CAAC;gBACX,IAAI,EAAE,mBAAmB,CAAC,aAAa;gBACvC,OAAO,EAAE,0FAA0F,MAAM,wCAAwC;gBACjJ,IAAI,EAAE,CAAC,SAAS,EAAE,SAAS,CAAC;gBAC5B,IAAI,EAAE,oBAAoB,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,kBAAkB,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,YAAY,EAAE;aAC/F,CAAC,CACH,CAAC;YACF,SAAS;QACX,CAAC;QAED,MAAM,YAAY,GAAG,IAAI,GAAG,EAAsB,CAAC;QACnD,KAAK,MAAM,KAAK,IAAI,QAAQ,EAAE,CAAC;YAC7B,MAAM,QAAQ,GAAG,yBAAyB,CAAC,KAAK,CAAC,CAAC;YAClD,IAAI,QAAQ,KAAK,SAAS,EAAE,CAAC;gBAC3B,WAAW,CAAC,IAAI,CACd,MAAM,CAAC,KAAK,CAAC;oBACX,IAAI,EAAE,mBAAmB,CAAC,iBAAiB;oBAC3C,OAAO,EAAE,mDAAmD,KAAK,4CAA4C,qBAAqB,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG;oBAChJ,IAAI,EAAE,CAAC,SAAS,EAAE,SAAS,CAAC;oBAC5B,IAAI,EAAE,qEAAqE;iBAC5E,CAAC,CACH,CAAC;gBACF,SAAS;YACX,CAAC;YACD,YAAY,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;QAC7B,CAAC;QAED,KAAK,MAAM,UAAU,IAAI,QAAQ,EAAE,CAAC;YAClC,IAAI,YAAY,CAAC,GAAG,CAAC,UAAU,CAAC;gBAAE,SAAS;YAC3C,WAAW,CAAC,IAAI,CACd,MAAM,CAAC,KAAK,CAAC;gBACX,IAAI,EAAE,mBAAmB,CAAC,iBAAiB;gBAC3C,OAAO,EAAE,wCAAwC,MAAM,uBAAuB,UAAU,uCAAuC;gBAC/H,IAAI,EAAE,CAAC,SAAS,EAAE,SAAS,CAAC;gBAC5B,IAAI,EAAE,YAAY,UAAU,UAAU,MAAM,sCAAsC;aACnF,CAAC,CACH,CAAC;QACJ,CAAC;IACH,CAAC;IAED,2BAA2B,CAAC,EAAE,EAAE,WAAW,EAAE,MAAM,CAAC,CAAC;IAErD,OAAO,EAAE,WAAW,EAAE,UAAU,EAAE,UAAU,EAAE,CAAC;AACjD,CAAC;AAED;;;GAGG;AACH,SAAS,2BAA2B,CAAC,EAAM,EAAE,WAA2B,EAAE,MAAgB;IACxF,MAAM,MAAM,GAAG,IAAI,GAAG,CAAC,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,EAAE,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC;IACpE,KAAK,MAAM,MAAM,IAAI,EAAE,CAAC,OAAO,EAAE,CAAC;QAChC,IAAI,MAAM,CAAC,MAAM,CAAC,IAAI,KAAK,YAAY;YAAE,SAAS;QAClD,MAAM,KAAK,GAAG,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;QACvC,IAAI,KAAK,KAAK,SAAS;YAAE,SAAS;QAClC,IAAI,KAAK,CAAC,YAAY,CAAC,QAAQ,CAAC,aAAa,CAAC;YAAE,SAAS;QACzD,WAAW,CAAC,IAAI,CACd,MAAM,CAAC,KAAK,CAAC;YACX,IAAI,EAAE,mBAAmB,CAAC,sBAAsB;YAChD,OAAO,EAAE,8CAA8C,MAAM,CAAC,EAAE,gDAAgD,KAAK,CAAC,EAAE,iDAAiD;YACzK,IAAI,EAAE,CAAC,SAAS,EAAE,MAAM,CAAC,EAAE,EAAE,OAAO,CAAC;YACrC,IAAI,EAAE,8DAA8D;SACrE,CAAC,CACH,CAAC;IACJ,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The contract every build-time gate honours.
|
|
3
|
+
*
|
|
4
|
+
* A gate returns diagnostics and never throws for a user-recoverable condition.
|
|
5
|
+
* A check Phase 0 genuinely cannot enforce is reported in `suppressed` with a
|
|
6
|
+
* stated reason, because a silently-skipped check is indistinguishable from a
|
|
7
|
+
* passing one — that is how an unpublished rule becomes a false sense of safety.
|
|
8
|
+
*/
|
|
9
|
+
import type { DiagnosticInit } from '@aid-framework/spec';
|
|
10
|
+
import type { TargetCapabilityDeclarations } from '../catalog/index.js';
|
|
11
|
+
import { type IrDiagnostic, type IrDiagnosticCode } from '../diagnostics.js';
|
|
12
|
+
import type { IR } from '../shapes.js';
|
|
13
|
+
/** A check that is not enforceable yet, and why. Never silent. */
|
|
14
|
+
export interface SuppressedCheck {
|
|
15
|
+
check: string;
|
|
16
|
+
reason: string;
|
|
17
|
+
}
|
|
18
|
+
export interface GateResult {
|
|
19
|
+
diagnostics: IrDiagnostic[];
|
|
20
|
+
suppressed: SuppressedCheck[];
|
|
21
|
+
}
|
|
22
|
+
export interface GateOptions {
|
|
23
|
+
/** Target capability declarations, injected so this layer never imports the SDK. */
|
|
24
|
+
targetCapabilities: TargetCapabilityDeclarations;
|
|
25
|
+
file?: string;
|
|
26
|
+
}
|
|
27
|
+
export type Gate = (ir: IR, options: GateOptions) => GateResult;
|
|
28
|
+
export interface GateReporter {
|
|
29
|
+
error(init: DiagnosticInit<IrDiagnosticCode>): IrDiagnostic;
|
|
30
|
+
warn(init: DiagnosticInit<IrDiagnosticCode>): IrDiagnostic;
|
|
31
|
+
}
|
|
32
|
+
/** Binds the source file into every diagnostic a gate emits. */
|
|
33
|
+
export declare function reporter(options: GateOptions): GateReporter;
|
|
34
|
+
export declare const NO_SUPPRESSIONS: SuppressedCheck[];
|
|
35
|
+
//# sourceMappingURL=contract.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"contract.d.ts","sourceRoot":"","sources":["../../src/gates/contract.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAC1D,OAAO,KAAK,EAAE,4BAA4B,EAAE,MAAM,qBAAqB,CAAC;AACxE,OAAO,EACL,KAAK,YAAY,EACjB,KAAK,gBAAgB,EAItB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,cAAc,CAAC;AAEvC,kEAAkE;AAClE,MAAM,WAAW,eAAe;IAC9B,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,UAAU;IACzB,WAAW,EAAE,YAAY,EAAE,CAAC;IAC5B,UAAU,EAAE,eAAe,EAAE,CAAC;CAC/B;AAED,MAAM,WAAW,WAAW;IAC1B,oFAAoF;IACpF,kBAAkB,EAAE,4BAA4B,CAAC;IACjD,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,MAAM,MAAM,IAAI,GAAG,CAAC,EAAE,EAAE,EAAE,EAAE,OAAO,EAAE,WAAW,KAAK,UAAU,CAAC;AAEhE,MAAM,WAAW,YAAY;IAC3B,KAAK,CAAC,IAAI,EAAE,cAAc,CAAC,gBAAgB,CAAC,GAAG,YAAY,CAAC;IAC5D,IAAI,CAAC,IAAI,EAAE,cAAc,CAAC,gBAAgB,CAAC,GAAG,YAAY,CAAC;CAC5D;AAED,gEAAgE;AAChE,wBAAgB,QAAQ,CAAC,OAAO,EAAE,WAAW,GAAG,YAAY,CAM3D;AAED,eAAO,MAAM,eAAe,EAAE,eAAe,EAAO,CAAC"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The contract every build-time gate honours.
|
|
3
|
+
*
|
|
4
|
+
* A gate returns diagnostics and never throws for a user-recoverable condition.
|
|
5
|
+
* A check Phase 0 genuinely cannot enforce is reported in `suppressed` with a
|
|
6
|
+
* stated reason, because a silently-skipped check is indistinguishable from a
|
|
7
|
+
* passing one — that is how an unpublished rule becomes a false sense of safety.
|
|
8
|
+
*/
|
|
9
|
+
import { irError, irWarning, withPosition, } from '../diagnostics.js';
|
|
10
|
+
/** Binds the source file into every diagnostic a gate emits. */
|
|
11
|
+
export function reporter(options) {
|
|
12
|
+
const file = options.file;
|
|
13
|
+
return {
|
|
14
|
+
error: (init) => withPosition(irError(init), { file }),
|
|
15
|
+
warn: (init) => withPosition(irWarning(init), { file }),
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
export const NO_SUPPRESSIONS = [];
|
|
19
|
+
//# sourceMappingURL=contract.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"contract.js","sourceRoot":"","sources":["../../src/gates/contract.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAIH,OAAO,EAGL,OAAO,EACP,SAAS,EACT,YAAY,GACb,MAAM,mBAAmB,CAAC;AA2B3B,gEAAgE;AAChE,MAAM,UAAU,QAAQ,CAAC,OAAoB;IAC3C,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC;IAC1B,OAAO;QACL,KAAK,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,YAAY,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,EAAE,IAAI,EAAE,CAAC;QACtD,IAAI,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,YAAY,CAAC,SAAS,CAAC,IAAI,CAAC,EAAE,EAAE,IAAI,EAAE,CAAC;KACxD,CAAC;AACJ,CAAC;AAED,MAAM,CAAC,MAAM,eAAe,GAAsB,EAAE,CAAC"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Gate 4 — cost.
|
|
3
|
+
*
|
|
4
|
+
* Cost profiles are resolved from the offline catalog in `src/catalog/models.json`, so
|
|
5
|
+
* an estimate is deterministic and reproducible on a machine with no network. The gate
|
|
6
|
+
* fails *closed* on an unpriced model that someone declared a budget for: an unpriced
|
|
7
|
+
* model cannot be shown to fit a budget, and silently assuming it does is the failure
|
|
8
|
+
* mode this gate exists to prevent.
|
|
9
|
+
*
|
|
10
|
+
* A retrieval path is not free by omission: the candidate chunks a retriever materialises
|
|
11
|
+
* are charged to the model that embeds them, so a retriever with a wide `topK` over large
|
|
12
|
+
* chunks shows up in the estimate and can exceed a declared budget on its own.
|
|
13
|
+
*/
|
|
14
|
+
import type { EvalShape, IR } from '../shapes.js';
|
|
15
|
+
import { type GateOptions, type GateResult } from './contract.js';
|
|
16
|
+
/** One model's contribution to a target's estimated per-run cost. */
|
|
17
|
+
export interface ModelCostEstimate {
|
|
18
|
+
model: string;
|
|
19
|
+
inputTokens: number;
|
|
20
|
+
outputTokens: number;
|
|
21
|
+
/** Absent when no catalog profile resolved, i.e. the model is unpriced. */
|
|
22
|
+
cost?: number;
|
|
23
|
+
}
|
|
24
|
+
export interface EvalCostEstimate {
|
|
25
|
+
inputTokens: number;
|
|
26
|
+
outputTokens: number;
|
|
27
|
+
/** Absent when any model on the target's path is unpriced. */
|
|
28
|
+
cost?: number;
|
|
29
|
+
models: ModelCostEstimate[];
|
|
30
|
+
/** The declared budget the estimate is compared against, when there is one. */
|
|
31
|
+
budget?: number;
|
|
32
|
+
}
|
|
33
|
+
export declare function costGate(ir: IR, options: GateOptions): GateResult;
|
|
34
|
+
/**
|
|
35
|
+
* The estimated per-run cost of one eval target: the sum over the models on the
|
|
36
|
+
* target's path of its prompt tokens and its bounded output tokens, plus the work the
|
|
37
|
+
* target's retrievers do.
|
|
38
|
+
*/
|
|
39
|
+
export declare function estimateEvalCost(ir: IR, evalShape: EvalShape): EvalCostEstimate;
|
|
40
|
+
//# sourceMappingURL=cost.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cost.d.ts","sourceRoot":"","sources":["../../src/gates/cost.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAIH,OAAO,KAAK,EAAe,SAAS,EAAE,EAAE,EAAsC,MAAM,cAAc,CAAC;AACnG,OAAO,EAAE,KAAK,WAAW,EAAE,KAAK,UAAU,EAAkC,MAAM,eAAe,CAAC;AAUlG,qEAAqE;AACrE,MAAM,WAAW,iBAAiB;IAChC,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;IACrB,2EAA2E;IAC3E,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,gBAAgB;IAC/B,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;IACrB,8DAA8D;IAC9D,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,iBAAiB,EAAE,CAAC;IAC5B,+EAA+E;IAC/E,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,wBAAgB,QAAQ,CAAC,EAAE,EAAE,EAAE,EAAE,OAAO,EAAE,WAAW,GAAG,UAAU,CA6CjE;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,EAAE,EAAE,EAAE,EAAE,SAAS,EAAE,SAAS,GAAG,gBAAgB,CAkC/E"}
|