@rlynjb/aptkit-core 0.1.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.
Files changed (132) hide show
  1. package/README.md +19 -0
  2. package/dist/src/index.d.ts +12 -0
  3. package/dist/src/index.js +9 -0
  4. package/node_modules/@aptkit/agent-anomaly-monitoring/README.md +13 -0
  5. package/node_modules/@aptkit/agent-anomaly-monitoring/dist/src/categories.d.ts +11 -0
  6. package/node_modules/@aptkit/agent-anomaly-monitoring/dist/src/categories.js +100 -0
  7. package/node_modules/@aptkit/agent-anomaly-monitoring/dist/src/fixture-provider.d.ts +10 -0
  8. package/node_modules/@aptkit/agent-anomaly-monitoring/dist/src/fixture-provider.js +18 -0
  9. package/node_modules/@aptkit/agent-anomaly-monitoring/dist/src/index.d.ts +6 -0
  10. package/node_modules/@aptkit/agent-anomaly-monitoring/dist/src/index.js +6 -0
  11. package/node_modules/@aptkit/agent-anomaly-monitoring/dist/src/monitoring-agent.d.ts +32 -0
  12. package/node_modules/@aptkit/agent-anomaly-monitoring/dist/src/monitoring-agent.js +88 -0
  13. package/node_modules/@aptkit/agent-anomaly-monitoring/dist/src/schema-summary.d.ts +2 -0
  14. package/node_modules/@aptkit/agent-anomaly-monitoring/dist/src/schema-summary.js +7 -0
  15. package/node_modules/@aptkit/agent-anomaly-monitoring/dist/src/types.d.ts +32 -0
  16. package/node_modules/@aptkit/agent-anomaly-monitoring/dist/src/types.js +1 -0
  17. package/node_modules/@aptkit/agent-anomaly-monitoring/dist/src/validate.d.ts +9 -0
  18. package/node_modules/@aptkit/agent-anomaly-monitoring/dist/src/validate.js +34 -0
  19. package/node_modules/@aptkit/agent-anomaly-monitoring/fixtures/promoted/sp-revenue-monitoring-fixture-promoted-2026-06-18-18-37-26.json +229 -0
  20. package/node_modules/@aptkit/agent-anomaly-monitoring/fixtures/sp-revenue-monitoring.json +136 -0
  21. package/node_modules/@aptkit/agent-anomaly-monitoring/package.json +33 -0
  22. package/node_modules/@aptkit/agent-diagnostic-investigation/README.md +11 -0
  23. package/node_modules/@aptkit/agent-diagnostic-investigation/dist/src/diagnostic-agent.d.ts +27 -0
  24. package/node_modules/@aptkit/agent-diagnostic-investigation/dist/src/diagnostic-agent.js +95 -0
  25. package/node_modules/@aptkit/agent-diagnostic-investigation/dist/src/fixture-provider.d.ts +10 -0
  26. package/node_modules/@aptkit/agent-diagnostic-investigation/dist/src/fixture-provider.js +18 -0
  27. package/node_modules/@aptkit/agent-diagnostic-investigation/dist/src/index.d.ts +5 -0
  28. package/node_modules/@aptkit/agent-diagnostic-investigation/dist/src/index.js +5 -0
  29. package/node_modules/@aptkit/agent-diagnostic-investigation/dist/src/schema-summary.d.ts +1 -0
  30. package/node_modules/@aptkit/agent-diagnostic-investigation/dist/src/schema-summary.js +1 -0
  31. package/node_modules/@aptkit/agent-diagnostic-investigation/dist/src/types.d.ts +37 -0
  32. package/node_modules/@aptkit/agent-diagnostic-investigation/dist/src/types.js +1 -0
  33. package/node_modules/@aptkit/agent-diagnostic-investigation/dist/src/validate.d.ts +10 -0
  34. package/node_modules/@aptkit/agent-diagnostic-investigation/dist/src/validate.js +49 -0
  35. package/node_modules/@aptkit/agent-diagnostic-investigation/fixtures/promoted/sp-revenue-diagnostic-fixture-promoted-2026-06-18-19-04-28.json +230 -0
  36. package/node_modules/@aptkit/agent-diagnostic-investigation/fixtures/sp-revenue-diagnostic.json +148 -0
  37. package/node_modules/@aptkit/agent-diagnostic-investigation/package.json +33 -0
  38. package/node_modules/@aptkit/agent-query/README.md +11 -0
  39. package/node_modules/@aptkit/agent-query/dist/src/fixture-provider.d.ts +10 -0
  40. package/node_modules/@aptkit/agent-query/dist/src/fixture-provider.js +18 -0
  41. package/node_modules/@aptkit/agent-query/dist/src/index.d.ts +6 -0
  42. package/node_modules/@aptkit/agent-query/dist/src/index.js +6 -0
  43. package/node_modules/@aptkit/agent-query/dist/src/intent.d.ts +6 -0
  44. package/node_modules/@aptkit/agent-query/dist/src/intent.js +23 -0
  45. package/node_modules/@aptkit/agent-query/dist/src/query-agent.d.ts +27 -0
  46. package/node_modules/@aptkit/agent-query/dist/src/query-agent.js +81 -0
  47. package/node_modules/@aptkit/agent-query/dist/src/schema-summary.d.ts +1 -0
  48. package/node_modules/@aptkit/agent-query/dist/src/schema-summary.js +1 -0
  49. package/node_modules/@aptkit/agent-query/dist/src/types.d.ts +5 -0
  50. package/node_modules/@aptkit/agent-query/dist/src/types.js +1 -0
  51. package/node_modules/@aptkit/agent-query/dist/src/validate.d.ts +7 -0
  52. package/node_modules/@aptkit/agent-query/dist/src/validate.js +9 -0
  53. package/node_modules/@aptkit/agent-query/fixtures/promoted/revenue-by-state-query-fixture-promoted-2026-06-18-19-29-11.json +138 -0
  54. package/node_modules/@aptkit/agent-query/fixtures/revenue-by-state-query.json +79 -0
  55. package/node_modules/@aptkit/agent-query/package.json +33 -0
  56. package/node_modules/@aptkit/agent-recommendation/README.md +109 -0
  57. package/node_modules/@aptkit/agent-recommendation/dist/src/fixture-provider.d.ts +10 -0
  58. package/node_modules/@aptkit/agent-recommendation/dist/src/fixture-provider.js +18 -0
  59. package/node_modules/@aptkit/agent-recommendation/dist/src/index.d.ts +4 -0
  60. package/node_modules/@aptkit/agent-recommendation/dist/src/index.js +4 -0
  61. package/node_modules/@aptkit/agent-recommendation/dist/src/recommendation-agent.d.ts +30 -0
  62. package/node_modules/@aptkit/agent-recommendation/dist/src/recommendation-agent.js +85 -0
  63. package/node_modules/@aptkit/agent-recommendation/dist/src/schema-summary.d.ts +1 -0
  64. package/node_modules/@aptkit/agent-recommendation/dist/src/schema-summary.js +1 -0
  65. package/node_modules/@aptkit/agent-recommendation/dist/src/types.d.ts +68 -0
  66. package/node_modules/@aptkit/agent-recommendation/dist/src/types.js +3 -0
  67. package/node_modules/@aptkit/agent-recommendation/dist/src/validate.d.ts +3 -0
  68. package/node_modules/@aptkit/agent-recommendation/dist/src/validate.js +54 -0
  69. package/node_modules/@aptkit/agent-recommendation/fixtures/electronics-spike.json +84 -0
  70. package/node_modules/@aptkit/agent-recommendation/fixtures/promoted/voucher-dropoff-w10-on-openai-promoted-2026-06-18-16-53-02.json +166 -0
  71. package/node_modules/@aptkit/agent-recommendation/fixtures/promoted/voucher-dropoff-w10-on-openai-promoted-2026-06-18-17-20-55.json +157 -0
  72. package/node_modules/@aptkit/agent-recommendation/fixtures/sp-revenue-drop.json +83 -0
  73. package/node_modules/@aptkit/agent-recommendation/fixtures/voucher-dropoff.json +84 -0
  74. package/node_modules/@aptkit/agent-recommendation/package.json +34 -0
  75. package/node_modules/@aptkit/context/README.md +15 -0
  76. package/node_modules/@aptkit/context/dist/src/index.d.ts +2 -0
  77. package/node_modules/@aptkit/context/dist/src/index.js +2 -0
  78. package/node_modules/@aptkit/context/dist/src/workspace-descriptor.d.ts +25 -0
  79. package/node_modules/@aptkit/context/dist/src/workspace-descriptor.js +1 -0
  80. package/node_modules/@aptkit/context/dist/src/workspace-summary.d.ts +9 -0
  81. package/node_modules/@aptkit/context/dist/src/workspace-summary.js +38 -0
  82. package/node_modules/@aptkit/context/package.json +24 -0
  83. package/node_modules/@aptkit/evals/dist/src/assertions.d.ts +13 -0
  84. package/node_modules/@aptkit/evals/dist/src/assertions.js +351 -0
  85. package/node_modules/@aptkit/evals/dist/src/detection-scorer.d.ts +25 -0
  86. package/node_modules/@aptkit/evals/dist/src/detection-scorer.js +72 -0
  87. package/node_modules/@aptkit/evals/dist/src/index.d.ts +3 -0
  88. package/node_modules/@aptkit/evals/dist/src/index.js +3 -0
  89. package/node_modules/@aptkit/evals/dist/src/replay-runner.d.ts +29 -0
  90. package/node_modules/@aptkit/evals/dist/src/replay-runner.js +72 -0
  91. package/node_modules/@aptkit/evals/dist/src/structural-diff.d.ts +50 -0
  92. package/node_modules/@aptkit/evals/dist/src/structural-diff.js +143 -0
  93. package/node_modules/@aptkit/evals/package.json +27 -0
  94. package/node_modules/@aptkit/prompts/README.md +7 -0
  95. package/node_modules/@aptkit/prompts/dist/src/diagnostic.d.ts +3 -0
  96. package/node_modules/@aptkit/prompts/dist/src/diagnostic.js +85 -0
  97. package/node_modules/@aptkit/prompts/dist/src/index.d.ts +5 -0
  98. package/node_modules/@aptkit/prompts/dist/src/index.js +5 -0
  99. package/node_modules/@aptkit/prompts/dist/src/monitoring.d.ts +3 -0
  100. package/node_modules/@aptkit/prompts/dist/src/monitoring.js +57 -0
  101. package/node_modules/@aptkit/prompts/dist/src/query.d.ts +3 -0
  102. package/node_modules/@aptkit/prompts/dist/src/query.js +86 -0
  103. package/node_modules/@aptkit/prompts/dist/src/recommendation.d.ts +3 -0
  104. package/node_modules/@aptkit/prompts/dist/src/recommendation.js +110 -0
  105. package/node_modules/@aptkit/prompts/dist/src/types.d.ts +21 -0
  106. package/node_modules/@aptkit/prompts/dist/src/types.js +6 -0
  107. package/node_modules/@aptkit/prompts/package.json +24 -0
  108. package/node_modules/@aptkit/runtime/dist/src/events.d.ts +44 -0
  109. package/node_modules/@aptkit/runtime/dist/src/events.js +3 -0
  110. package/node_modules/@aptkit/runtime/dist/src/index.d.ts +6 -0
  111. package/node_modules/@aptkit/runtime/dist/src/index.js +6 -0
  112. package/node_modules/@aptkit/runtime/dist/src/json-output.d.ts +10 -0
  113. package/node_modules/@aptkit/runtime/dist/src/json-output.js +32 -0
  114. package/node_modules/@aptkit/runtime/dist/src/model-provider.d.ts +49 -0
  115. package/node_modules/@aptkit/runtime/dist/src/model-provider.js +1 -0
  116. package/node_modules/@aptkit/runtime/dist/src/ndjson-stream.d.ts +43 -0
  117. package/node_modules/@aptkit/runtime/dist/src/ndjson-stream.js +128 -0
  118. package/node_modules/@aptkit/runtime/dist/src/run-agent-loop.d.ts +42 -0
  119. package/node_modules/@aptkit/runtime/dist/src/run-agent-loop.js +138 -0
  120. package/node_modules/@aptkit/runtime/dist/src/usage-ledger.d.ts +29 -0
  121. package/node_modules/@aptkit/runtime/dist/src/usage-ledger.js +61 -0
  122. package/node_modules/@aptkit/runtime/package.json +23 -0
  123. package/node_modules/@aptkit/tools/dist/src/coverage-gate.d.ts +32 -0
  124. package/node_modules/@aptkit/tools/dist/src/coverage-gate.js +43 -0
  125. package/node_modules/@aptkit/tools/dist/src/index.d.ts +3 -0
  126. package/node_modules/@aptkit/tools/dist/src/index.js +3 -0
  127. package/node_modules/@aptkit/tools/dist/src/tool-policy.d.ts +9 -0
  128. package/node_modules/@aptkit/tools/dist/src/tool-policy.js +11 -0
  129. package/node_modules/@aptkit/tools/dist/src/tool-registry.d.ts +27 -0
  130. package/node_modules/@aptkit/tools/dist/src/tool-registry.js +25 -0
  131. package/node_modules/@aptkit/tools/package.json +26 -0
  132. package/package.json +53 -0
@@ -0,0 +1,2 @@
1
+ export * from './workspace-descriptor.js';
2
+ export * from './workspace-summary.js';
@@ -0,0 +1,25 @@
1
+ export type WorkspaceEventDescriptor = {
2
+ name: string;
3
+ properties: string[];
4
+ eventCount: number;
5
+ };
6
+ export type WorkspaceCatalogDescriptor = {
7
+ id?: string;
8
+ name: string;
9
+ };
10
+ export type DataHorizon = {
11
+ from: string;
12
+ to: string;
13
+ durationDays: number;
14
+ };
15
+ export type WorkspaceDescriptor = {
16
+ projectId: string;
17
+ projectName: string;
18
+ events: WorkspaceEventDescriptor[];
19
+ customerProperties: string[];
20
+ catalogs: WorkspaceCatalogDescriptor[];
21
+ totalCustomers: number;
22
+ totalEvents: number;
23
+ oldestTimestamp: number | null;
24
+ dataHorizon?: DataHorizon;
25
+ };
@@ -0,0 +1,9 @@
1
+ import type { WorkspaceDescriptor } from './workspace-descriptor.js';
2
+ export type WorkspaceSummaryOptions = {
3
+ maxEvents?: number;
4
+ maxEventProperties?: number;
5
+ maxCustomerProperties?: number;
6
+ horizonStyle?: 'arrow-with-query-rule' | 'plain';
7
+ eventHeading?: string;
8
+ };
9
+ export declare function schemaSummary(workspace: WorkspaceDescriptor, options?: WorkspaceSummaryOptions): string;
@@ -0,0 +1,38 @@
1
+ export function schemaSummary(workspace, options = {}) {
2
+ const { maxEvents = 20, maxEventProperties = 10, maxCustomerProperties = 30, horizonStyle = 'arrow-with-query-rule', eventHeading = 'Top events (name, eventCount: properties):', } = options;
3
+ const oldestDate = workspace.oldestTimestamp
4
+ ? new Date(workspace.oldestTimestamp).toISOString().slice(0, 10)
5
+ : 'unknown';
6
+ const eventsText = workspace.events
7
+ .slice(0, maxEvents)
8
+ .map((event) => {
9
+ const props = event.properties.slice(0, maxEventProperties).join(', ');
10
+ return ` - ${event.name} (${event.eventCount}): ${props || '(no properties)'}`;
11
+ })
12
+ .join('\n');
13
+ const customerPropsText = workspace.customerProperties
14
+ .slice(0, maxCustomerProperties)
15
+ .join(', ') || 'none';
16
+ const horizonLine = formatDataHorizon(workspace, horizonStyle);
17
+ return [
18
+ `Project: ${workspace.projectName} (${workspace.projectId})`,
19
+ `Total customers: ${workspace.totalCustomers.toLocaleString()}`,
20
+ `Total events: ${workspace.totalEvents.toLocaleString()}`,
21
+ `Oldest data: ${oldestDate}`,
22
+ ...(horizonLine ? [horizonLine] : []),
23
+ `Catalogs: ${workspace.catalogs.map((catalog) => catalog.name).join(', ') || 'none'}`,
24
+ '',
25
+ eventHeading,
26
+ eventsText,
27
+ '',
28
+ `Customer properties: ${customerPropsText}`,
29
+ ].join('\n');
30
+ }
31
+ function formatDataHorizon(workspace, horizonStyle) {
32
+ if (!workspace.dataHorizon)
33
+ return null;
34
+ if (horizonStyle === 'plain') {
35
+ return `Data horizon: ${workspace.dataHorizon.from} to ${workspace.dataHorizon.to} (${workspace.dataHorizon.durationDays} days; to exclusive).`;
36
+ }
37
+ return `Data horizon: ${workspace.dataHorizon.from} -> ${workspace.dataHorizon.to} (${workspace.dataHorizon.durationDays} days; to exclusive). ALL queries MUST land inside this window.`;
38
+ }
@@ -0,0 +1,24 @@
1
+ {
2
+ "name": "@aptkit/context",
3
+ "version": "0.0.0",
4
+ "type": "module",
5
+ "main": "./dist/src/index.js",
6
+ "types": "./dist/src/index.d.ts",
7
+ "files": [
8
+ "README.md",
9
+ "dist/src"
10
+ ],
11
+ "exports": {
12
+ ".": {
13
+ "types": "./dist/src/index.d.ts",
14
+ "import": "./dist/src/index.js"
15
+ }
16
+ },
17
+ "scripts": {
18
+ "build": "tsc -p tsconfig.json",
19
+ "test": "npm run build && node --test dist/test/*.test.js"
20
+ },
21
+ "devDependencies": {
22
+ "@types/node": "^20.0.0"
23
+ }
24
+ }
@@ -0,0 +1,13 @@
1
+ import { type StructuralDiffResult } from './structural-diff.js';
2
+ export type EvalAssertionResult = StructuralDiffResult & {
3
+ name: string;
4
+ };
5
+ export declare function assertRecommendationShape(output: unknown): EvalAssertionResult;
6
+ export declare function assertAnomalyShape(output: unknown): EvalAssertionResult;
7
+ export declare function assertCapabilityReplayArtifactShape(output: unknown): EvalAssertionResult;
8
+ export declare function assertQueryAnswerShape(output: unknown): EvalAssertionResult;
9
+ export declare function assertReplayArtifactShape(output: unknown): EvalAssertionResult;
10
+ export declare function assertMonitoringReplayArtifactShape(output: unknown): EvalAssertionResult;
11
+ export declare function assertDiagnosticShape(output: unknown): EvalAssertionResult;
12
+ export declare function assertDiagnosticReplayArtifactShape(output: unknown): EvalAssertionResult;
13
+ export declare function assertQueryReplayArtifactShape(output: unknown): EvalAssertionResult;
@@ -0,0 +1,351 @@
1
+ import { assertRequiredPaths } from './structural-diff.js';
2
+ export function assertRecommendationShape(output) {
3
+ const result = assertRequiredPaths(output, [
4
+ '0.title',
5
+ '0.rationale',
6
+ '0.bloomreachFeature',
7
+ '0.steps',
8
+ '0.estimatedImpact',
9
+ '0.confidence',
10
+ ]);
11
+ return { name: 'recommendation-shape', ...result };
12
+ }
13
+ export function assertAnomalyShape(output) {
14
+ if (Array.isArray(output) && output.length === 0) {
15
+ return { name: 'anomaly-shape', ok: true, issues: [] };
16
+ }
17
+ const result = assertRequiredPaths(output, [
18
+ '0.metric',
19
+ '0.scope',
20
+ '0.change.value',
21
+ '0.change.direction',
22
+ '0.change.baseline',
23
+ '0.severity',
24
+ ]);
25
+ return { name: 'anomaly-shape', ...result };
26
+ }
27
+ export function assertCapabilityReplayArtifactShape(output) {
28
+ if (isRecord(output) && (output.capabilityId === 'query-agent' || typeof output.answer === 'string')) {
29
+ return assertQueryReplayArtifactShape(output);
30
+ }
31
+ if (isRecord(output) && (output.capabilityId === 'diagnostic-investigation-agent' || isRecord(output.diagnosis))) {
32
+ return assertDiagnosticReplayArtifactShape(output);
33
+ }
34
+ if (isRecord(output) && (output.capabilityId === 'anomaly-monitoring-agent' || Array.isArray(output.anomalies))) {
35
+ return assertMonitoringReplayArtifactShape(output);
36
+ }
37
+ return assertReplayArtifactShape(output);
38
+ }
39
+ export function assertQueryAnswerShape(output) {
40
+ const issues = [];
41
+ if (typeof output !== 'string') {
42
+ issues.push({ path: '', message: 'answer must be a string' });
43
+ }
44
+ else if (output.trim().length < 20) {
45
+ issues.push({ path: '', message: 'answer is too short to be useful' });
46
+ }
47
+ return { name: 'query-answer-shape', ok: issues.length === 0, issues };
48
+ }
49
+ export function assertReplayArtifactShape(output) {
50
+ const result = assertRequiredPaths(output, [
51
+ 'schemaVersion',
52
+ 'createdAt',
53
+ 'durationMs',
54
+ 'provider.id',
55
+ 'provider.model',
56
+ 'fixture.id',
57
+ 'fixture.path',
58
+ 'recommendations',
59
+ 'trace',
60
+ 'eval.name',
61
+ 'eval.ok',
62
+ 'modelTurns',
63
+ ]);
64
+ const issues = [...result.issues];
65
+ if (!isRecord(output)) {
66
+ return {
67
+ name: 'replay-artifact-shape',
68
+ ok: false,
69
+ issues: [{ path: '', message: 'artifact must be an object' }, ...issues],
70
+ };
71
+ }
72
+ if (output.schemaVersion !== 1) {
73
+ issues.push({ path: 'schemaVersion', message: 'expected schemaVersion 1' });
74
+ }
75
+ if (typeof output.createdAt !== 'string' || Number.isNaN(Date.parse(output.createdAt))) {
76
+ issues.push({ path: 'createdAt', message: 'expected an ISO timestamp string' });
77
+ }
78
+ if (typeof output.durationMs !== 'number' || output.durationMs < 0) {
79
+ issues.push({ path: 'durationMs', message: 'expected a non-negative number' });
80
+ }
81
+ if (typeof output.modelTurns !== 'number' || output.modelTurns < 0) {
82
+ issues.push({ path: 'modelTurns', message: 'expected a non-negative number' });
83
+ }
84
+ if (!Array.isArray(output.trace)) {
85
+ issues.push({ path: 'trace', message: 'expected an array' });
86
+ }
87
+ const recommendations = output.recommendations;
88
+ if (!Array.isArray(recommendations)) {
89
+ issues.push({ path: 'recommendations', message: 'expected an array' });
90
+ }
91
+ else {
92
+ const recommendationResult = assertRecommendationShape(recommendations);
93
+ for (const issue of recommendationResult.issues) {
94
+ issues.push({ path: `recommendations.${issue.path}`, message: issue.message });
95
+ }
96
+ }
97
+ const replayEval = output.eval;
98
+ if (!isRecord(replayEval) || replayEval.ok !== true) {
99
+ issues.push({ path: 'eval.ok', message: 'expected embedded replay eval to pass' });
100
+ }
101
+ validatePromptPackageProvenance(output, issues);
102
+ const secretIssue = findSecretLikeString(output);
103
+ if (secretIssue) {
104
+ issues.push(secretIssue);
105
+ }
106
+ return { name: 'replay-artifact-shape', ok: issues.length === 0, issues };
107
+ }
108
+ export function assertMonitoringReplayArtifactShape(output) {
109
+ const result = assertRequiredPaths(output, [
110
+ 'schemaVersion',
111
+ 'capabilityId',
112
+ 'createdAt',
113
+ 'durationMs',
114
+ 'provider.id',
115
+ 'provider.model',
116
+ 'fixture.id',
117
+ 'fixture.path',
118
+ 'anomalies',
119
+ 'trace',
120
+ 'eval.name',
121
+ 'eval.ok',
122
+ 'modelTurns',
123
+ ]);
124
+ const issues = [...result.issues];
125
+ if (!isRecord(output)) {
126
+ return {
127
+ name: 'monitoring-replay-artifact-shape',
128
+ ok: false,
129
+ issues: [{ path: '', message: 'artifact must be an object' }, ...issues],
130
+ };
131
+ }
132
+ if (output.schemaVersion !== 1) {
133
+ issues.push({ path: 'schemaVersion', message: 'expected schemaVersion 1' });
134
+ }
135
+ if (output.capabilityId !== 'anomaly-monitoring-agent') {
136
+ issues.push({ path: 'capabilityId', message: 'expected anomaly-monitoring-agent' });
137
+ }
138
+ if (typeof output.createdAt !== 'string' || Number.isNaN(Date.parse(output.createdAt))) {
139
+ issues.push({ path: 'createdAt', message: 'expected an ISO timestamp string' });
140
+ }
141
+ if (typeof output.durationMs !== 'number' || output.durationMs < 0) {
142
+ issues.push({ path: 'durationMs', message: 'expected a non-negative number' });
143
+ }
144
+ if (typeof output.modelTurns !== 'number' || output.modelTurns < 0) {
145
+ issues.push({ path: 'modelTurns', message: 'expected a non-negative number' });
146
+ }
147
+ if (!Array.isArray(output.trace)) {
148
+ issues.push({ path: 'trace', message: 'expected an array' });
149
+ }
150
+ const anomalies = output.anomalies;
151
+ if (!Array.isArray(anomalies)) {
152
+ issues.push({ path: 'anomalies', message: 'expected an array' });
153
+ }
154
+ else {
155
+ const anomalyResult = assertAnomalyShape(anomalies);
156
+ for (const issue of anomalyResult.issues) {
157
+ issues.push({ path: `anomalies.${issue.path}`, message: issue.message });
158
+ }
159
+ }
160
+ const replayEval = output.eval;
161
+ if (!isRecord(replayEval) || replayEval.ok !== true) {
162
+ issues.push({ path: 'eval.ok', message: 'expected embedded replay eval to pass' });
163
+ }
164
+ validatePromptPackageProvenance(output, issues);
165
+ const secretIssue = findSecretLikeString(output);
166
+ if (secretIssue) {
167
+ issues.push(secretIssue);
168
+ }
169
+ return { name: 'monitoring-replay-artifact-shape', ok: issues.length === 0, issues };
170
+ }
171
+ export function assertDiagnosticShape(output) {
172
+ const result = assertRequiredPaths(output, [
173
+ 'conclusion',
174
+ 'evidence',
175
+ 'hypothesesConsidered',
176
+ ]);
177
+ const issues = [...result.issues];
178
+ if (!isRecord(output)) {
179
+ return {
180
+ name: 'diagnosis-shape',
181
+ ok: false,
182
+ issues: [{ path: '', message: 'diagnosis must be an object' }, ...issues],
183
+ };
184
+ }
185
+ if (!Array.isArray(output.evidence)) {
186
+ issues.push({ path: 'evidence', message: 'expected an array' });
187
+ }
188
+ if (!Array.isArray(output.hypothesesConsidered)) {
189
+ issues.push({ path: 'hypothesesConsidered', message: 'expected an array' });
190
+ }
191
+ return { name: 'diagnosis-shape', ok: issues.length === 0, issues };
192
+ }
193
+ export function assertDiagnosticReplayArtifactShape(output) {
194
+ const result = assertRequiredPaths(output, [
195
+ 'schemaVersion',
196
+ 'capabilityId',
197
+ 'createdAt',
198
+ 'durationMs',
199
+ 'provider.id',
200
+ 'provider.model',
201
+ 'fixture.id',
202
+ 'fixture.path',
203
+ 'diagnosis',
204
+ 'trace',
205
+ 'eval.name',
206
+ 'eval.ok',
207
+ 'modelTurns',
208
+ ]);
209
+ const issues = [...result.issues];
210
+ if (!isRecord(output)) {
211
+ return {
212
+ name: 'diagnostic-replay-artifact-shape',
213
+ ok: false,
214
+ issues: [{ path: '', message: 'artifact must be an object' }, ...issues],
215
+ };
216
+ }
217
+ if (output.schemaVersion !== 1) {
218
+ issues.push({ path: 'schemaVersion', message: 'expected schemaVersion 1' });
219
+ }
220
+ if (output.capabilityId !== 'diagnostic-investigation-agent') {
221
+ issues.push({ path: 'capabilityId', message: 'expected diagnostic-investigation-agent' });
222
+ }
223
+ if (typeof output.createdAt !== 'string' || Number.isNaN(Date.parse(output.createdAt))) {
224
+ issues.push({ path: 'createdAt', message: 'expected an ISO timestamp string' });
225
+ }
226
+ if (typeof output.durationMs !== 'number' || output.durationMs < 0) {
227
+ issues.push({ path: 'durationMs', message: 'expected a non-negative number' });
228
+ }
229
+ if (typeof output.modelTurns !== 'number' || output.modelTurns < 0) {
230
+ issues.push({ path: 'modelTurns', message: 'expected a non-negative number' });
231
+ }
232
+ if (!Array.isArray(output.trace)) {
233
+ issues.push({ path: 'trace', message: 'expected an array' });
234
+ }
235
+ const diagnosisResult = assertDiagnosticShape(output.diagnosis);
236
+ for (const issue of diagnosisResult.issues) {
237
+ issues.push({ path: `diagnosis.${issue.path}`, message: issue.message });
238
+ }
239
+ const replayEval = output.eval;
240
+ if (!isRecord(replayEval) || replayEval.ok !== true) {
241
+ issues.push({ path: 'eval.ok', message: 'expected embedded replay eval to pass' });
242
+ }
243
+ validatePromptPackageProvenance(output, issues);
244
+ const secretIssue = findSecretLikeString(output);
245
+ if (secretIssue) {
246
+ issues.push(secretIssue);
247
+ }
248
+ return { name: 'diagnostic-replay-artifact-shape', ok: issues.length === 0, issues };
249
+ }
250
+ export function assertQueryReplayArtifactShape(output) {
251
+ const result = assertRequiredPaths(output, [
252
+ 'schemaVersion',
253
+ 'capabilityId',
254
+ 'createdAt',
255
+ 'durationMs',
256
+ 'provider.id',
257
+ 'provider.model',
258
+ 'fixture.id',
259
+ 'fixture.path',
260
+ 'answer',
261
+ 'trace',
262
+ 'eval.name',
263
+ 'eval.ok',
264
+ 'modelTurns',
265
+ ]);
266
+ const issues = [...result.issues];
267
+ if (!isRecord(output)) {
268
+ return {
269
+ name: 'query-replay-artifact-shape',
270
+ ok: false,
271
+ issues: [{ path: '', message: 'artifact must be an object' }, ...issues],
272
+ };
273
+ }
274
+ if (output.schemaVersion !== 1) {
275
+ issues.push({ path: 'schemaVersion', message: 'expected schemaVersion 1' });
276
+ }
277
+ if (output.capabilityId !== 'query-agent') {
278
+ issues.push({ path: 'capabilityId', message: 'expected query-agent' });
279
+ }
280
+ if (typeof output.createdAt !== 'string' || Number.isNaN(Date.parse(output.createdAt))) {
281
+ issues.push({ path: 'createdAt', message: 'expected an ISO timestamp string' });
282
+ }
283
+ if (typeof output.durationMs !== 'number' || output.durationMs < 0) {
284
+ issues.push({ path: 'durationMs', message: 'expected a non-negative number' });
285
+ }
286
+ if (typeof output.modelTurns !== 'number' || output.modelTurns < 0) {
287
+ issues.push({ path: 'modelTurns', message: 'expected a non-negative number' });
288
+ }
289
+ if (!Array.isArray(output.trace)) {
290
+ issues.push({ path: 'trace', message: 'expected an array' });
291
+ }
292
+ const answerResult = assertQueryAnswerShape(output.answer);
293
+ for (const issue of answerResult.issues) {
294
+ issues.push({ path: `answer.${issue.path}`, message: issue.message });
295
+ }
296
+ const replayEval = output.eval;
297
+ if (!isRecord(replayEval) || replayEval.ok !== true) {
298
+ issues.push({ path: 'eval.ok', message: 'expected embedded replay eval to pass' });
299
+ }
300
+ validatePromptPackageProvenance(output, issues);
301
+ const secretIssue = findSecretLikeString(output);
302
+ if (secretIssue) {
303
+ issues.push(secretIssue);
304
+ }
305
+ return { name: 'query-replay-artifact-shape', ok: issues.length === 0, issues };
306
+ }
307
+ function isRecord(value) {
308
+ return Boolean(value) && typeof value === 'object' && !Array.isArray(value);
309
+ }
310
+ function validatePromptPackageProvenance(output, issues) {
311
+ if (output.promptPackage === undefined)
312
+ return;
313
+ if (!isRecord(output.promptPackage)) {
314
+ issues.push({ path: 'promptPackage', message: 'expected an object' });
315
+ return;
316
+ }
317
+ for (const path of ['id', 'version', 'capabilityId', 'templateHash', 'renderedHash']) {
318
+ if (typeof output.promptPackage[path] !== 'string' || output.promptPackage[path].trim().length === 0) {
319
+ issues.push({ path: `promptPackage.${path}`, message: 'expected a non-empty string' });
320
+ }
321
+ }
322
+ for (const path of ['templateChars', 'renderedChars']) {
323
+ if (typeof output.promptPackage[path] !== 'number' || output.promptPackage[path] <= 0) {
324
+ issues.push({ path: `promptPackage.${path}`, message: 'expected a positive number' });
325
+ }
326
+ }
327
+ }
328
+ function findSecretLikeString(value, path = '') {
329
+ if (typeof value === 'string') {
330
+ if (/sk-[A-Za-z0-9_-]{10,}/.test(value) || /OPENAI_API_KEY\s*=/.test(value)) {
331
+ return { path, message: 'artifact contains a secret-like string' };
332
+ }
333
+ return null;
334
+ }
335
+ if (Array.isArray(value)) {
336
+ for (let index = 0; index < value.length; index += 1) {
337
+ const issue = findSecretLikeString(value[index], path ? `${path}.${index}` : String(index));
338
+ if (issue)
339
+ return issue;
340
+ }
341
+ return null;
342
+ }
343
+ if (isRecord(value)) {
344
+ for (const [key, child] of Object.entries(value)) {
345
+ const issue = findSecretLikeString(child, path ? `${path}.${key}` : key);
346
+ if (issue)
347
+ return issue;
348
+ }
349
+ }
350
+ return null;
351
+ }
@@ -0,0 +1,25 @@
1
+ import type { StructuralIssue } from './structural-diff.js';
2
+ export type DetectionLike = {
3
+ category?: string;
4
+ metric?: string;
5
+ scope?: readonly string[];
6
+ severity?: string;
7
+ };
8
+ export type DetectionExpectations = {
9
+ minCount?: number;
10
+ maxCount?: number;
11
+ requiredCategories?: readonly string[];
12
+ requiredMetrics?: readonly string[];
13
+ requiredScopes?: readonly string[];
14
+ requiredSeverities?: readonly string[];
15
+ };
16
+ export type DetectionScoreResult = {
17
+ ok: boolean;
18
+ score: number;
19
+ matched: string[];
20
+ missed: string[];
21
+ unexpected: string[];
22
+ issues: StructuralIssue[];
23
+ };
24
+ /** Scores detection-like outputs against expected categories, metrics, scopes, severities, and counts. */
25
+ export declare function scoreDetections(detections: readonly DetectionLike[], expectations?: DetectionExpectations): DetectionScoreResult;
@@ -0,0 +1,72 @@
1
+ /** Scores detection-like outputs against expected categories, metrics, scopes, severities, and counts. */
2
+ export function scoreDetections(detections, expectations = {}) {
3
+ const required = [
4
+ ...(expectations.requiredCategories ?? []).map((value) => ({ kind: 'category', value })),
5
+ ...(expectations.requiredMetrics ?? []).map((value) => ({ kind: 'metric', value })),
6
+ ...(expectations.requiredScopes ?? []).map((value) => ({ kind: 'scope', value })),
7
+ ...(expectations.requiredSeverities ?? []).map((value) => ({ kind: 'severity', value })),
8
+ ];
9
+ const matched = [];
10
+ const missed = [];
11
+ const issues = [];
12
+ const minCount = expectations.minCount ?? 0;
13
+ if (detections.length < minCount) {
14
+ issues.push({ path: 'expectations.minCount', message: `expected at least ${minCount} detections, got ${detections.length}` });
15
+ }
16
+ if (expectations.maxCount !== undefined && detections.length > expectations.maxCount) {
17
+ issues.push({ path: 'expectations.maxCount', message: `expected at most ${expectations.maxCount} detections, got ${detections.length}` });
18
+ }
19
+ for (const requirement of required) {
20
+ const label = `${requirement.kind}:${requirement.value}`;
21
+ if (matchesRequirement(detections, requirement.kind, requirement.value)) {
22
+ matched.push(label);
23
+ }
24
+ else {
25
+ missed.push(label);
26
+ issues.push({
27
+ path: expectationPath(requirement.kind),
28
+ message: `expected ${requirement.kind}=${requirement.value}`,
29
+ });
30
+ }
31
+ }
32
+ const expectedCategories = new Set(expectations.requiredCategories ?? []);
33
+ const unexpected = detections
34
+ .map((detection) => detection.category)
35
+ .filter((category) => typeof category === 'string' && category.length > 0)
36
+ .filter((category) => expectedCategories.size > 0 && !expectedCategories.has(category))
37
+ .map((category) => `category:${category}`);
38
+ const requirementCount = required.length + (minCount > 0 ? 1 : 0) + (expectations.maxCount !== undefined ? 1 : 0);
39
+ const failedCount = missed.length + issues.filter((issue) => issue.path === 'expectations.minCount' || issue.path === 'expectations.maxCount').length;
40
+ const score = requirementCount === 0 ? 1 : Math.max(0, (requirementCount - failedCount) / requirementCount);
41
+ return {
42
+ ok: issues.length === 0,
43
+ score,
44
+ matched,
45
+ missed,
46
+ unexpected: [...new Set(unexpected)],
47
+ issues,
48
+ };
49
+ }
50
+ function matchesRequirement(detections, kind, value) {
51
+ return detections.some((detection) => {
52
+ if (kind === 'category')
53
+ return detection.category === value;
54
+ if (kind === 'metric')
55
+ return detection.metric === value;
56
+ if (kind === 'scope')
57
+ return detection.scope?.includes(value) ?? false;
58
+ if (kind === 'severity')
59
+ return detection.severity === value;
60
+ return false;
61
+ });
62
+ }
63
+ function capitalize(value) {
64
+ return `${value.charAt(0).toUpperCase()}${value.slice(1)}`;
65
+ }
66
+ function expectationPath(kind) {
67
+ if (kind === 'category')
68
+ return 'expectations.requiredCategories';
69
+ if (kind === 'severity')
70
+ return 'expectations.requiredSeverities';
71
+ return `expectations.required${capitalize(kind)}s`;
72
+ }
@@ -0,0 +1,3 @@
1
+ export * from './assertions.js';
2
+ export * from './detection-scorer.js';
3
+ export * from './structural-diff.js';
@@ -0,0 +1,3 @@
1
+ export * from './assertions.js';
2
+ export * from './detection-scorer.js';
3
+ export * from './structural-diff.js';
@@ -0,0 +1,29 @@
1
+ import { type EvalAssertionResult } from './assertions.js';
2
+ export type ReplayArtifactEvalSummary = {
3
+ path: string;
4
+ ok: boolean;
5
+ issues: EvalAssertionResult['issues'];
6
+ capabilityId: string;
7
+ provider: unknown;
8
+ fixture: string | null;
9
+ recommendationCount: number | null;
10
+ anomalyCount: number | null;
11
+ diagnosisPresent: boolean | null;
12
+ answerPresent: boolean | null;
13
+ };
14
+ export type ReplayArtifactEvalReport = {
15
+ ok: boolean;
16
+ checked: number;
17
+ failed: number;
18
+ results: ReplayArtifactEvalSummary[];
19
+ message?: string;
20
+ };
21
+ export type EvaluateReplayArtifactFilesOptions = {
22
+ cwd?: string;
23
+ };
24
+ /** Lists replay artifact JSON files in deterministic filename order. */
25
+ export declare function listReplayArtifacts(dir: string): Promise<string[]>;
26
+ /** Evaluates one parsed replay artifact and returns the CLI/Studio summary fields. */
27
+ export declare function evaluateReplayArtifact(artifact: unknown, path: string): ReplayArtifactEvalSummary;
28
+ /** Reads and evaluates replay artifact files, preserving the aggregate CLI report shape. */
29
+ export declare function evaluateReplayArtifactFiles(paths: readonly string[], options?: EvaluateReplayArtifactFilesOptions): Promise<ReplayArtifactEvalReport>;