@harness-engineering/intelligence 0.1.1 → 0.1.3

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/dist/index.js CHANGED
@@ -197,7 +197,22 @@ function convertNullable(def) {
197
197
  }
198
198
  var ZOD_CONVERTERS = {
199
199
  ZodString: () => ({ type: "string" }),
200
- ZodNumber: () => ({ type: "number" }),
200
+ ZodNumber: (def) => {
201
+ const result = { type: "number" };
202
+ const checks = def["checks"];
203
+ if (checks) {
204
+ for (const check of checks) {
205
+ if (check.kind === "min") {
206
+ result[check.inclusive === false ? "exclusiveMinimum" : "minimum"] = check.value;
207
+ }
208
+ if (check.kind === "max") {
209
+ result[check.inclusive === false ? "exclusiveMaximum" : "maximum"] = check.value;
210
+ }
211
+ if (check.kind === "int") result["type"] = "integer";
212
+ }
213
+ }
214
+ return result;
215
+ },
201
216
  ZodBoolean: () => ({ type: "boolean" }),
202
217
  ZodLiteral: (def) => ({ type: typeof def["value"], const: def["value"] }),
203
218
  ZodEnum: (def) => ({ type: "string", enum: def["values"] }),
@@ -1374,16 +1389,19 @@ function computeVolumeBonus(sampleSize) {
1374
1389
  function bucketKey(persona, systemNodeId, taskType) {
1375
1390
  return `${persona}|${systemNodeId}|${taskType}`;
1376
1391
  }
1377
- function computeSpecialization(store, opts) {
1378
- const records = gatherOutcomesWithTaskType(store);
1379
- if (records.length === 0) return [];
1380
- const temporal = opts?.temporal ?? { halfLifeDays: DEFAULT_HALF_LIFE };
1381
- const minSamples = opts?.minSamples ?? DEFAULT_MIN_SAMPLES;
1392
+ function matchesFilter(record, opts) {
1393
+ if (!opts) return true;
1394
+ const filters = [
1395
+ [opts.persona, record.persona],
1396
+ [opts.systemNodeId, record.systemNodeId],
1397
+ [opts.taskType, record.taskType]
1398
+ ];
1399
+ return filters.every(([filter, value]) => !filter || filter === value);
1400
+ }
1401
+ function groupIntoBuckets(records, opts) {
1382
1402
  const buckets = /* @__PURE__ */ new Map();
1383
1403
  for (const record of records) {
1384
- if (opts?.persona && record.persona !== opts.persona) continue;
1385
- if (opts?.systemNodeId && record.systemNodeId !== opts.systemNodeId) continue;
1386
- if (opts?.taskType && record.taskType !== opts.taskType) continue;
1404
+ if (!matchesFilter(record, opts)) continue;
1387
1405
  const key = bucketKey(record.persona, record.systemNodeId, record.taskType);
1388
1406
  let arr = buckets.get(key);
1389
1407
  if (!arr) {
@@ -1392,35 +1410,46 @@ function computeSpecialization(store, opts) {
1392
1410
  }
1393
1411
  arr.push(record);
1394
1412
  }
1413
+ return buckets;
1414
+ }
1415
+ function computeEntryFromBucket(records, temporal) {
1416
+ const first = records[0];
1417
+ const { persona, systemNodeId, taskType } = first;
1418
+ const sorted = [...records].sort((a, b) => Date.parse(a.timestamp) - Date.parse(b.timestamp));
1419
+ const tsr = temporalSuccessRate(
1420
+ sorted.map((r) => ({ result: r.result, timestamp: r.timestamp })),
1421
+ temporal
1422
+ );
1423
+ const consistency = computeConsistency(sorted.map((r) => r.result));
1424
+ const volume = computeVolumeBonus(sorted.length);
1425
+ const composite = W_TEMPORAL * tsr + W_CONSISTENCY * consistency + W_VOLUME * volume;
1426
+ const lastOutcome = sorted[sorted.length - 1].timestamp;
1427
+ const rawSuccessRate = sorted.filter((r) => r.result === "success").length / sorted.length;
1428
+ return {
1429
+ persona,
1430
+ systemNodeId,
1431
+ taskType,
1432
+ score: {
1433
+ temporalSuccessRate: tsr,
1434
+ consistencyScore: consistency,
1435
+ volumeBonus: volume,
1436
+ composite
1437
+ },
1438
+ expertiseLevel: computeExpertiseLevel(sorted.length, rawSuccessRate),
1439
+ sampleSize: sorted.length,
1440
+ lastOutcome
1441
+ };
1442
+ }
1443
+ function computeSpecialization(store, opts) {
1444
+ const records = gatherOutcomesWithTaskType(store);
1445
+ if (records.length === 0) return [];
1446
+ const temporal = opts?.temporal ?? { halfLifeDays: DEFAULT_HALF_LIFE };
1447
+ const minSamples = opts?.minSamples ?? DEFAULT_MIN_SAMPLES;
1448
+ const buckets = groupIntoBuckets(records, opts);
1395
1449
  const entries = [];
1396
1450
  for (const [, records2] of buckets) {
1397
1451
  if (records2.length < minSamples) continue;
1398
- const first = records2[0];
1399
- const { persona, systemNodeId, taskType } = first;
1400
- const sorted = [...records2].sort((a, b) => Date.parse(a.timestamp) - Date.parse(b.timestamp));
1401
- const tsr = temporalSuccessRate(
1402
- sorted.map((r) => ({ result: r.result, timestamp: r.timestamp })),
1403
- temporal
1404
- );
1405
- const consistency = computeConsistency(sorted.map((r) => r.result));
1406
- const volume = computeVolumeBonus(sorted.length);
1407
- const composite = W_TEMPORAL * tsr + W_CONSISTENCY * consistency + W_VOLUME * volume;
1408
- const lastOutcome = sorted[sorted.length - 1].timestamp;
1409
- const rawSuccessRate = sorted.filter((r) => r.result === "success").length / sorted.length;
1410
- entries.push({
1411
- persona,
1412
- systemNodeId,
1413
- taskType,
1414
- score: {
1415
- temporalSuccessRate: tsr,
1416
- consistencyScore: consistency,
1417
- volumeBonus: volume,
1418
- composite
1419
- },
1420
- expertiseLevel: computeExpertiseLevel(sorted.length, rawSuccessRate),
1421
- sampleSize: sorted.length,
1422
- lastOutcome
1423
- });
1452
+ entries.push(computeEntryFromBucket(records2, temporal));
1424
1453
  }
1425
1454
  entries.sort((a, b) => b.score.composite - a.score.composite);
1426
1455
  return entries;
package/dist/index.mjs CHANGED
@@ -130,7 +130,22 @@ function convertNullable(def) {
130
130
  }
131
131
  var ZOD_CONVERTERS = {
132
132
  ZodString: () => ({ type: "string" }),
133
- ZodNumber: () => ({ type: "number" }),
133
+ ZodNumber: (def) => {
134
+ const result = { type: "number" };
135
+ const checks = def["checks"];
136
+ if (checks) {
137
+ for (const check of checks) {
138
+ if (check.kind === "min") {
139
+ result[check.inclusive === false ? "exclusiveMinimum" : "minimum"] = check.value;
140
+ }
141
+ if (check.kind === "max") {
142
+ result[check.inclusive === false ? "exclusiveMaximum" : "maximum"] = check.value;
143
+ }
144
+ if (check.kind === "int") result["type"] = "integer";
145
+ }
146
+ }
147
+ return result;
148
+ },
134
149
  ZodBoolean: () => ({ type: "boolean" }),
135
150
  ZodLiteral: (def) => ({ type: typeof def["value"], const: def["value"] }),
136
151
  ZodEnum: (def) => ({ type: "string", enum: def["values"] }),
@@ -1307,16 +1322,19 @@ function computeVolumeBonus(sampleSize) {
1307
1322
  function bucketKey(persona, systemNodeId, taskType) {
1308
1323
  return `${persona}|${systemNodeId}|${taskType}`;
1309
1324
  }
1310
- function computeSpecialization(store, opts) {
1311
- const records = gatherOutcomesWithTaskType(store);
1312
- if (records.length === 0) return [];
1313
- const temporal = opts?.temporal ?? { halfLifeDays: DEFAULT_HALF_LIFE };
1314
- const minSamples = opts?.minSamples ?? DEFAULT_MIN_SAMPLES;
1325
+ function matchesFilter(record, opts) {
1326
+ if (!opts) return true;
1327
+ const filters = [
1328
+ [opts.persona, record.persona],
1329
+ [opts.systemNodeId, record.systemNodeId],
1330
+ [opts.taskType, record.taskType]
1331
+ ];
1332
+ return filters.every(([filter, value]) => !filter || filter === value);
1333
+ }
1334
+ function groupIntoBuckets(records, opts) {
1315
1335
  const buckets = /* @__PURE__ */ new Map();
1316
1336
  for (const record of records) {
1317
- if (opts?.persona && record.persona !== opts.persona) continue;
1318
- if (opts?.systemNodeId && record.systemNodeId !== opts.systemNodeId) continue;
1319
- if (opts?.taskType && record.taskType !== opts.taskType) continue;
1337
+ if (!matchesFilter(record, opts)) continue;
1320
1338
  const key = bucketKey(record.persona, record.systemNodeId, record.taskType);
1321
1339
  let arr = buckets.get(key);
1322
1340
  if (!arr) {
@@ -1325,35 +1343,46 @@ function computeSpecialization(store, opts) {
1325
1343
  }
1326
1344
  arr.push(record);
1327
1345
  }
1346
+ return buckets;
1347
+ }
1348
+ function computeEntryFromBucket(records, temporal) {
1349
+ const first = records[0];
1350
+ const { persona, systemNodeId, taskType } = first;
1351
+ const sorted = [...records].sort((a, b) => Date.parse(a.timestamp) - Date.parse(b.timestamp));
1352
+ const tsr = temporalSuccessRate(
1353
+ sorted.map((r) => ({ result: r.result, timestamp: r.timestamp })),
1354
+ temporal
1355
+ );
1356
+ const consistency = computeConsistency(sorted.map((r) => r.result));
1357
+ const volume = computeVolumeBonus(sorted.length);
1358
+ const composite = W_TEMPORAL * tsr + W_CONSISTENCY * consistency + W_VOLUME * volume;
1359
+ const lastOutcome = sorted[sorted.length - 1].timestamp;
1360
+ const rawSuccessRate = sorted.filter((r) => r.result === "success").length / sorted.length;
1361
+ return {
1362
+ persona,
1363
+ systemNodeId,
1364
+ taskType,
1365
+ score: {
1366
+ temporalSuccessRate: tsr,
1367
+ consistencyScore: consistency,
1368
+ volumeBonus: volume,
1369
+ composite
1370
+ },
1371
+ expertiseLevel: computeExpertiseLevel(sorted.length, rawSuccessRate),
1372
+ sampleSize: sorted.length,
1373
+ lastOutcome
1374
+ };
1375
+ }
1376
+ function computeSpecialization(store, opts) {
1377
+ const records = gatherOutcomesWithTaskType(store);
1378
+ if (records.length === 0) return [];
1379
+ const temporal = opts?.temporal ?? { halfLifeDays: DEFAULT_HALF_LIFE };
1380
+ const minSamples = opts?.minSamples ?? DEFAULT_MIN_SAMPLES;
1381
+ const buckets = groupIntoBuckets(records, opts);
1328
1382
  const entries = [];
1329
1383
  for (const [, records2] of buckets) {
1330
1384
  if (records2.length < minSamples) continue;
1331
- const first = records2[0];
1332
- const { persona, systemNodeId, taskType } = first;
1333
- const sorted = [...records2].sort((a, b) => Date.parse(a.timestamp) - Date.parse(b.timestamp));
1334
- const tsr = temporalSuccessRate(
1335
- sorted.map((r) => ({ result: r.result, timestamp: r.timestamp })),
1336
- temporal
1337
- );
1338
- const consistency = computeConsistency(sorted.map((r) => r.result));
1339
- const volume = computeVolumeBonus(sorted.length);
1340
- const composite = W_TEMPORAL * tsr + W_CONSISTENCY * consistency + W_VOLUME * volume;
1341
- const lastOutcome = sorted[sorted.length - 1].timestamp;
1342
- const rawSuccessRate = sorted.filter((r) => r.result === "success").length / sorted.length;
1343
- entries.push({
1344
- persona,
1345
- systemNodeId,
1346
- taskType,
1347
- score: {
1348
- temporalSuccessRate: tsr,
1349
- consistencyScore: consistency,
1350
- volumeBonus: volume,
1351
- composite
1352
- },
1353
- expertiseLevel: computeExpertiseLevel(sorted.length, rawSuccessRate),
1354
- sampleSize: sorted.length,
1355
- lastOutcome
1356
- });
1385
+ entries.push(computeEntryFromBucket(records2, temporal));
1357
1386
  }
1358
1387
  entries.sort((a, b) => b.score.composite - a.score.composite);
1359
1388
  return entries;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@harness-engineering/intelligence",
3
- "version": "0.1.1",
3
+ "version": "0.1.3",
4
4
  "description": "Intelligence pipeline for spec enrichment, complexity modeling, and pre-execution simulation",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.mjs",
@@ -37,17 +37,17 @@
37
37
  },
38
38
  "homepage": "https://github.com/Intense-Visions/harness-engineering/tree/main/packages/intelligence#readme",
39
39
  "dependencies": {
40
- "@anthropic-ai/sdk": "^0.39.0",
41
- "openai": "^4.0.0",
40
+ "@anthropic-ai/sdk": "^0.91.0",
41
+ "openai": "^6.0.0",
42
42
  "zod": "^3.25.76",
43
- "@harness-engineering/types": "0.10.0",
44
- "@harness-engineering/graph": "0.4.3"
43
+ "@harness-engineering/graph": "0.6.0",
44
+ "@harness-engineering/types": "0.10.1"
45
45
  },
46
46
  "devDependencies": {
47
47
  "@types/node": "^22.19.15",
48
- "@vitest/coverage-v8": "^4.1.2",
48
+ "@vitest/coverage-v8": "^4.1.5",
49
49
  "tsup": "^8.5.1",
50
- "vitest": "^4.1.2"
50
+ "vitest": "^4.1.5"
51
51
  },
52
52
  "scripts": {
53
53
  "build": "tsup src/index.ts --format cjs,esm --dts --tsconfig tsconfig.build.json",