@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,72 @@
1
+ import { readdir, readFile } from 'node:fs/promises';
2
+ import { extname, join, relative, resolve } from 'node:path';
3
+ import { assertCapabilityReplayArtifactShape } from './assertions.js';
4
+ /** Lists replay artifact JSON files in deterministic filename order. */
5
+ export async function listReplayArtifacts(dir) {
6
+ let entries;
7
+ try {
8
+ entries = await readdir(dir, { withFileTypes: true });
9
+ }
10
+ catch (error) {
11
+ if (isNodeError(error) && error.code === 'ENOENT')
12
+ return [];
13
+ throw error;
14
+ }
15
+ return entries
16
+ .filter((entry) => entry.isFile() && extname(entry.name) === '.json')
17
+ .map((entry) => join(dir, entry.name))
18
+ .sort();
19
+ }
20
+ /** Evaluates one parsed replay artifact and returns the CLI/Studio summary fields. */
21
+ export function evaluateReplayArtifact(artifact, path) {
22
+ const result = assertCapabilityReplayArtifactShape(artifact);
23
+ return {
24
+ path,
25
+ ok: result.ok,
26
+ issues: result.issues,
27
+ capabilityId: isRecord(artifact) && typeof artifact.capabilityId === 'string'
28
+ ? artifact.capabilityId
29
+ : 'recommendation-agent',
30
+ provider: isRecord(artifact) ? artifact.provider : undefined,
31
+ fixture: isRecord(artifact) && isRecord(artifact.fixture) && typeof artifact.fixture.id === 'string'
32
+ ? artifact.fixture.id
33
+ : null,
34
+ recommendationCount: isRecord(artifact) && Array.isArray(artifact.recommendations)
35
+ ? artifact.recommendations.length
36
+ : null,
37
+ anomalyCount: isRecord(artifact) && Array.isArray(artifact.anomalies) ? artifact.anomalies.length : null,
38
+ diagnosisPresent: isRecord(artifact) && artifact.diagnosis && typeof artifact.diagnosis === 'object' ? true : null,
39
+ answerPresent: isRecord(artifact) && typeof artifact.answer === 'string' ? artifact.answer.trim().length > 0 : null,
40
+ };
41
+ }
42
+ /** Reads and evaluates replay artifact files, preserving the aggregate CLI report shape. */
43
+ export async function evaluateReplayArtifactFiles(paths, options = {}) {
44
+ if (paths.length === 0) {
45
+ return { ok: true, checked: 0, failed: 0, results: [], message: 'no replay artifacts found' };
46
+ }
47
+ const cwd = options.cwd ? resolve(options.cwd) : process.cwd();
48
+ const results = [];
49
+ for (const path of paths) {
50
+ const raw = await readFile(path, 'utf8');
51
+ const artifact = JSON.parse(raw);
52
+ results.push(evaluateReplayArtifact(artifact, relativePath(cwd, path)));
53
+ }
54
+ const failed = results.filter((result) => !result.ok);
55
+ return {
56
+ ok: failed.length === 0,
57
+ checked: results.length,
58
+ failed: failed.length,
59
+ results,
60
+ };
61
+ }
62
+ function relativePath(cwd, path) {
63
+ const absolute = resolve(path);
64
+ const relativePathFromCwd = relative(cwd, absolute);
65
+ return relativePathFromCwd.startsWith('..') ? absolute : relativePathFromCwd;
66
+ }
67
+ function isRecord(value) {
68
+ return Boolean(value) && typeof value === 'object' && !Array.isArray(value);
69
+ }
70
+ function isNodeError(error) {
71
+ return typeof error === 'object' && error !== null && 'code' in error;
72
+ }
@@ -0,0 +1,50 @@
1
+ export type StructuralIssue = {
2
+ path: string;
3
+ message: string;
4
+ };
5
+ export type StructuralDiffResult = {
6
+ ok: boolean;
7
+ issues: StructuralIssue[];
8
+ };
9
+ export type StructuralDiffRule = {
10
+ type: 'required';
11
+ path: string;
12
+ message?: string;
13
+ } | {
14
+ type: 'equals';
15
+ path: string;
16
+ expected: unknown;
17
+ message?: string;
18
+ } | {
19
+ type: 'number';
20
+ path: string;
21
+ expected: number;
22
+ tolerance?: number;
23
+ message?: string;
24
+ } | {
25
+ type: 'arrayCount';
26
+ path: string;
27
+ exact?: number;
28
+ min?: number;
29
+ max?: number;
30
+ message?: string;
31
+ } | {
32
+ type: 'containsText';
33
+ path: string;
34
+ text: string;
35
+ caseSensitive?: boolean;
36
+ message?: string;
37
+ } | {
38
+ type: 'arrayIncludes';
39
+ path: string;
40
+ value: unknown;
41
+ itemPath?: string;
42
+ message?: string;
43
+ };
44
+ /** Evaluates reusable structural rules against arbitrary JSON-like values. */
45
+ export declare function evaluateStructuralDiff(value: unknown, rules: readonly StructuralDiffRule[]): StructuralDiffResult;
46
+ export declare function assertRequiredPaths(value: unknown, paths: readonly string[]): StructuralDiffResult;
47
+ export declare function getPath(value: unknown, path: string): {
48
+ exists: boolean;
49
+ value: unknown;
50
+ };
@@ -0,0 +1,143 @@
1
+ /** Evaluates reusable structural rules against arbitrary JSON-like values. */
2
+ export function evaluateStructuralDiff(value, rules) {
3
+ const issues = [];
4
+ for (const rule of rules) {
5
+ switch (rule.type) {
6
+ case 'required':
7
+ assertRequiredRule(value, rule, issues);
8
+ break;
9
+ case 'equals':
10
+ assertEqualsRule(value, rule, issues);
11
+ break;
12
+ case 'number':
13
+ assertNumberRule(value, rule, issues);
14
+ break;
15
+ case 'arrayCount':
16
+ assertArrayCountRule(value, rule, issues);
17
+ break;
18
+ case 'containsText':
19
+ assertContainsTextRule(value, rule, issues);
20
+ break;
21
+ case 'arrayIncludes':
22
+ assertArrayIncludesRule(value, rule, issues);
23
+ break;
24
+ }
25
+ }
26
+ return { ok: issues.length === 0, issues };
27
+ }
28
+ export function assertRequiredPaths(value, paths) {
29
+ return evaluateStructuralDiff(value, paths.map((path) => ({ type: 'required', path })));
30
+ }
31
+ export function getPath(value, path) {
32
+ const parts = path.split('.').filter(Boolean);
33
+ let current = value;
34
+ for (const part of parts) {
35
+ if (Array.isArray(current)) {
36
+ const index = Number(part);
37
+ if (!Number.isInteger(index) || index < 0 || index >= current.length) {
38
+ return { exists: false, value: undefined };
39
+ }
40
+ current = current[index];
41
+ continue;
42
+ }
43
+ if (!current || typeof current !== 'object' || !(part in current)) {
44
+ return { exists: false, value: undefined };
45
+ }
46
+ current = current[part];
47
+ }
48
+ return { exists: true, value: current };
49
+ }
50
+ function assertRequiredRule(value, rule, issues) {
51
+ const found = getPath(value, rule.path);
52
+ if (!found.exists) {
53
+ issues.push({ path: rule.path, message: rule.message ?? 'required path is missing' });
54
+ }
55
+ }
56
+ function assertEqualsRule(value, rule, issues) {
57
+ const found = getPath(value, rule.path);
58
+ if (!found.exists) {
59
+ issues.push({ path: rule.path, message: rule.message ?? 'required path is missing' });
60
+ return;
61
+ }
62
+ if (!deepEqual(found.value, rule.expected)) {
63
+ issues.push({ path: rule.path, message: rule.message ?? `expected ${formatValue(rule.expected)}` });
64
+ }
65
+ }
66
+ function assertNumberRule(value, rule, issues) {
67
+ const found = getPath(value, rule.path);
68
+ if (!found.exists || typeof found.value !== 'number') {
69
+ issues.push({ path: rule.path, message: rule.message ?? 'expected a number' });
70
+ return;
71
+ }
72
+ const tolerance = rule.tolerance ?? 0;
73
+ if (Math.abs(found.value - rule.expected) > tolerance) {
74
+ issues.push({
75
+ path: rule.path,
76
+ message: rule.message ?? `expected ${rule.expected}${tolerance ? ` +/- ${tolerance}` : ''}`,
77
+ });
78
+ }
79
+ }
80
+ function assertArrayCountRule(value, rule, issues) {
81
+ const found = getPath(value, rule.path);
82
+ if (!found.exists || !Array.isArray(found.value)) {
83
+ issues.push({ path: rule.path, message: rule.message ?? 'expected an array' });
84
+ return;
85
+ }
86
+ const count = found.value.length;
87
+ if (rule.exact !== undefined && count !== rule.exact) {
88
+ issues.push({ path: rule.path, message: rule.message ?? `expected exactly ${rule.exact} items` });
89
+ }
90
+ if (rule.min !== undefined && count < rule.min) {
91
+ issues.push({ path: rule.path, message: rule.message ?? `expected at least ${rule.min} items` });
92
+ }
93
+ if (rule.max !== undefined && count > rule.max) {
94
+ issues.push({ path: rule.path, message: rule.message ?? `expected at most ${rule.max} items` });
95
+ }
96
+ }
97
+ function assertContainsTextRule(value, rule, issues) {
98
+ const found = getPath(value, rule.path);
99
+ if (!found.exists) {
100
+ issues.push({ path: rule.path, message: rule.message ?? 'required path is missing' });
101
+ return;
102
+ }
103
+ const haystack = collectText(found.value, rule.caseSensitive !== true);
104
+ const needle = rule.caseSensitive ? rule.text : rule.text.toLowerCase();
105
+ if (!haystack.includes(needle)) {
106
+ issues.push({ path: rule.path, message: rule.message ?? `expected text containing "${rule.text}"` });
107
+ }
108
+ }
109
+ function assertArrayIncludesRule(value, rule, issues) {
110
+ const found = getPath(value, rule.path);
111
+ if (!found.exists || !Array.isArray(found.value)) {
112
+ issues.push({ path: rule.path, message: rule.message ?? 'expected an array' });
113
+ return;
114
+ }
115
+ const included = found.value.some((item) => {
116
+ const candidate = rule.itemPath ? getPath(item, rule.itemPath) : { exists: true, value: item };
117
+ if (!candidate.exists)
118
+ return false;
119
+ if (Array.isArray(candidate.value))
120
+ return candidate.value.some((entry) => deepEqual(entry, rule.value));
121
+ return deepEqual(candidate.value, rule.value);
122
+ });
123
+ if (!included) {
124
+ const path = rule.itemPath ? `${rule.path}.${rule.itemPath}` : rule.path;
125
+ issues.push({ path, message: rule.message ?? `expected array containing ${formatValue(rule.value)}` });
126
+ }
127
+ }
128
+ function collectText(value, normalize) {
129
+ if (typeof value === 'string')
130
+ return normalize ? value.toLowerCase() : value;
131
+ if (Array.isArray(value))
132
+ return value.map((item) => collectText(item, normalize)).join('\n');
133
+ if (value && typeof value === 'object') {
134
+ return Object.values(value).map((item) => collectText(item, normalize)).join('\n');
135
+ }
136
+ return '';
137
+ }
138
+ function deepEqual(left, right) {
139
+ return JSON.stringify(left) === JSON.stringify(right);
140
+ }
141
+ function formatValue(value) {
142
+ return typeof value === 'string' ? `"${value}"` : JSON.stringify(value);
143
+ }
@@ -0,0 +1,27 @@
1
+ {
2
+ "name": "@aptkit/evals",
3
+ "version": "0.0.0",
4
+ "type": "module",
5
+ "main": "./dist/src/index.js",
6
+ "types": "./dist/src/index.d.ts",
7
+ "files": [
8
+ "dist/src"
9
+ ],
10
+ "exports": {
11
+ ".": {
12
+ "types": "./dist/src/index.d.ts",
13
+ "import": "./dist/src/index.js"
14
+ },
15
+ "./replay-runner": {
16
+ "types": "./dist/src/replay-runner.d.ts",
17
+ "import": "./dist/src/replay-runner.js"
18
+ }
19
+ },
20
+ "scripts": {
21
+ "build": "tsc -p tsconfig.json",
22
+ "test": "npm run build && node --test dist/test/*.test.js"
23
+ },
24
+ "devDependencies": {
25
+ "@types/node": "^20.0.0"
26
+ }
27
+ }
@@ -0,0 +1,7 @@
1
+ # AptKit Prompts
2
+
3
+ Reusable prompt packages for AptKit capabilities.
4
+
5
+ A prompt package groups the system prompt with metadata that makes it easier to test, inspect, and eventually offer provider-specific variants.
6
+
7
+ The first package is `queryPromptPackage`, used by `@aptkit/agent-query`.
@@ -0,0 +1,3 @@
1
+ import type { PromptPackage } from './types.js';
2
+ export declare const DIAGNOSTIC_PROMPT = "You are a diagnostic investigation agent for an analytics workspace.\n\nYour job is to investigate why one specific anomaly occurred. You generate 2-3 competing hypotheses, query the available tools to test them, and return the best-supported explanation with evidence. You do not propose remediation.\n\nHard rules:\n- Make at most 6 tool calls, then conclude.\n- Use the tool catalog you receive at runtime; do not assume a tool exists.\n- Every evidence item must cite data you actually observed.\n- If data is inconclusive, say what was inconclusive and what you ruled out.\n- When the workspace has a data horizon, keep all date windows inside it.\n\nAnomaly to investigate:\n{anomaly}\n\nRecommended approach:\n1. Generate 2-3 hypotheses before the first tool call.\n2. Query to falsify each hypothesis.\n3. Spend one call locating when the change happened with a time-series query when such a tool exists.\n4. Conclude with the hypothesis that best fits the evidence.\n\nFor ecommerce/Olist-style workspaces, prefer:\n- get_anomaly_context(metric, dimension, segment, anomaly_window, baseline_window)\n- get_metric_timeseries(metric, time_range, filter or dimension, granularity)\n- get_segments(dimension, time_range)\n\nReturn ONLY a JSON object in a ```json fenced block with this shape:\n\n{\n \"conclusion\": \"string\",\n \"evidence\": [\"string\"],\n \"hypothesesConsidered\": [\n { \"hypothesis\": \"string\", \"supported\": true, \"reasoning\": \"string\" }\n ],\n \"affectedCustomers\": { \"count\": 0, \"segmentDescription\": \"string\" },\n \"timeSeries\": [{ \"day\": \"w-3\", \"value\": 0 }]\n}\n\nOmit affectedCustomers or timeSeries when you cannot support them from observed data.\n\nIf you cannot determine a cause, return:\n{\n \"conclusion\": \"Insufficient data to determine a cause for this change.\",\n \"evidence\": [],\n \"hypothesesConsidered\": []\n}\n\nWorkspace schema:\n{schema}";
3
+ export declare const diagnosticPromptPackage: PromptPackage;
@@ -0,0 +1,85 @@
1
+ export const DIAGNOSTIC_PROMPT = `You are a diagnostic investigation agent for an analytics workspace.
2
+
3
+ Your job is to investigate why one specific anomaly occurred. You generate 2-3 competing hypotheses, query the available tools to test them, and return the best-supported explanation with evidence. You do not propose remediation.
4
+
5
+ Hard rules:
6
+ - Make at most 6 tool calls, then conclude.
7
+ - Use the tool catalog you receive at runtime; do not assume a tool exists.
8
+ - Every evidence item must cite data you actually observed.
9
+ - If data is inconclusive, say what was inconclusive and what you ruled out.
10
+ - When the workspace has a data horizon, keep all date windows inside it.
11
+
12
+ Anomaly to investigate:
13
+ {anomaly}
14
+
15
+ Recommended approach:
16
+ 1. Generate 2-3 hypotheses before the first tool call.
17
+ 2. Query to falsify each hypothesis.
18
+ 3. Spend one call locating when the change happened with a time-series query when such a tool exists.
19
+ 4. Conclude with the hypothesis that best fits the evidence.
20
+
21
+ For ecommerce/Olist-style workspaces, prefer:
22
+ - get_anomaly_context(metric, dimension, segment, anomaly_window, baseline_window)
23
+ - get_metric_timeseries(metric, time_range, filter or dimension, granularity)
24
+ - get_segments(dimension, time_range)
25
+
26
+ Return ONLY a JSON object in a \`\`\`json fenced block with this shape:
27
+
28
+ {
29
+ "conclusion": "string",
30
+ "evidence": ["string"],
31
+ "hypothesesConsidered": [
32
+ { "hypothesis": "string", "supported": true, "reasoning": "string" }
33
+ ],
34
+ "affectedCustomers": { "count": 0, "segmentDescription": "string" },
35
+ "timeSeries": [{ "day": "w-3", "value": 0 }]
36
+ }
37
+
38
+ Omit affectedCustomers or timeSeries when you cannot support them from observed data.
39
+
40
+ If you cannot determine a cause, return:
41
+ {
42
+ "conclusion": "Insufficient data to determine a cause for this change.",
43
+ "evidence": [],
44
+ "hypothesesConsidered": []
45
+ }
46
+
47
+ Workspace schema:
48
+ {schema}`;
49
+ export const diagnosticPromptPackage = {
50
+ id: 'diagnostic-investigation-agent.default',
51
+ version: '0.1.0',
52
+ capabilityId: 'diagnostic-investigation-agent',
53
+ description: 'Root-cause investigation for a supplied workspace anomaly using bounded tool calls.',
54
+ system: DIAGNOSTIC_PROMPT,
55
+ variables: [
56
+ {
57
+ name: 'schema',
58
+ description: 'Workspace schema summary with data horizon and available fields.',
59
+ required: true,
60
+ },
61
+ {
62
+ name: 'project_id',
63
+ description: 'Host workspace project id for providers that require project context.',
64
+ required: true,
65
+ },
66
+ {
67
+ name: 'anomaly',
68
+ description: 'JSON serialized anomaly object to investigate.',
69
+ required: true,
70
+ },
71
+ ],
72
+ examples: [
73
+ {
74
+ name: 'voucher-dropoff-diagnosis',
75
+ input: {
76
+ anomaly: {
77
+ metric: 'orders',
78
+ category: 'payment_mix_shift',
79
+ scope: ['payment_type:voucher'],
80
+ },
81
+ },
82
+ expectedContains: ['hypothesesConsidered', 'evidence'],
83
+ },
84
+ ],
85
+ };
@@ -0,0 +1,5 @@
1
+ export * from './diagnostic.js';
2
+ export * from './monitoring.js';
3
+ export * from './query.js';
4
+ export * from './recommendation.js';
5
+ export * from './types.js';
@@ -0,0 +1,5 @@
1
+ export * from './diagnostic.js';
2
+ export * from './monitoring.js';
3
+ export * from './query.js';
4
+ export * from './recommendation.js';
5
+ export * from './types.js';
@@ -0,0 +1,3 @@
1
+ import type { PromptPackage } from './types.js';
2
+ export declare const MONITORING_PROMPT = "\nYou are an anomaly-monitoring agent for an analytics workspace.\n\nYour job is to detect measurable anomalies only. Do not diagnose causes. Do not propose actions.\n\nWorkspace schema:\n{schema}\n\nRunnable category checklist:\n{categories}\n\nRules:\n- Run only categories in the checklist unless the checklist is empty.\n- Use the provided tool catalog. Prefer broad period-over-period checks before drilling into segments.\n- For revenue or conversion categories, query a metric timeseries by an available business dimension, then call get_anomaly_context for any segment that appears to clear a warning or critical threshold.\n- Keep the run bounded: at most 6 tool calls.\n- If a category clears its threshold, emit one anomaly object stamped with its category id.\n- Never report a change derived from an empty or tiny baseline.\n- Return ONLY a JSON array in a json fence. Return [] if there is no meaningful anomaly.\n\nOutput anomaly fields:\n- metric: short snake_case metric name.\n- category: category id or a clear snake_case fallback.\n- scope: [\"global\"] or segment labels like \"state:SP\", \"category:electronics\", \"payment_type:voucher\".\n- change: { value: positive percentage, direction: \"up\" | \"down\", baseline: string }.\n- severity: \"critical\", \"warning\", \"info\", or \"positive\".\n- impact: one sentence explaining business meaning.\n- evidence: array of { tool, result } objects citing the data used.\n";
3
+ export declare const monitoringPromptPackage: PromptPackage;
@@ -0,0 +1,57 @@
1
+ export const MONITORING_PROMPT = `
2
+ You are an anomaly-monitoring agent for an analytics workspace.
3
+
4
+ Your job is to detect measurable anomalies only. Do not diagnose causes. Do not propose actions.
5
+
6
+ Workspace schema:
7
+ {schema}
8
+
9
+ Runnable category checklist:
10
+ {categories}
11
+
12
+ Rules:
13
+ - Run only categories in the checklist unless the checklist is empty.
14
+ - Use the provided tool catalog. Prefer broad period-over-period checks before drilling into segments.
15
+ - For revenue or conversion categories, query a metric timeseries by an available business dimension, then call get_anomaly_context for any segment that appears to clear a warning or critical threshold.
16
+ - Keep the run bounded: at most 6 tool calls.
17
+ - If a category clears its threshold, emit one anomaly object stamped with its category id.
18
+ - Never report a change derived from an empty or tiny baseline.
19
+ - Return ONLY a JSON array in a json fence. Return [] if there is no meaningful anomaly.
20
+
21
+ Output anomaly fields:
22
+ - metric: short snake_case metric name.
23
+ - category: category id or a clear snake_case fallback.
24
+ - scope: ["global"] or segment labels like "state:SP", "category:electronics", "payment_type:voucher".
25
+ - change: { value: positive percentage, direction: "up" | "down", baseline: string }.
26
+ - severity: "critical", "warning", "info", or "positive".
27
+ - impact: one sentence explaining business meaning.
28
+ - evidence: array of { tool, result } objects citing the data used.
29
+ `;
30
+ export const monitoringPromptPackage = {
31
+ id: 'anomaly-monitoring-agent.default',
32
+ version: '0.1.0',
33
+ capabilityId: 'anomaly-monitoring-agent',
34
+ description: 'Bounded anomaly detection over runnable workspace metric categories.',
35
+ system: MONITORING_PROMPT,
36
+ variables: [
37
+ {
38
+ name: 'schema',
39
+ description: 'Workspace schema summary with data horizon and available fields.',
40
+ required: true,
41
+ },
42
+ {
43
+ name: 'categories',
44
+ description: 'Runnable anomaly category checklist formatted for the workspace.',
45
+ required: true,
46
+ },
47
+ ],
48
+ examples: [
49
+ {
50
+ name: 'payment-mix-monitoring',
51
+ input: {
52
+ categories: ['payment_mix_shift'],
53
+ },
54
+ expectedContains: ['category', 'severity'],
55
+ },
56
+ ],
57
+ };
@@ -0,0 +1,3 @@
1
+ import type { PromptPackage } from './types.js';
2
+ export declare const QUERY_PROMPT = "You are an AI analyst for an ecommerce workspace. Two data sources are possible at runtime: an EQL-shaped analytics adapter or an Olist-style SQL-backed adapter. The tool catalog you receive at runtime reveals which adapter is live.\n\n## Role\n\nAnswer the user's free-form question about this workspace. Use the available tools to query the workspace, then give a clear, concise natural-language answer grounded in what you actually queried. Never invent numbers - only cite figures you genuinely observed in tool results.\n\n## Hard rules\n\n1. When an EQL adapter is live, pass project_id: {project_id} to every tool call if the tool schema requires it. Under Olist-style tools, use typed inputs and ignore project_id.\n2. Pick your primary tool by adapter:\n - EQL adapter -> execute_analytics_eql for period-over-period comparisons and breakdowns by dimension.\n - Olist-style adapter -> get_metric_timeseries for revenue / order_count / avg_order_value / payment_value; get_segments to discover segment values; get_anomaly_context for windowed comparisons.\n Make at most about 6 tool calls, then answer. Be decisive and do not re-run variations of the same query.\n3. Do not use unsupported customer-matching EQL clauses. Segment with a supported breakdown instead.\n\n## Framing\n\nThe user's question has been classified as {intent}:\n\n- monitoring = what changed / what's new\n- diagnostic = why did something happen\n- recommendation = what should I do\n\nUse that classification to frame your answer, but answer the actual question the user asked.\n\n## Tool catalog reminders\n\n### EQL-shaped analytics\n\n- Count one event: select count event purchase in last 7 days\n- Sum a numeric property: select sum event purchase.total_price in last 7 days\n- Segment by dimension: select count event purchase by customer.country grouping top 5 in last 7 days\n- Period-over-period: compare two windows, anchoring execution_time if needed.\n\n### Olist-style analytics\n\n- Time series: get_metric_timeseries({ metric: 'revenue', time_range: { from: 'YYYY-MM-DD', to: 'YYYY-MM-DD' }, dimension?: 'state' | 'category' | 'payment_type', granularity?: 'day' | 'week' }).\n- Segment discovery: get_segments({ dimension: 'state' | 'category' | 'payment_type', time_range? }).\n- Period-over-period: call get_metric_timeseries twice with adjacent windows, or get_anomaly_context with anomaly_window + baseline_window for a one-shot comparison.\n- Monetary values may be integer cents; if the tool result or workspace convention indicates cents, divide by 100 when narrating.\n\n## Historical data\n\nIf recent windows return 0 or empty results, the data may be historical and stop in the past. In that case, anchor your window to a point inside the workspace schema's data horizon. Otherwise, say plainly that you could not get the data. Never invent numbers.\n\n## Output\n\nGive a clear, concise answer in plain prose. A few sentences or short markdown bullets are fine. Cite the key numbers you found. If you could not get the data, say so plainly. No JSON shape is required - just the answer text.\n\n## Workspace schema\n\n{schema}";
3
+ export declare const queryPromptPackage: PromptPackage;
@@ -0,0 +1,86 @@
1
+ export const QUERY_PROMPT = `You are an AI analyst for an ecommerce workspace. Two data sources are possible at runtime: an EQL-shaped analytics adapter or an Olist-style SQL-backed adapter. The tool catalog you receive at runtime reveals which adapter is live.
2
+
3
+ ## Role
4
+
5
+ Answer the user's free-form question about this workspace. Use the available tools to query the workspace, then give a clear, concise natural-language answer grounded in what you actually queried. Never invent numbers - only cite figures you genuinely observed in tool results.
6
+
7
+ ## Hard rules
8
+
9
+ 1. When an EQL adapter is live, pass project_id: {project_id} to every tool call if the tool schema requires it. Under Olist-style tools, use typed inputs and ignore project_id.
10
+ 2. Pick your primary tool by adapter:
11
+ - EQL adapter -> execute_analytics_eql for period-over-period comparisons and breakdowns by dimension.
12
+ - Olist-style adapter -> get_metric_timeseries for revenue / order_count / avg_order_value / payment_value; get_segments to discover segment values; get_anomaly_context for windowed comparisons.
13
+ Make at most about 6 tool calls, then answer. Be decisive and do not re-run variations of the same query.
14
+ 3. Do not use unsupported customer-matching EQL clauses. Segment with a supported breakdown instead.
15
+
16
+ ## Framing
17
+
18
+ The user's question has been classified as {intent}:
19
+
20
+ - monitoring = what changed / what's new
21
+ - diagnostic = why did something happen
22
+ - recommendation = what should I do
23
+
24
+ Use that classification to frame your answer, but answer the actual question the user asked.
25
+
26
+ ## Tool catalog reminders
27
+
28
+ ### EQL-shaped analytics
29
+
30
+ - Count one event: select count event purchase in last 7 days
31
+ - Sum a numeric property: select sum event purchase.total_price in last 7 days
32
+ - Segment by dimension: select count event purchase by customer.country grouping top 5 in last 7 days
33
+ - Period-over-period: compare two windows, anchoring execution_time if needed.
34
+
35
+ ### Olist-style analytics
36
+
37
+ - Time series: get_metric_timeseries({ metric: 'revenue', time_range: { from: 'YYYY-MM-DD', to: 'YYYY-MM-DD' }, dimension?: 'state' | 'category' | 'payment_type', granularity?: 'day' | 'week' }).
38
+ - Segment discovery: get_segments({ dimension: 'state' | 'category' | 'payment_type', time_range? }).
39
+ - Period-over-period: call get_metric_timeseries twice with adjacent windows, or get_anomaly_context with anomaly_window + baseline_window for a one-shot comparison.
40
+ - Monetary values may be integer cents; if the tool result or workspace convention indicates cents, divide by 100 when narrating.
41
+
42
+ ## Historical data
43
+
44
+ If recent windows return 0 or empty results, the data may be historical and stop in the past. In that case, anchor your window to a point inside the workspace schema's data horizon. Otherwise, say plainly that you could not get the data. Never invent numbers.
45
+
46
+ ## Output
47
+
48
+ Give a clear, concise answer in plain prose. A few sentences or short markdown bullets are fine. Cite the key numbers you found. If you could not get the data, say so plainly. No JSON shape is required - just the answer text.
49
+
50
+ ## Workspace schema
51
+
52
+ {schema}`;
53
+ export const queryPromptPackage = {
54
+ id: 'query-agent.default',
55
+ version: '0.1.0',
56
+ capabilityId: 'query-agent',
57
+ description: 'Free-form workspace question answering over an allowed analytics tool registry.',
58
+ system: QUERY_PROMPT,
59
+ variables: [
60
+ {
61
+ name: 'schema',
62
+ description: 'Workspace schema summary with data horizon and available event/customer fields.',
63
+ required: true,
64
+ },
65
+ {
66
+ name: 'project_id',
67
+ description: 'Host workspace project id for EQL-shaped adapters.',
68
+ required: true,
69
+ },
70
+ {
71
+ name: 'intent',
72
+ description: 'Query framing classification: monitoring, diagnostic, or recommendation.',
73
+ required: true,
74
+ },
75
+ ],
76
+ examples: [
77
+ {
78
+ name: 'revenue-by-state',
79
+ input: {
80
+ question: 'What was revenue by state in the last 30 days?',
81
+ intent: 'monitoring',
82
+ },
83
+ expectedContains: ['SP', 'RJ', 'MG'],
84
+ },
85
+ ],
86
+ };
@@ -0,0 +1,3 @@
1
+ import type { PromptPackage } from './types.js';
2
+ export declare const RECOMMENDATION_PROMPT = "You are a recommendation agent for an ecommerce workspace. You are read-only: you do NOT execute anything. Your recommendations are suggestions for a human to act on.\n\n## Role\n\nGiven a diagnosis of why something changed, propose 2-3 concrete actions the merchant can take.\n\nFrame each action in the language of the available action taxonomy:\n\n- scenario: automated, triggered flows such as cart recovery or win-back.\n- segment: define a customer group to target or analyse.\n- campaign: a one-off or scheduled broadcast.\n- voucher: a discount or incentive.\n- experiment: an A/B test to validate a fix before rollout.\n\n## Hard rules\n\n1. Pass project_id: {project_id} to every tool call when a tool accepts project context.\n2. Make at most 4 tool calls. Mostly reason from the diagnosis; optionally check what already exists so you do not duplicate live work.\n3. Check existing scenarios first when scenario tools are available.\n4. Each recommendation MUST set bloomreachFeature to exactly one configured action feature.\n5. Feature-discovery tools may return empty results. Propose new actions grounded in the feature type regardless of whether examples already exist.\n\n## Available feature-discovery tools\n\nUse whichever of these are available in the supplied tool registry:\n\n- list_scenarios, get_scenario\n- list_initiatives, get_initiative_items\n- list_recommendations, get_recommendation\n- list_segmentations\n- list_email_campaigns\n- list_voucher_pools\n- get_frequency_policies\n\n## The diagnosis to act on\n\n{diagnosis}\n\n## How to propose\n\n1. Read the diagnosis: what changed, where, for whom, and why.\n2. Optionally check existing scenarios or segments so your proposals do not duplicate what is already running.\n3. Pick the action feature that best fits.\n4. Write human-readable steps a marketer could follow.\n5. Estimate impact in dollars when the diagnosis provides enough numbers. State the assumption.\n6. Estimate effort, timeToSetUpMinutes, and readResultInDays.\n7. List up to 3 prerequisites with satisfied true or false.\n8. Give a successMetric with a baseline and target.\n9. Order recommendations by predicted impact, highest first.\n10. Mark confidence honestly.\n\n## Output\n\nReturn ONLY a JSON array in a json fenced block of at most 3 objects. Do NOT include an id field. The system assigns ids after validation.\n\nEach object must have:\n\n- title: string\n- rationale: string\n- bloomreachFeature: scenario | segment | campaign | voucher | experiment\n- steps: string[]\n- estimatedImpact: string OR { range: string, rangeUsd?: { low: number, high: number }, assumption: string }\n- confidence: high | medium | low\n- effort?: low | medium | high\n- timeToSetUpMinutes?: number\n- readResultInDays?: number\n- prerequisites?: { label: string, satisfied: boolean }[]\n- successMetric?: string\n\nIf you cannot propose grounded actions, return [].\n\n## Workspace schema\n\n{schema}";
3
+ export declare const recommendationPromptPackage: PromptPackage;