agent-inspect 6.19.0 → 6.20.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/CHANGELOG.md +12 -0
- package/README.md +3 -1
- package/SECURITY.md +2 -0
- package/docs/ARCHITECTURE.md +28 -16
- package/docs/KNOWN-ISSUES.md +3 -3
- package/docs/LIMITATIONS.md +5 -4
- package/docs/PERFORMANCE.md +1 -1
- package/docs/SUPPORT-LEVELS.md +2 -1
- package/docs/TRACE-CONTRACTS.md +64 -52
- package/package.json +3 -2
- package/packages/cli/dist/{chunk-R7Y5SGH5.mjs → chunk-QPRJUVLH.mjs} +57 -17
- package/packages/cli/dist/chunk-QPRJUVLH.mjs.map +1 -0
- package/packages/cli/dist/index.cjs +69 -18
- package/packages/cli/dist/index.cjs.map +1 -1
- package/packages/cli/dist/index.mjs +9 -6
- package/packages/cli/dist/index.mjs.map +1 -1
- package/packages/cli/dist/{src-T4EZERCX.mjs → src-6W5ZR3I7.mjs} +3 -3
- package/packages/cli/dist/{src-T4EZERCX.mjs.map → src-6W5ZR3I7.mjs.map} +1 -1
- package/packages/core/dist/advanced.cjs +118 -18
- package/packages/core/dist/advanced.cjs.map +1 -1
- package/packages/core/dist/advanced.d.cts +2 -2
- package/packages/core/dist/advanced.d.ts +2 -2
- package/packages/core/dist/advanced.mjs +8 -8
- package/packages/core/dist/checks.cjs +443 -9
- package/packages/core/dist/checks.cjs.map +1 -1
- package/packages/core/dist/checks.d.cts +78 -16
- package/packages/core/dist/checks.d.ts +78 -16
- package/packages/core/dist/checks.mjs +3 -3
- package/packages/core/dist/{chunk-VFO76UH3.mjs → chunk-3XS5O4JI.mjs} +3 -3
- package/packages/core/dist/{chunk-VFO76UH3.mjs.map → chunk-3XS5O4JI.mjs.map} +1 -1
- package/packages/core/dist/{chunk-ZWA5RWMV.mjs → chunk-5YFJJFXU.mjs} +4 -4
- package/packages/core/dist/{chunk-ZWA5RWMV.mjs.map → chunk-5YFJJFXU.mjs.map} +1 -1
- package/packages/core/dist/{chunk-NABMW5DX.mjs → chunk-G47KQB42.mjs} +445 -13
- package/packages/core/dist/chunk-G47KQB42.mjs.map +1 -0
- package/packages/core/dist/{chunk-SGL4JGCD.mjs → chunk-JBNRJLIV.mjs} +58 -18
- package/packages/core/dist/chunk-JBNRJLIV.mjs.map +1 -0
- package/packages/core/dist/{chunk-ULCGIRTC.mjs → chunk-U25RHRSU.mjs} +65 -5
- package/packages/core/dist/chunk-U25RHRSU.mjs.map +1 -0
- package/packages/core/dist/{context-Ca5yK8Cs.d.cts → context-C5ye_xcS.d.cts} +0 -4
- package/packages/core/dist/{context-D6cS4XIL.d.ts → context-CNsNSgE2.d.ts} +0 -4
- package/packages/core/dist/exporters.cjs +55 -15
- package/packages/core/dist/exporters.cjs.map +1 -1
- package/packages/core/dist/exporters.mjs +3 -3
- package/packages/core/dist/{index-DKwuGSe-.d.ts → index-Bg9ZdsdS.d.ts} +10 -0
- package/packages/core/dist/{index-DCR816Yt.d.cts → index-rVpX5PPh.d.cts} +10 -0
- package/packages/core/dist/index.cjs +63 -3
- package/packages/core/dist/index.cjs.map +1 -1
- package/packages/core/dist/index.d.cts +1 -1
- package/packages/core/dist/index.d.ts +1 -1
- package/packages/core/dist/index.mjs +4 -4
- package/packages/core/dist/writers.cjs +33 -2
- package/packages/core/dist/writers.cjs.map +1 -1
- package/packages/core/dist/writers.mjs +1 -1
- package/packages/cli/dist/chunk-R7Y5SGH5.mjs.map +0 -1
- package/packages/core/dist/chunk-NABMW5DX.mjs.map +0 -1
- package/packages/core/dist/chunk-SGL4JGCD.mjs.map +0 -1
- package/packages/core/dist/chunk-ULCGIRTC.mjs.map +0 -1
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { extractOutcomesFromPersistedEvents, outcomesMatchingStatus } from './chunk-
|
|
1
|
+
import { extractOutcomesFromPersistedEvents, outcomesMatchingStatus } from './chunk-3XS5O4JI.mjs';
|
|
2
2
|
import { formatProgrammaticDiagnostic } from './chunk-FWK3Q3OJ.mjs';
|
|
3
3
|
|
|
4
4
|
// packages/core/src/checks/logical-events.ts
|
|
@@ -1676,6 +1676,7 @@ function createToolUsageRule(options) {
|
|
|
1676
1676
|
}
|
|
1677
1677
|
function createToolOrderingRule(options) {
|
|
1678
1678
|
const ruleId = options.id ?? "tool.order";
|
|
1679
|
+
const mode = options.mode ?? "first-occurrence";
|
|
1679
1680
|
return {
|
|
1680
1681
|
id: ruleId,
|
|
1681
1682
|
category: "tool",
|
|
@@ -1688,7 +1689,7 @@ function createToolOrderingRule(options) {
|
|
|
1688
1689
|
if (beforeIndex === void 0 || afterIndex === void 0) {
|
|
1689
1690
|
return [];
|
|
1690
1691
|
}
|
|
1691
|
-
if (beforeIndex >= afterIndex) {
|
|
1692
|
+
if (mode === "first-occurrence" && beforeIndex >= afterIndex) {
|
|
1692
1693
|
return [
|
|
1693
1694
|
failFinding(
|
|
1694
1695
|
ruleId,
|
|
@@ -1703,6 +1704,130 @@ function createToolOrderingRule(options) {
|
|
|
1703
1704
|
const afterEvent = tools[afterIndex];
|
|
1704
1705
|
const beforeEnd = eventEndMs(beforeEvent);
|
|
1705
1706
|
const afterStart = eventStartMs(afterEvent);
|
|
1707
|
+
if (mode === "happens-before") {
|
|
1708
|
+
const expected = {
|
|
1709
|
+
before: options.before,
|
|
1710
|
+
after: options.after,
|
|
1711
|
+
mode,
|
|
1712
|
+
relation: "before.end <= after.start"
|
|
1713
|
+
};
|
|
1714
|
+
if (options.before === options.after) {
|
|
1715
|
+
return [
|
|
1716
|
+
failFinding(
|
|
1717
|
+
ruleId,
|
|
1718
|
+
`Tool ${options.before} cannot causally happen before itself.`,
|
|
1719
|
+
[eventEvidence(beforeEvent)],
|
|
1720
|
+
expected,
|
|
1721
|
+
{ code: "tool.order.same-tool" }
|
|
1722
|
+
)
|
|
1723
|
+
];
|
|
1724
|
+
}
|
|
1725
|
+
if (beforeEnd === void 0 || afterStart === void 0) {
|
|
1726
|
+
return [
|
|
1727
|
+
failFinding(
|
|
1728
|
+
ruleId,
|
|
1729
|
+
`Tool order ${options.before} before ${options.after} could not establish causal timing.`,
|
|
1730
|
+
[eventEvidence(beforeEvent), eventEvidence(afterEvent)],
|
|
1731
|
+
expected,
|
|
1732
|
+
{
|
|
1733
|
+
code: "tool.order.interval-unresolved",
|
|
1734
|
+
beforeEndResolved: beforeEnd !== void 0,
|
|
1735
|
+
afterStartResolved: afterStart !== void 0
|
|
1736
|
+
}
|
|
1737
|
+
)
|
|
1738
|
+
];
|
|
1739
|
+
}
|
|
1740
|
+
if (beforeEnd > afterStart) {
|
|
1741
|
+
return [
|
|
1742
|
+
failFinding(
|
|
1743
|
+
ruleId,
|
|
1744
|
+
`Tool ${options.before} must finish before ${options.after} starts.`,
|
|
1745
|
+
[eventEvidence(beforeEvent), eventEvidence(afterEvent)],
|
|
1746
|
+
expected,
|
|
1747
|
+
{
|
|
1748
|
+
beforeEndedAt: new Date(beforeEnd).toISOString(),
|
|
1749
|
+
afterStartedAt: new Date(afterStart).toISOString()
|
|
1750
|
+
}
|
|
1751
|
+
)
|
|
1752
|
+
];
|
|
1753
|
+
}
|
|
1754
|
+
return [];
|
|
1755
|
+
}
|
|
1756
|
+
if (mode === "all-occurrences") {
|
|
1757
|
+
const beforeEvents = tools.filter((event) => toolName(event) === options.before);
|
|
1758
|
+
const afterEvents = tools.filter((event) => toolName(event) === options.after);
|
|
1759
|
+
const expected = {
|
|
1760
|
+
before: options.before,
|
|
1761
|
+
after: options.after,
|
|
1762
|
+
mode,
|
|
1763
|
+
relation: "max(before.end) <= min(after.start)"
|
|
1764
|
+
};
|
|
1765
|
+
if (options.before === options.after) {
|
|
1766
|
+
return [
|
|
1767
|
+
failFinding(
|
|
1768
|
+
ruleId,
|
|
1769
|
+
`Tool ${options.before} cannot causally happen before itself.`,
|
|
1770
|
+
[eventEvidence(beforeEvent)],
|
|
1771
|
+
expected,
|
|
1772
|
+
{ code: "tool.order.same-tool" }
|
|
1773
|
+
)
|
|
1774
|
+
];
|
|
1775
|
+
}
|
|
1776
|
+
let latestBefore;
|
|
1777
|
+
let earliestAfter;
|
|
1778
|
+
let missingBeforeEnds = 0;
|
|
1779
|
+
let missingAfterStarts = 0;
|
|
1780
|
+
let firstMissingBefore;
|
|
1781
|
+
let firstMissingAfter;
|
|
1782
|
+
for (const event of beforeEvents) {
|
|
1783
|
+
const end = eventEndMs(event);
|
|
1784
|
+
if (end === void 0) {
|
|
1785
|
+
missingBeforeEnds += 1;
|
|
1786
|
+
firstMissingBefore ??= event;
|
|
1787
|
+
} else if (latestBefore === void 0 || end > latestBefore.end) {
|
|
1788
|
+
latestBefore = { event, end };
|
|
1789
|
+
}
|
|
1790
|
+
}
|
|
1791
|
+
for (const event of afterEvents) {
|
|
1792
|
+
const start = eventStartMs(event);
|
|
1793
|
+
if (start === void 0) {
|
|
1794
|
+
missingAfterStarts += 1;
|
|
1795
|
+
firstMissingAfter ??= event;
|
|
1796
|
+
} else if (earliestAfter === void 0 || start < earliestAfter.start) {
|
|
1797
|
+
earliestAfter = { event, start };
|
|
1798
|
+
}
|
|
1799
|
+
}
|
|
1800
|
+
if (missingBeforeEnds > 0 || missingAfterStarts > 0 || latestBefore === void 0 || earliestAfter === void 0) {
|
|
1801
|
+
return [
|
|
1802
|
+
failFinding(
|
|
1803
|
+
ruleId,
|
|
1804
|
+
`Tool order ${options.before} before ${options.after} could not establish all causal intervals.`,
|
|
1805
|
+
[firstMissingBefore, firstMissingAfter].filter((event) => event !== void 0).map((event) => eventEvidence(event)),
|
|
1806
|
+
expected,
|
|
1807
|
+
{
|
|
1808
|
+
code: "tool.order.interval-unresolved",
|
|
1809
|
+
missingBeforeEnds,
|
|
1810
|
+
missingAfterStarts
|
|
1811
|
+
}
|
|
1812
|
+
)
|
|
1813
|
+
];
|
|
1814
|
+
}
|
|
1815
|
+
if (latestBefore.end > earliestAfter.start) {
|
|
1816
|
+
return [
|
|
1817
|
+
failFinding(
|
|
1818
|
+
ruleId,
|
|
1819
|
+
`Every ${options.before} tool call must finish before any ${options.after} tool call starts.`,
|
|
1820
|
+
[eventEvidence(latestBefore.event), eventEvidence(earliestAfter.event)],
|
|
1821
|
+
expected,
|
|
1822
|
+
{
|
|
1823
|
+
latestBeforeEndedAt: new Date(latestBefore.end).toISOString(),
|
|
1824
|
+
earliestAfterStartedAt: new Date(earliestAfter.start).toISOString()
|
|
1825
|
+
}
|
|
1826
|
+
)
|
|
1827
|
+
];
|
|
1828
|
+
}
|
|
1829
|
+
return [];
|
|
1830
|
+
}
|
|
1706
1831
|
if (beforeEnd !== void 0 && afterStart !== void 0 && beforeEnd > afterStart) {
|
|
1707
1832
|
return [
|
|
1708
1833
|
{
|
|
@@ -2653,6 +2778,17 @@ function normalizeStatus(status) {
|
|
|
2653
2778
|
if (status === "failed") return "error";
|
|
2654
2779
|
return "error";
|
|
2655
2780
|
}
|
|
2781
|
+
function cloneBody(body) {
|
|
2782
|
+
return {
|
|
2783
|
+
...body.run ? { run: { ...body.run } } : {},
|
|
2784
|
+
...body.tools ? { tools: { ...body.tools } } : {},
|
|
2785
|
+
...body.llm ? { llm: { ...body.llm } } : {},
|
|
2786
|
+
...body.observations ? { observations: { ...body.observations } } : {}
|
|
2787
|
+
};
|
|
2788
|
+
}
|
|
2789
|
+
function bodyHasRules(body) {
|
|
2790
|
+
return body.run !== void 0 || body.tools !== void 0 || body.llm !== void 0 || body.observations !== void 0;
|
|
2791
|
+
}
|
|
2656
2792
|
function contractToRules(contract) {
|
|
2657
2793
|
const rules = [];
|
|
2658
2794
|
const allowedStatuses = contract.run?.allowedStatuses ?? [];
|
|
@@ -2727,6 +2863,7 @@ function contractToRules(contract) {
|
|
|
2727
2863
|
}
|
|
2728
2864
|
if (contract.tools) {
|
|
2729
2865
|
const order = contract.tools.requiredOrder ?? [];
|
|
2866
|
+
const requiredOrderMode = contract.tools.requiredOrderMode ?? "first-occurrence";
|
|
2730
2867
|
const required = [
|
|
2731
2868
|
.../* @__PURE__ */ new Set([
|
|
2732
2869
|
...contract.tools.required ?? [],
|
|
@@ -2751,7 +2888,8 @@ function contractToRules(contract) {
|
|
|
2751
2888
|
createToolOrderingRule({
|
|
2752
2889
|
before: order[i],
|
|
2753
2890
|
after: order[i + 1],
|
|
2754
|
-
id: `contract.tool.order.${i}
|
|
2891
|
+
id: `contract.tool.order.${i}`,
|
|
2892
|
+
mode: requiredOrderMode
|
|
2755
2893
|
})
|
|
2756
2894
|
);
|
|
2757
2895
|
}
|
|
@@ -2801,25 +2939,319 @@ function contractToRules(contract) {
|
|
|
2801
2939
|
}
|
|
2802
2940
|
return rules;
|
|
2803
2941
|
}
|
|
2804
|
-
function
|
|
2942
|
+
function validateAlternativesShape(alternatives) {
|
|
2943
|
+
const diagnostics = [];
|
|
2944
|
+
if (alternatives === void 0) return diagnostics;
|
|
2945
|
+
const branches = alternatives.anyOf ?? [];
|
|
2946
|
+
if (branches.length === 0) {
|
|
2947
|
+
diagnostics.push({
|
|
2948
|
+
code: "contract.alternatives.empty",
|
|
2949
|
+
severity: "error",
|
|
2950
|
+
message: "alternatives.anyOf must contain at least one branch.",
|
|
2951
|
+
path: "alternatives.anyOf"
|
|
2952
|
+
});
|
|
2953
|
+
return diagnostics;
|
|
2954
|
+
}
|
|
2955
|
+
const seen = /* @__PURE__ */ new Set();
|
|
2956
|
+
for (const [index, branch] of branches.entries()) {
|
|
2957
|
+
const path = `alternatives.anyOf[${index}]`;
|
|
2958
|
+
if (!branch?.id || branch.id.trim() === "") {
|
|
2959
|
+
diagnostics.push({
|
|
2960
|
+
code: "contract.alternatives.missing-id",
|
|
2961
|
+
severity: "error",
|
|
2962
|
+
message: "Each alternatives.anyOf branch requires a non-empty id.",
|
|
2963
|
+
path
|
|
2964
|
+
});
|
|
2965
|
+
continue;
|
|
2966
|
+
}
|
|
2967
|
+
if (seen.has(branch.id)) {
|
|
2968
|
+
diagnostics.push({
|
|
2969
|
+
code: "contract.alternatives.duplicate-id",
|
|
2970
|
+
severity: "error",
|
|
2971
|
+
message: `Duplicate alternatives.anyOf branch id: ${branch.id}`,
|
|
2972
|
+
path: `${path}.id`
|
|
2973
|
+
});
|
|
2974
|
+
}
|
|
2975
|
+
seen.add(branch.id);
|
|
2976
|
+
if (!bodyHasRules(branch.contract ?? {})) {
|
|
2977
|
+
diagnostics.push({
|
|
2978
|
+
code: "contract.alternatives.empty-branch",
|
|
2979
|
+
severity: "error",
|
|
2980
|
+
message: `Branch ${branch.id} must declare at least one run/tools/llm/observations rule.`,
|
|
2981
|
+
path: `${path}.contract`
|
|
2982
|
+
});
|
|
2983
|
+
}
|
|
2984
|
+
const nested = branch.contract?.alternatives;
|
|
2985
|
+
if (nested !== void 0) {
|
|
2986
|
+
diagnostics.push({
|
|
2987
|
+
code: "contract.alternatives.nested",
|
|
2988
|
+
severity: "error",
|
|
2989
|
+
message: "Nested alternatives.anyOf is not supported. Keep one alternatives level only.",
|
|
2990
|
+
path: `${path}.contract.alternatives`
|
|
2991
|
+
});
|
|
2992
|
+
}
|
|
2993
|
+
}
|
|
2994
|
+
return diagnostics;
|
|
2995
|
+
}
|
|
2996
|
+
function emptyPassResult(input, runId) {
|
|
2805
2997
|
return {
|
|
2806
|
-
|
|
2807
|
-
|
|
2808
|
-
|
|
2809
|
-
...
|
|
2998
|
+
ok: true,
|
|
2999
|
+
status: "pass",
|
|
3000
|
+
format: input.read.format,
|
|
3001
|
+
...runId !== void 0 ? { runId } : {},
|
|
3002
|
+
summary: { passed: 0, failed: 0, warnings: 0, errors: 0, rulesEvaluated: 0 },
|
|
3003
|
+
findings: [],
|
|
3004
|
+
diagnostics: [],
|
|
3005
|
+
ruleExecutions: []
|
|
2810
3006
|
};
|
|
2811
3007
|
}
|
|
2812
|
-
function
|
|
2813
|
-
const
|
|
3008
|
+
function mergeContractResults(input, parts, extraFindings = []) {
|
|
3009
|
+
const findings = [...parts.flatMap((part) => part.findings), ...extraFindings];
|
|
3010
|
+
const diagnostics = parts.flatMap((part) => part.diagnostics);
|
|
3011
|
+
const ruleExecutions = parts.flatMap((part) => part.ruleExecutions);
|
|
3012
|
+
const failed = findings.filter(
|
|
3013
|
+
(finding) => finding.status === "fail" && finding.severity === "error"
|
|
3014
|
+
).length;
|
|
3015
|
+
const errors = diagnostics.filter((item) => item.severity === "error").length;
|
|
3016
|
+
const status = errors > 0 ? "error" : failed > 0 ? "fail" : "pass";
|
|
3017
|
+
const runId = parts.find((part) => part.runId !== void 0)?.runId;
|
|
3018
|
+
return {
|
|
3019
|
+
ok: status === "pass",
|
|
3020
|
+
status,
|
|
3021
|
+
format: input.read.format,
|
|
3022
|
+
...runId !== void 0 ? { runId } : {},
|
|
3023
|
+
summary: {
|
|
3024
|
+
passed: findings.filter((finding) => finding.status === "pass").length,
|
|
3025
|
+
failed,
|
|
3026
|
+
warnings: findings.filter(
|
|
3027
|
+
(finding) => finding.status === "warning" || finding.severity === "warning"
|
|
3028
|
+
).length,
|
|
3029
|
+
errors,
|
|
3030
|
+
rulesEvaluated: ruleExecutions.length
|
|
3031
|
+
},
|
|
3032
|
+
findings,
|
|
3033
|
+
diagnostics,
|
|
3034
|
+
ruleExecutions
|
|
3035
|
+
};
|
|
3036
|
+
}
|
|
3037
|
+
function evaluateBody(input, body, options = {}) {
|
|
3038
|
+
const rules = contractToRules(body);
|
|
3039
|
+
if (rules.length === 0) {
|
|
3040
|
+
return emptyPassResult(input, options.runId);
|
|
3041
|
+
}
|
|
2814
3042
|
return runTraceChecks(input, {
|
|
2815
3043
|
rules,
|
|
2816
3044
|
...options.runId !== void 0 ? { runId: options.runId } : {}
|
|
2817
3045
|
});
|
|
2818
3046
|
}
|
|
3047
|
+
function defineTraceContract(input) {
|
|
3048
|
+
const shapeErrors = validateAlternativesShape(input.alternatives).filter(
|
|
3049
|
+
(item) => item.severity === "error"
|
|
3050
|
+
);
|
|
3051
|
+
if (shapeErrors.length > 0) {
|
|
3052
|
+
throw new TypeError(shapeErrors.map((item) => item.message).join(" "));
|
|
3053
|
+
}
|
|
3054
|
+
const body = cloneBody(input);
|
|
3055
|
+
const alternatives = input.alternatives ? {
|
|
3056
|
+
anyOf: input.alternatives.anyOf.map((branch) => ({
|
|
3057
|
+
id: branch.id,
|
|
3058
|
+
...branch.description !== void 0 ? { description: branch.description } : {},
|
|
3059
|
+
contract: cloneBody(branch.contract)
|
|
3060
|
+
}))
|
|
3061
|
+
} : void 0;
|
|
3062
|
+
return {
|
|
3063
|
+
...body,
|
|
3064
|
+
...alternatives ? { alternatives } : {}
|
|
3065
|
+
};
|
|
3066
|
+
}
|
|
3067
|
+
function evaluateTraceContract(input, contract, options = {}) {
|
|
3068
|
+
const shapeErrors = validateAlternativesShape(contract.alternatives).filter(
|
|
3069
|
+
(item) => item.severity === "error"
|
|
3070
|
+
);
|
|
3071
|
+
if (shapeErrors.length > 0) {
|
|
3072
|
+
return {
|
|
3073
|
+
ok: false,
|
|
3074
|
+
status: "error",
|
|
3075
|
+
format: input.read.format,
|
|
3076
|
+
...options.runId !== void 0 ? { runId: options.runId } : {},
|
|
3077
|
+
summary: {
|
|
3078
|
+
passed: 0,
|
|
3079
|
+
failed: 0,
|
|
3080
|
+
warnings: 0,
|
|
3081
|
+
errors: shapeErrors.length,
|
|
3082
|
+
rulesEvaluated: 0
|
|
3083
|
+
},
|
|
3084
|
+
findings: [],
|
|
3085
|
+
diagnostics: shapeErrors.map((item) => ({
|
|
3086
|
+
code: "AI_CHECK_INVALID_CONFIG",
|
|
3087
|
+
message: item.message,
|
|
3088
|
+
severity: "error",
|
|
3089
|
+
ruleId: item.code
|
|
3090
|
+
})),
|
|
3091
|
+
ruleExecutions: []
|
|
3092
|
+
};
|
|
3093
|
+
}
|
|
3094
|
+
const base = evaluateBody(input, contract, options);
|
|
3095
|
+
const branches = contract.alternatives?.anyOf ?? [];
|
|
3096
|
+
if (branches.length === 0) {
|
|
3097
|
+
return base;
|
|
3098
|
+
}
|
|
3099
|
+
const branchEvaluations = branches.map((branch) => {
|
|
3100
|
+
const result = evaluateBody(input, branch.contract, options);
|
|
3101
|
+
return { branch, result };
|
|
3102
|
+
});
|
|
3103
|
+
const satisfied = branchEvaluations.filter((item) => item.result.ok && item.result.status === "pass").map((item) => item.branch.id);
|
|
3104
|
+
const failedBranches = branchEvaluations.filter(
|
|
3105
|
+
(item) => !(item.result.ok && item.result.status === "pass")
|
|
3106
|
+
);
|
|
3107
|
+
if (satisfied.length > 0) {
|
|
3108
|
+
const passFinding = {
|
|
3109
|
+
ruleId: "contract.alternatives.anyOf",
|
|
3110
|
+
severity: "info",
|
|
3111
|
+
status: "pass",
|
|
3112
|
+
message: `Satisfied alternative branch(es): ${satisfied.join(", ")}.`,
|
|
3113
|
+
expected: { anyOf: branches.map((branch) => branch.id) },
|
|
3114
|
+
actual: {
|
|
3115
|
+
satisfied,
|
|
3116
|
+
failed: failedBranches.map((item) => item.branch.id)
|
|
3117
|
+
},
|
|
3118
|
+
evidence: []
|
|
3119
|
+
};
|
|
3120
|
+
return mergeContractResults(input, [base], [passFinding]);
|
|
3121
|
+
}
|
|
3122
|
+
const noneFinding = {
|
|
3123
|
+
ruleId: "contract.alternatives.none-satisfied",
|
|
3124
|
+
severity: "error",
|
|
3125
|
+
status: "fail",
|
|
3126
|
+
message: "No alternatives.anyOf branch fully satisfied its contract.",
|
|
3127
|
+
expected: { anyOf: branches.map((branch) => branch.id) },
|
|
3128
|
+
actual: {
|
|
3129
|
+
branchFailures: Object.fromEntries(
|
|
3130
|
+
failedBranches.map((item) => [
|
|
3131
|
+
item.branch.id,
|
|
3132
|
+
item.result.findings.filter((finding) => finding.status === "fail").map((finding) => ({
|
|
3133
|
+
ruleId: finding.ruleId,
|
|
3134
|
+
message: finding.message
|
|
3135
|
+
}))
|
|
3136
|
+
])
|
|
3137
|
+
)
|
|
3138
|
+
},
|
|
3139
|
+
evidence: []
|
|
3140
|
+
};
|
|
3141
|
+
const prefixedBranchFindings = failedBranches.flatMap(
|
|
3142
|
+
(item) => item.result.findings.filter((finding) => finding.status === "fail").map((finding) => ({
|
|
3143
|
+
...finding,
|
|
3144
|
+
ruleId: `contract.alternatives.${item.branch.id}.${finding.ruleId}`
|
|
3145
|
+
}))
|
|
3146
|
+
);
|
|
3147
|
+
return mergeContractResults(input, [base], [noneFinding, ...prefixedBranchFindings]);
|
|
3148
|
+
}
|
|
2819
3149
|
function evaluateTraceContractRead(read, contract, options = {}) {
|
|
2820
3150
|
return evaluateTraceContract({ read }, contract, options);
|
|
2821
3151
|
}
|
|
3152
|
+
function lintTraceContract(contract) {
|
|
3153
|
+
const diagnostics = validateAlternativesShape(contract.alternatives);
|
|
3154
|
+
const branches = contract.alternatives?.anyOf ?? [];
|
|
3155
|
+
if (branches.length === 1) {
|
|
3156
|
+
diagnostics.push({
|
|
3157
|
+
code: "contract.alternatives.single-branch",
|
|
3158
|
+
severity: "warning",
|
|
3159
|
+
message: "alternatives.anyOf has a single branch. Prefer base rules unless a second valid path exists.",
|
|
3160
|
+
path: "alternatives.anyOf"
|
|
3161
|
+
});
|
|
3162
|
+
}
|
|
3163
|
+
const required = [
|
|
3164
|
+
...contract.tools?.required ?? [],
|
|
3165
|
+
...contract.tools?.requiredTools ?? []
|
|
3166
|
+
];
|
|
3167
|
+
if (required.length > 0 && branches.length === 0) {
|
|
3168
|
+
diagnostics.push({
|
|
3169
|
+
code: "contract.brittle.unconditional-required",
|
|
3170
|
+
severity: "info",
|
|
3171
|
+
message: "tools.required is unconditional. Use alternatives.anyOf when a legitimate shortcut may skip a tool.",
|
|
3172
|
+
path: "tools.required"
|
|
3173
|
+
});
|
|
3174
|
+
}
|
|
3175
|
+
const order = contract.tools?.requiredOrder ?? [];
|
|
3176
|
+
if (order.length >= 2 && contract.tools?.requiredOrderMode === void 0) {
|
|
3177
|
+
diagnostics.push({
|
|
3178
|
+
code: "contract.brittle.first-occurrence-default",
|
|
3179
|
+
severity: "info",
|
|
3180
|
+
message: "requiredOrder defaults to first-occurrence. Set requiredOrderMode when repeated calls must fail.",
|
|
3181
|
+
path: "tools.requiredOrderMode"
|
|
3182
|
+
});
|
|
3183
|
+
}
|
|
3184
|
+
return diagnostics;
|
|
3185
|
+
}
|
|
3186
|
+
function explainTraceContract(contract) {
|
|
3187
|
+
const lines = [];
|
|
3188
|
+
if (contract.run?.requireCompleted !== false) {
|
|
3189
|
+
lines.push("Base: run must complete (no running events).");
|
|
3190
|
+
}
|
|
3191
|
+
if (contract.run?.allowedStatuses?.length) {
|
|
3192
|
+
lines.push(`Base: run status in [${contract.run.allowedStatuses.join(", ")}].`);
|
|
3193
|
+
}
|
|
3194
|
+
if (contract.run?.maxDurationMs !== void 0) {
|
|
3195
|
+
lines.push(`Base: run duration <= ${contract.run.maxDurationMs}ms.`);
|
|
3196
|
+
}
|
|
3197
|
+
if (contract.tools) {
|
|
3198
|
+
const required = [
|
|
3199
|
+
.../* @__PURE__ */ new Set([
|
|
3200
|
+
...contract.tools.required ?? [],
|
|
3201
|
+
...contract.tools.requiredTools ?? [],
|
|
3202
|
+
...contract.tools.requiredOrder ?? []
|
|
3203
|
+
])
|
|
3204
|
+
];
|
|
3205
|
+
if (required.length > 0) {
|
|
3206
|
+
lines.push(`Base: required tools [${required.join(", ")}].`);
|
|
3207
|
+
}
|
|
3208
|
+
const forbidden = [
|
|
3209
|
+
...contract.tools.forbidden ?? [],
|
|
3210
|
+
...contract.tools.forbiddenTools ?? []
|
|
3211
|
+
];
|
|
3212
|
+
if (forbidden.length > 0) {
|
|
3213
|
+
lines.push(`Base: forbidden tools [${forbidden.join(", ")}].`);
|
|
3214
|
+
}
|
|
3215
|
+
if ((contract.tools.requiredOrder?.length ?? 0) >= 2) {
|
|
3216
|
+
const mode = contract.tools.requiredOrderMode ?? "first-occurrence";
|
|
3217
|
+
lines.push(
|
|
3218
|
+
`Base: requiredOrder [${contract.tools.requiredOrder.join(" \u2192 ")}] mode=${mode}.`
|
|
3219
|
+
);
|
|
3220
|
+
}
|
|
3221
|
+
}
|
|
3222
|
+
if (contract.llm) {
|
|
3223
|
+
if (contract.llm.maxCalls !== void 0) {
|
|
3224
|
+
lines.push(`Base: LLM maxCalls=${contract.llm.maxCalls}.`);
|
|
3225
|
+
}
|
|
3226
|
+
if (contract.llm.maxTotalTokens !== void 0) {
|
|
3227
|
+
lines.push(`Base: LLM maxTotalTokens=${contract.llm.maxTotalTokens}.`);
|
|
3228
|
+
}
|
|
3229
|
+
if (contract.llm.allowedModels?.length) {
|
|
3230
|
+
lines.push(`Base: LLM allowedModels [${contract.llm.allowedModels.join(", ")}].`);
|
|
3231
|
+
}
|
|
3232
|
+
}
|
|
3233
|
+
if (contract.observations?.required?.length) {
|
|
3234
|
+
lines.push(`Base: required observations [${contract.observations.required.join(", ")}].`);
|
|
3235
|
+
}
|
|
3236
|
+
if (contract.observations?.failOn?.length) {
|
|
3237
|
+
lines.push(`Base: fail on observations [${contract.observations.failOn.join(", ")}].`);
|
|
3238
|
+
}
|
|
3239
|
+
const branches = contract.alternatives?.anyOf ?? [];
|
|
3240
|
+
if (branches.length > 0) {
|
|
3241
|
+
lines.push(
|
|
3242
|
+
`Alternatives: at least one of [${branches.map((branch) => branch.id).join(", ")}] must fully pass.`
|
|
3243
|
+
);
|
|
3244
|
+
for (const branch of branches) {
|
|
3245
|
+
const detail = branch.description ? ` \u2014 ${branch.description}` : "";
|
|
3246
|
+
lines.push(` branch ${branch.id}${detail}`);
|
|
3247
|
+
}
|
|
3248
|
+
}
|
|
3249
|
+
if (lines.length === 0) {
|
|
3250
|
+
lines.push("Empty contract: no base rules and no alternatives.");
|
|
3251
|
+
}
|
|
3252
|
+
return lines;
|
|
3253
|
+
}
|
|
2822
3254
|
|
|
2823
|
-
export { buildTraceFacts, createBaselineRegressionRule, createDecisionRule, createGuardrailRule, createLlmUsageRule, createMaxStepDurationRule, createObservedOutcomeRule, createRequireCompletedRule, createRetrievalRule, createRunDepthRule, createRunDurationRule, createRunEventCountRule, createRunStatusRule, createSafetyOversizedAttributeRule, createSafetyRawContentRule, createSafetyRedactionRule, createSafetySecretPatternRule, createStallDetectionRule, createStructureCycleRule, createStructureIncompleteRule, createStructureOrphanRule, createStructureParallelWidthRule, createStructureRelationshipRule, createToolFailureRule, createToolOrderingRule, createToolUsageRule, defineTraceContract, deriveFailureFacts, evaluateTraceContract, evaluateTraceContractRead, projectLogicalEvents, resolveCanonicalToolName, runTraceChecks, summarizeSemanticParity };
|
|
2824
|
-
//# sourceMappingURL=chunk-
|
|
2825
|
-
//# sourceMappingURL=chunk-
|
|
3255
|
+
export { buildTraceFacts, createBaselineRegressionRule, createDecisionRule, createGuardrailRule, createLlmUsageRule, createMaxStepDurationRule, createObservedOutcomeRule, createRequireCompletedRule, createRetrievalRule, createRunDepthRule, createRunDurationRule, createRunEventCountRule, createRunStatusRule, createSafetyOversizedAttributeRule, createSafetyRawContentRule, createSafetyRedactionRule, createSafetySecretPatternRule, createStallDetectionRule, createStructureCycleRule, createStructureIncompleteRule, createStructureOrphanRule, createStructureParallelWidthRule, createStructureRelationshipRule, createToolFailureRule, createToolOrderingRule, createToolUsageRule, defineTraceContract, deriveFailureFacts, evaluateTraceContract, evaluateTraceContractRead, explainTraceContract, lintTraceContract, projectLogicalEvents, resolveCanonicalToolName, runTraceChecks, summarizeSemanticParity };
|
|
3256
|
+
//# sourceMappingURL=chunk-G47KQB42.mjs.map
|
|
3257
|
+
//# sourceMappingURL=chunk-G47KQB42.mjs.map
|