agent-inspect 6.31.20 → 6.31.22
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 +1 -1
- package/package.json +1 -1
- package/packages/cli/dist/{chunk-EVSIYDB2.mjs → chunk-EMWA5EKU.mjs} +324 -35
- package/packages/cli/dist/chunk-EMWA5EKU.mjs.map +1 -0
- package/packages/cli/dist/index.cjs +403 -60
- package/packages/cli/dist/index.cjs.map +1 -1
- package/packages/cli/dist/index.mjs +75 -31
- package/packages/cli/dist/index.mjs.map +1 -1
- package/packages/cli/dist/{src-NWDDK72G.mjs → src-VZHGOLTO.mjs} +3 -3
- package/packages/cli/dist/{src-NWDDK72G.mjs.map → src-VZHGOLTO.mjs.map} +1 -1
- package/packages/core/dist/advanced.cjs +247 -5
- package/packages/core/dist/advanced.cjs.map +1 -1
- package/packages/core/dist/advanced.mjs +6 -5
- package/packages/core/dist/advanced.mjs.map +1 -1
- package/packages/core/dist/checks.cjs +184 -31
- package/packages/core/dist/checks.cjs.map +1 -1
- package/packages/core/dist/checks.mjs +2 -1
- package/packages/core/dist/chunk-GCZUWY47.mjs +182 -0
- package/packages/core/dist/chunk-GCZUWY47.mjs.map +1 -0
- package/packages/core/dist/{chunk-JE3TUFAQ.mjs → chunk-RBXD7BNX.mjs} +3 -3
- package/packages/core/dist/{chunk-JE3TUFAQ.mjs.map → chunk-RBXD7BNX.mjs.map} +1 -1
- package/packages/core/dist/{chunk-YU6XT5A2.mjs → chunk-S4NU55LU.mjs} +45 -3
- package/packages/core/dist/chunk-S4NU55LU.mjs.map +1 -0
- package/packages/core/dist/{chunk-EIP5CNEL.mjs → chunk-UPGBMRL4.mjs} +49 -3
- package/packages/core/dist/chunk-UPGBMRL4.mjs.map +1 -0
- package/packages/core/dist/{chunk-GFQPPNSF.mjs → chunk-ZOF6ON65.mjs} +128 -103
- package/packages/core/dist/chunk-ZOF6ON65.mjs.map +1 -0
- package/packages/core/dist/exporters.cjs +82 -27
- package/packages/core/dist/exporters.cjs.map +1 -1
- package/packages/core/dist/exporters.mjs +72 -27
- package/packages/core/dist/exporters.mjs.map +1 -1
- package/packages/core/dist/logs.cjs +197 -1
- package/packages/core/dist/logs.cjs.map +1 -1
- package/packages/core/dist/logs.mjs +3 -2
- package/packages/core/dist/logs.mjs.map +1 -1
- package/packages/core/dist/persisted.cjs +197 -1
- package/packages/core/dist/persisted.cjs.map +1 -1
- package/packages/core/dist/persisted.mjs +4 -3
- package/packages/core/dist/persisted.mjs.map +1 -1
- package/packages/core/dist/readers.cjs +243 -1
- package/packages/core/dist/readers.cjs.map +1 -1
- package/packages/core/dist/readers.mjs +4 -3
- package/packages/cli/dist/chunk-EVSIYDB2.mjs.map +0 -1
- package/packages/core/dist/chunk-EIP5CNEL.mjs.map +0 -1
- package/packages/core/dist/chunk-GFQPPNSF.mjs.map +0 -1
- package/packages/core/dist/chunk-YU6XT5A2.mjs.map +0 -1
|
@@ -1704,6 +1704,65 @@ function evaluateToolArgumentValue(value, check, evidencePresent) {
|
|
|
1704
1704
|
};
|
|
1705
1705
|
}
|
|
1706
1706
|
|
|
1707
|
+
// packages/core/src/persisted/delivery-identity.ts
|
|
1708
|
+
var DELIVERY_CONFLICT_ATTR = "agent_inspect.delivery_conflict";
|
|
1709
|
+
var SYNTHETIC_DELIVERY_ID = /^(?:manual|inspect):[A-Za-z0-9_-]+:[A-Za-z0-9_-]+:[A-Za-z0-9_-]+:\d+$/;
|
|
1710
|
+
function stripReaderDeliveryDiscriminator(eventId) {
|
|
1711
|
+
if (!SYNTHETIC_DELIVERY_ID.test(eventId)) return eventId;
|
|
1712
|
+
return eventId.replace(/:\d+$/, "");
|
|
1713
|
+
}
|
|
1714
|
+
function canonicalDigest(value) {
|
|
1715
|
+
if (value === void 0) return null;
|
|
1716
|
+
const encoded = encodeCanonicalStructured(value);
|
|
1717
|
+
return encoded.ok ? encoded.value : `unencodable:${encoded.code}`;
|
|
1718
|
+
}
|
|
1719
|
+
function capturedContentDigest(attributes) {
|
|
1720
|
+
if (!attributes || typeof attributes !== "object") {
|
|
1721
|
+
return { args: null, result: null };
|
|
1722
|
+
}
|
|
1723
|
+
const nested = attributes.metadata && typeof attributes.metadata === "object" ? attributes.metadata : void 0;
|
|
1724
|
+
const args = attributes.arguments ?? attributes.args ?? attributes.input ?? nested?.arguments ?? nested?.args ?? nested?.input;
|
|
1725
|
+
const result = attributes.result ?? attributes.output ?? attributes.response ?? nested?.result ?? nested?.output ?? nested?.response;
|
|
1726
|
+
return {
|
|
1727
|
+
args: args === void 0 ? null : canonicalDigest(args),
|
|
1728
|
+
result: result === void 0 ? null : canonicalDigest(result)
|
|
1729
|
+
};
|
|
1730
|
+
}
|
|
1731
|
+
function timeKey(fields) {
|
|
1732
|
+
if (typeof fields.startedAt === "string" && fields.startedAt.trim() !== "") {
|
|
1733
|
+
return fields.startedAt;
|
|
1734
|
+
}
|
|
1735
|
+
if (typeof fields.timestamp === "string" && fields.timestamp.trim() !== "") {
|
|
1736
|
+
return fields.timestamp;
|
|
1737
|
+
}
|
|
1738
|
+
if (typeof fields.timestamp === "number" && Number.isFinite(fields.timestamp)) {
|
|
1739
|
+
return String(fields.timestamp);
|
|
1740
|
+
}
|
|
1741
|
+
return null;
|
|
1742
|
+
}
|
|
1743
|
+
function deliverySemanticFingerprint(fields) {
|
|
1744
|
+
const content = capturedContentDigest(fields.attributes);
|
|
1745
|
+
return JSON.stringify({
|
|
1746
|
+
stableEventId: stripReaderDeliveryDiscriminator(fields.eventId),
|
|
1747
|
+
runId: fields.runId,
|
|
1748
|
+
kind: fields.kind,
|
|
1749
|
+
name: fields.name,
|
|
1750
|
+
status: fields.status ?? null,
|
|
1751
|
+
parentId: fields.parentId ?? null,
|
|
1752
|
+
sourceType: fields.sourceType ?? null,
|
|
1753
|
+
time: timeKey(fields),
|
|
1754
|
+
operationId: fields.operationId ?? null,
|
|
1755
|
+
attemptId: fields.attemptId ?? null,
|
|
1756
|
+
attemptNumber: fields.attemptNumber ?? null,
|
|
1757
|
+
retryOf: fields.retryOf ?? null,
|
|
1758
|
+
argsDigest: content.args,
|
|
1759
|
+
resultDigest: content.result
|
|
1760
|
+
});
|
|
1761
|
+
}
|
|
1762
|
+
function hasDeliveryConflictMarker(attributes) {
|
|
1763
|
+
return attributes?.[DELIVERY_CONFLICT_ATTR] === true;
|
|
1764
|
+
}
|
|
1765
|
+
|
|
1707
1766
|
// packages/core/src/checks/retry-safety.ts
|
|
1708
1767
|
function fail2(ruleId, message, evidence, expected, actual) {
|
|
1709
1768
|
return {
|
|
@@ -1759,7 +1818,7 @@ function attemptIdOf(event) {
|
|
|
1759
1818
|
}
|
|
1760
1819
|
function countOperationAttempts(members) {
|
|
1761
1820
|
const identified = /* @__PURE__ */ new Set();
|
|
1762
|
-
|
|
1821
|
+
const unidentifiedFingerprints = /* @__PURE__ */ new Set();
|
|
1763
1822
|
for (const event of members) {
|
|
1764
1823
|
if (event.kind !== "TOOL" && event.kind !== "LLM") continue;
|
|
1765
1824
|
const id = attemptIdOf(event);
|
|
@@ -1767,13 +1826,13 @@ function countOperationAttempts(members) {
|
|
|
1767
1826
|
identified.add(id);
|
|
1768
1827
|
continue;
|
|
1769
1828
|
}
|
|
1770
|
-
|
|
1829
|
+
unidentifiedFingerprints.add(redeliveryFingerprint(event));
|
|
1771
1830
|
}
|
|
1772
1831
|
if (identified.size > 0) {
|
|
1773
|
-
return identified.size +
|
|
1832
|
+
return identified.size + unidentifiedFingerprints.size;
|
|
1774
1833
|
}
|
|
1775
1834
|
const numbered = /* @__PURE__ */ new Set();
|
|
1776
|
-
|
|
1835
|
+
const unnumberedFingerprints = /* @__PURE__ */ new Set();
|
|
1777
1836
|
for (const event of members) {
|
|
1778
1837
|
if (event.kind !== "TOOL" && event.kind !== "LLM") continue;
|
|
1779
1838
|
const num = attemptNumberOf(event);
|
|
@@ -1781,12 +1840,12 @@ function countOperationAttempts(members) {
|
|
|
1781
1840
|
numbered.add(num);
|
|
1782
1841
|
continue;
|
|
1783
1842
|
}
|
|
1784
|
-
|
|
1843
|
+
unnumberedFingerprints.add(redeliveryFingerprint(event));
|
|
1785
1844
|
}
|
|
1786
1845
|
if (numbered.size > 0) {
|
|
1787
|
-
return numbered.size +
|
|
1846
|
+
return numbered.size + unnumberedFingerprints.size;
|
|
1788
1847
|
}
|
|
1789
|
-
return
|
|
1848
|
+
return unnumberedFingerprints.size;
|
|
1790
1849
|
}
|
|
1791
1850
|
function classifyRetryAttempt(event, priorOrdered, allMembers) {
|
|
1792
1851
|
const workflow = workflowFor(event);
|
|
@@ -1836,13 +1895,88 @@ function classifyRetryAttempt(event, priorOrdered, allMembers) {
|
|
|
1836
1895
|
}
|
|
1837
1896
|
return { kind: "unknown", reason: "ambiguous attempt identity" };
|
|
1838
1897
|
}
|
|
1839
|
-
function
|
|
1840
|
-
const
|
|
1898
|
+
function redeliveryFingerprint(event) {
|
|
1899
|
+
const workflow = workflowFor(event);
|
|
1900
|
+
return deliverySemanticFingerprint({
|
|
1901
|
+
eventId: event.eventId ?? "",
|
|
1902
|
+
runId: event.runId,
|
|
1903
|
+
kind: event.kind,
|
|
1904
|
+
name: event.name,
|
|
1905
|
+
status: event.status,
|
|
1906
|
+
parentId: event.parentId,
|
|
1907
|
+
timestamp: event.timestamp,
|
|
1908
|
+
startedAt: event.startedAt,
|
|
1909
|
+
sourceType: event.source?.type,
|
|
1910
|
+
attributes: event.attributes && typeof event.attributes === "object" ? event.attributes : void 0,
|
|
1911
|
+
operationId: workflow.operationId ?? null,
|
|
1912
|
+
attemptId: workflow.attemptId ?? null,
|
|
1913
|
+
attemptNumber: workflow.attemptNumber ?? null,
|
|
1914
|
+
retryOf: workflow.retryOf ?? null
|
|
1915
|
+
});
|
|
1916
|
+
}
|
|
1917
|
+
var IDENTITY_KEYS = ["operationId", "attemptId", "retryOf", "attemptNumber"];
|
|
1918
|
+
function identityValuesEqual(a, b) {
|
|
1919
|
+
if (typeof a === "number" && typeof b === "number") {
|
|
1920
|
+
return Number.isFinite(a) && Number.isFinite(b) && a === b;
|
|
1921
|
+
}
|
|
1922
|
+
if (typeof a === "string" && typeof b === "string") {
|
|
1923
|
+
return a.trim() === b.trim();
|
|
1924
|
+
}
|
|
1925
|
+
return a === b;
|
|
1926
|
+
}
|
|
1927
|
+
function directNestedIdentityConflicts(event) {
|
|
1928
|
+
const attrs2 = event.attributes;
|
|
1929
|
+
if (!attrs2 || typeof attrs2 !== "object") return [];
|
|
1930
|
+
const nested = attrs2.metadata && typeof attrs2.metadata === "object" && !Array.isArray(attrs2.metadata) ? attrs2.metadata : void 0;
|
|
1931
|
+
if (!nested) return [];
|
|
1932
|
+
const conflicts = [];
|
|
1933
|
+
for (const key of IDENTITY_KEYS) {
|
|
1934
|
+
const direct = attrs2[key];
|
|
1935
|
+
const nestedValue = nested[key];
|
|
1936
|
+
if (direct === void 0 || nestedValue === void 0) continue;
|
|
1937
|
+
if (!identityValuesEqual(direct, nestedValue)) {
|
|
1938
|
+
conflicts.push(key);
|
|
1939
|
+
}
|
|
1940
|
+
}
|
|
1941
|
+
return conflicts;
|
|
1942
|
+
}
|
|
1943
|
+
function hasConflictingAttemptIdReuse(members) {
|
|
1944
|
+
const byAttempt = /* @__PURE__ */ new Map();
|
|
1841
1945
|
for (const event of members) {
|
|
1946
|
+
if (event.kind !== "TOOL" && event.kind !== "LLM") continue;
|
|
1842
1947
|
const id = attemptIdOf(event);
|
|
1843
1948
|
if (!id) continue;
|
|
1844
|
-
|
|
1845
|
-
|
|
1949
|
+
const fingerprints = byAttempt.get(id) ?? /* @__PURE__ */ new Set();
|
|
1950
|
+
fingerprints.add(redeliveryFingerprint(event));
|
|
1951
|
+
byAttempt.set(id, fingerprints);
|
|
1952
|
+
}
|
|
1953
|
+
for (const fingerprints of byAttempt.values()) {
|
|
1954
|
+
if (fingerprints.size > 1) return true;
|
|
1955
|
+
}
|
|
1956
|
+
return false;
|
|
1957
|
+
}
|
|
1958
|
+
function hasConflictingEventIdReuse(members) {
|
|
1959
|
+
const byEventId = /* @__PURE__ */ new Map();
|
|
1960
|
+
for (const event of members) {
|
|
1961
|
+
if (event.kind !== "TOOL" && event.kind !== "LLM") continue;
|
|
1962
|
+
const eventId = event.eventId;
|
|
1963
|
+
if (!eventId) continue;
|
|
1964
|
+
if (hasDeliveryConflictMarker(event.attributes)) {
|
|
1965
|
+
return true;
|
|
1966
|
+
}
|
|
1967
|
+
const fingerprints = byEventId.get(eventId) ?? /* @__PURE__ */ new Set();
|
|
1968
|
+
fingerprints.add(redeliveryFingerprint(event));
|
|
1969
|
+
byEventId.set(eventId, fingerprints);
|
|
1970
|
+
}
|
|
1971
|
+
for (const fingerprints of byEventId.values()) {
|
|
1972
|
+
if (fingerprints.size > 1) return true;
|
|
1973
|
+
}
|
|
1974
|
+
return false;
|
|
1975
|
+
}
|
|
1976
|
+
function hasIdentityRepresentationConflict(members) {
|
|
1977
|
+
for (const event of members) {
|
|
1978
|
+
if (event.kind !== "TOOL" && event.kind !== "LLM") continue;
|
|
1979
|
+
if (directNestedIdentityConflicts(event).length > 0) return true;
|
|
1846
1980
|
}
|
|
1847
1981
|
return false;
|
|
1848
1982
|
}
|
|
@@ -1853,23 +1987,49 @@ function evaluateRetrySafetyRules(events, rules, _runEvidence) {
|
|
|
1853
1987
|
const workflow = workflowFor(event);
|
|
1854
1988
|
const operationId = workflow.operationId;
|
|
1855
1989
|
if (!operationId) continue;
|
|
1856
|
-
const
|
|
1857
|
-
|
|
1858
|
-
|
|
1990
|
+
const key = `${event.runId}\0${operationId}`;
|
|
1991
|
+
const group = byOperation.get(key) ?? { operationId, members: [] };
|
|
1992
|
+
group.members.push(event);
|
|
1993
|
+
byOperation.set(key, group);
|
|
1859
1994
|
}
|
|
1860
1995
|
if (rules.maxAttempts !== void 0) {
|
|
1861
|
-
for (const
|
|
1862
|
-
if (
|
|
1996
|
+
for (const { operationId, members } of byOperation.values()) {
|
|
1997
|
+
if (hasConflictingAttemptIdReuse(members) || hasConflictingEventIdReuse(members)) {
|
|
1863
1998
|
findings.push(
|
|
1864
1999
|
fail2(
|
|
1865
2000
|
"contract.retry.duplicate-attempt-id",
|
|
1866
|
-
`Operation ${operationId} has
|
|
2001
|
+
`Operation ${operationId} has conflicting attemptId reuse (distinct executions).`,
|
|
1867
2002
|
members.slice(0, 4).map(eventEvidence),
|
|
1868
2003
|
"unique attemptId",
|
|
1869
2004
|
"duplicate"
|
|
1870
2005
|
)
|
|
1871
2006
|
);
|
|
1872
2007
|
}
|
|
2008
|
+
if (hasIdentityRepresentationConflict(members)) {
|
|
2009
|
+
findings.push(
|
|
2010
|
+
fail2(
|
|
2011
|
+
"contract.retry.ambiguous-identity",
|
|
2012
|
+
`Operation ${operationId} has conflicting direct vs nested identity fields; strict identity cannot pass.`,
|
|
2013
|
+
members.slice(0, 4).map(eventEvidence),
|
|
2014
|
+
"agreeing identity representation",
|
|
2015
|
+
"direct/nested conflict"
|
|
2016
|
+
)
|
|
2017
|
+
);
|
|
2018
|
+
}
|
|
2019
|
+
const toolish = members.filter((event) => event.kind === "TOOL" || event.kind === "LLM");
|
|
2020
|
+
const hasAttemptId = toolish.some((event) => attemptIdOf(event) !== void 0);
|
|
2021
|
+
const missingAttemptId = toolish.some((event) => attemptIdOf(event) === void 0);
|
|
2022
|
+
if (hasAttemptId && missingAttemptId) {
|
|
2023
|
+
findings.push(
|
|
2024
|
+
fail2(
|
|
2025
|
+
"contract.retry.ambiguous-identity",
|
|
2026
|
+
`Operation ${operationId} has partial attempt identity; strict identity conformance cannot pass.`,
|
|
2027
|
+
members.slice(0, 4).map(eventEvidence),
|
|
2028
|
+
"complete attempt identity",
|
|
2029
|
+
"partial attemptId coverage"
|
|
2030
|
+
)
|
|
2031
|
+
);
|
|
2032
|
+
}
|
|
1873
2033
|
const count = countOperationAttempts(members);
|
|
1874
2034
|
if (count > rules.maxAttempts) {
|
|
1875
2035
|
findings.push(
|
|
@@ -1885,7 +2045,7 @@ function evaluateRetrySafetyRules(events, rules, _runEvidence) {
|
|
|
1885
2045
|
}
|
|
1886
2046
|
}
|
|
1887
2047
|
if (rules.requireTerminalResult) {
|
|
1888
|
-
for (const
|
|
2048
|
+
for (const { operationId, members } of byOperation.values()) {
|
|
1889
2049
|
const hasTerminal = members.some((event) => event.status === "ok" || event.status === "error");
|
|
1890
2050
|
if (!hasTerminal) {
|
|
1891
2051
|
findings.push(
|
|
@@ -1905,7 +2065,7 @@ function evaluateRetrySafetyRules(events, rules, _runEvidence) {
|
|
|
1905
2065
|
const workflow = workflowFor(event);
|
|
1906
2066
|
const fallbackOf = workflow.fallbackOf;
|
|
1907
2067
|
if (!fallbackOf) continue;
|
|
1908
|
-
const prior = byOperation.get(fallbackOf) ?? [];
|
|
2068
|
+
const prior = byOperation.get(`${event.runId}\0${fallbackOf}`)?.members ?? [];
|
|
1909
2069
|
const fallbackStart = eventTime(event);
|
|
1910
2070
|
const earlierFailure = prior.some(
|
|
1911
2071
|
(candidate) => candidate.status === "error" && eventTime(candidate) !== "" && fallbackStart !== "" && eventTime(candidate) < fallbackStart
|
|
@@ -1932,7 +2092,7 @@ function evaluateRetrySafetyRules(events, rules, _runEvidence) {
|
|
|
1932
2092
|
for (const event of toolEvents) {
|
|
1933
2093
|
const name = resolveCanonicalToolName(event);
|
|
1934
2094
|
const workflow = workflowFor(event);
|
|
1935
|
-
const key = `${workflow.operationId ?? name}::${name}`;
|
|
2095
|
+
const key = `${event.runId}::${workflow.operationId ?? name}::${name}`;
|
|
1936
2096
|
const list = byToolOp.get(key) ?? [];
|
|
1937
2097
|
list.push(event);
|
|
1938
2098
|
byToolOp.set(key, list);
|
|
@@ -1990,7 +2150,7 @@ function evaluateRetrySafetyRules(events, rules, _runEvidence) {
|
|
|
1990
2150
|
}
|
|
1991
2151
|
}
|
|
1992
2152
|
if (rules.requireRecoveredFailureVisible) {
|
|
1993
|
-
for (const
|
|
2153
|
+
for (const { operationId, members } of byOperation.values()) {
|
|
1994
2154
|
const ordered = sortByTime(members);
|
|
1995
2155
|
const toolish = ordered.filter(
|
|
1996
2156
|
(event) => (event.kind === "TOOL" || event.kind === "LLM") && (event.status === "ok" || event.status === "error")
|
|
@@ -2248,15 +2408,8 @@ function attemptIdOf2(event) {
|
|
|
2248
2408
|
const value = workflowFor2(event).attemptId;
|
|
2249
2409
|
return typeof value === "string" && value.trim() !== "" ? value.trim() : void 0;
|
|
2250
2410
|
}
|
|
2251
|
-
function
|
|
2252
|
-
|
|
2253
|
-
for (const event of members) {
|
|
2254
|
-
const id = attemptIdOf2(event);
|
|
2255
|
-
if (!id) continue;
|
|
2256
|
-
if (seen.has(id)) return true;
|
|
2257
|
-
seen.add(id);
|
|
2258
|
-
}
|
|
2259
|
-
return false;
|
|
2411
|
+
function hasDuplicateAttemptIds(members) {
|
|
2412
|
+
return hasConflictingAttemptIdReuse(members) || hasConflictingEventIdReuse(members);
|
|
2260
2413
|
}
|
|
2261
2414
|
function findRetryTarget(members, retryOf) {
|
|
2262
2415
|
return members.find(
|
|
@@ -2344,7 +2497,7 @@ function evaluateRecoveryOperations(events, operations) {
|
|
|
2344
2497
|
}
|
|
2345
2498
|
for (const [operationKey, members] of groups) {
|
|
2346
2499
|
const ordered = sortByTime2(members);
|
|
2347
|
-
if (
|
|
2500
|
+
if (hasDuplicateAttemptIds(members)) {
|
|
2348
2501
|
findings.push(
|
|
2349
2502
|
fail3(
|
|
2350
2503
|
"contract.retry.operations.duplicate-attempt-id",
|