@jamesaphoenix/tx-core 0.4.1
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/db.d.ts +42 -0
- package/dist/db.d.ts.map +1 -0
- package/dist/db.js +46 -0
- package/dist/db.js.map +1 -0
- package/dist/errors.d.ts +231 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +139 -0
- package/dist/errors.js.map +1 -0
- package/dist/id.d.ts +6 -0
- package/dist/id.d.ts.map +1 -0
- package/dist/id.js +21 -0
- package/dist/id.js.map +1 -0
- package/dist/index.d.ts +25 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +56 -0
- package/dist/index.js.map +1 -0
- package/dist/layer.d.ts +50 -0
- package/dist/layer.d.ts.map +1 -0
- package/dist/layer.js +155 -0
- package/dist/layer.js.map +1 -0
- package/dist/mappers/anchor.d.ts +14 -0
- package/dist/mappers/anchor.d.ts.map +1 -0
- package/dist/mappers/anchor.js +38 -0
- package/dist/mappers/anchor.js.map +1 -0
- package/dist/mappers/attempt.d.ts +15 -0
- package/dist/mappers/attempt.d.ts.map +1 -0
- package/dist/mappers/attempt.js +23 -0
- package/dist/mappers/attempt.js.map +1 -0
- package/dist/mappers/candidate.d.ts +23 -0
- package/dist/mappers/candidate.d.ts.map +1 -0
- package/dist/mappers/candidate.js +53 -0
- package/dist/mappers/candidate.js.map +1 -0
- package/dist/mappers/claim.d.ts +30 -0
- package/dist/mappers/claim.d.ts.map +1 -0
- package/dist/mappers/claim.js +32 -0
- package/dist/mappers/claim.js.map +1 -0
- package/dist/mappers/deduplication.d.ts +39 -0
- package/dist/mappers/deduplication.d.ts.map +1 -0
- package/dist/mappers/deduplication.js +53 -0
- package/dist/mappers/deduplication.js.map +1 -0
- package/dist/mappers/edge.d.ts +10 -0
- package/dist/mappers/edge.d.ts.map +1 -0
- package/dist/mappers/edge.js +19 -0
- package/dist/mappers/edge.js.map +1 -0
- package/dist/mappers/file-learning.d.ts +14 -0
- package/dist/mappers/file-learning.d.ts.map +1 -0
- package/dist/mappers/file-learning.js +75 -0
- package/dist/mappers/file-learning.js.map +1 -0
- package/dist/mappers/index.d.ts +17 -0
- package/dist/mappers/index.d.ts.map +1 -0
- package/dist/mappers/index.js +30 -0
- package/dist/mappers/index.js.map +1 -0
- package/dist/mappers/learning.d.ts +19 -0
- package/dist/mappers/learning.d.ts.map +1 -0
- package/dist/mappers/learning.js +41 -0
- package/dist/mappers/learning.js.map +1 -0
- package/dist/mappers/orchestrator-state.d.ts +33 -0
- package/dist/mappers/orchestrator-state.d.ts.map +1 -0
- package/dist/mappers/orchestrator-state.js +34 -0
- package/dist/mappers/orchestrator-state.js.map +1 -0
- package/dist/mappers/run.d.ts +32 -0
- package/dist/mappers/run.d.ts.map +1 -0
- package/dist/mappers/run.js +64 -0
- package/dist/mappers/run.js.map +1 -0
- package/dist/mappers/task.d.ts +23 -0
- package/dist/mappers/task.d.ts.map +1 -0
- package/dist/mappers/task.js +54 -0
- package/dist/mappers/task.js.map +1 -0
- package/dist/mappers/tracked-project.d.ts +15 -0
- package/dist/mappers/tracked-project.d.ts.map +1 -0
- package/dist/mappers/tracked-project.js +23 -0
- package/dist/mappers/tracked-project.js.map +1 -0
- package/dist/mappers/worker.d.ts +33 -0
- package/dist/mappers/worker.d.ts.map +1 -0
- package/dist/mappers/worker.js +35 -0
- package/dist/mappers/worker.js.map +1 -0
- package/dist/repo/anchor-repo.d.ts +52 -0
- package/dist/repo/anchor-repo.d.ts.map +1 -0
- package/dist/repo/anchor-repo.js +204 -0
- package/dist/repo/anchor-repo.js.map +1 -0
- package/dist/repo/attempt-repo.d.ts +25 -0
- package/dist/repo/attempt-repo.d.ts.map +1 -0
- package/dist/repo/attempt-repo.js +78 -0
- package/dist/repo/attempt-repo.js.map +1 -0
- package/dist/repo/candidate-repo.d.ts +16 -0
- package/dist/repo/candidate-repo.d.ts.map +1 -0
- package/dist/repo/candidate-repo.js +143 -0
- package/dist/repo/candidate-repo.js.map +1 -0
- package/dist/repo/claim-repo.d.ts +17 -0
- package/dist/repo/claim-repo.d.ts.map +1 -0
- package/dist/repo/claim-repo.js +62 -0
- package/dist/repo/claim-repo.js.map +1 -0
- package/dist/repo/deduplication-repo.d.ts +37 -0
- package/dist/repo/deduplication-repo.d.ts.map +1 -0
- package/dist/repo/deduplication-repo.js +133 -0
- package/dist/repo/deduplication-repo.js.map +1 -0
- package/dist/repo/dep-repo.d.ts +19 -0
- package/dist/repo/dep-repo.d.ts.map +1 -0
- package/dist/repo/dep-repo.js +104 -0
- package/dist/repo/dep-repo.js.map +1 -0
- package/dist/repo/edge-repo.d.ts +26 -0
- package/dist/repo/edge-repo.d.ts.map +1 -0
- package/dist/repo/edge-repo.js +227 -0
- package/dist/repo/edge-repo.js.map +1 -0
- package/dist/repo/file-learning-repo.d.ts +17 -0
- package/dist/repo/file-learning-repo.d.ts.map +1 -0
- package/dist/repo/file-learning-repo.js +60 -0
- package/dist/repo/file-learning-repo.js.map +1 -0
- package/dist/repo/index.d.ts +18 -0
- package/dist/repo/index.d.ts.map +1 -0
- package/dist/repo/index.js +18 -0
- package/dist/repo/index.js.map +1 -0
- package/dist/repo/learning-repo.d.ts +31 -0
- package/dist/repo/learning-repo.d.ts.map +1 -0
- package/dist/repo/learning-repo.js +165 -0
- package/dist/repo/learning-repo.js.map +1 -0
- package/dist/repo/orchestrator-state-repo.d.ts +27 -0
- package/dist/repo/orchestrator-state-repo.d.ts.map +1 -0
- package/dist/repo/orchestrator-state-repo.js +96 -0
- package/dist/repo/orchestrator-state-repo.js.map +1 -0
- package/dist/repo/run-repo.d.ts +31 -0
- package/dist/repo/run-repo.d.ts.map +1 -0
- package/dist/repo/run-repo.js +132 -0
- package/dist/repo/run-repo.js.map +1 -0
- package/dist/repo/task-repo.d.ts +21 -0
- package/dist/repo/task-repo.d.ts.map +1 -0
- package/dist/repo/task-repo.js +169 -0
- package/dist/repo/task-repo.js.map +1 -0
- package/dist/repo/tracked-project-repo.d.ts +16 -0
- package/dist/repo/tracked-project-repo.d.ts.map +1 -0
- package/dist/repo/tracked-project-repo.js +54 -0
- package/dist/repo/tracked-project-repo.js.map +1 -0
- package/dist/repo/worker-repo.d.ts +19 -0
- package/dist/repo/worker-repo.d.ts.map +1 -0
- package/dist/repo/worker-repo.js +72 -0
- package/dist/repo/worker-repo.js.map +1 -0
- package/dist/schemas/index.d.ts +8 -0
- package/dist/schemas/index.d.ts.map +1 -0
- package/dist/schemas/index.js +7 -0
- package/dist/schemas/index.js.map +1 -0
- package/dist/schemas/sync.d.ts +296 -0
- package/dist/schemas/sync.d.ts.map +1 -0
- package/dist/schemas/sync.js +146 -0
- package/dist/schemas/sync.js.map +1 -0
- package/dist/schemas/worker.d.ts +77 -0
- package/dist/schemas/worker.d.ts.map +1 -0
- package/dist/schemas/worker.js +80 -0
- package/dist/schemas/worker.js.map +1 -0
- package/dist/services/anchor-service.d.ts +147 -0
- package/dist/services/anchor-service.d.ts.map +1 -0
- package/dist/services/anchor-service.js +540 -0
- package/dist/services/anchor-service.js.map +1 -0
- package/dist/services/anchor-verification.d.ts +94 -0
- package/dist/services/anchor-verification.d.ts.map +1 -0
- package/dist/services/anchor-verification.js +617 -0
- package/dist/services/anchor-verification.js.map +1 -0
- package/dist/services/ast-grep-service.d.ts +58 -0
- package/dist/services/ast-grep-service.d.ts.map +1 -0
- package/dist/services/ast-grep-service.js +356 -0
- package/dist/services/ast-grep-service.js.map +1 -0
- package/dist/services/attempt-service.d.ts +24 -0
- package/dist/services/attempt-service.d.ts.map +1 -0
- package/dist/services/attempt-service.js +55 -0
- package/dist/services/attempt-service.js.map +1 -0
- package/dist/services/auto-sync-service.d.ts +56 -0
- package/dist/services/auto-sync-service.d.ts.map +1 -0
- package/dist/services/auto-sync-service.js +66 -0
- package/dist/services/auto-sync-service.js.map +1 -0
- package/dist/services/candidate-extractor-service.d.ts +56 -0
- package/dist/services/candidate-extractor-service.d.ts.map +1 -0
- package/dist/services/candidate-extractor-service.js +365 -0
- package/dist/services/candidate-extractor-service.js.map +1 -0
- package/dist/services/claim-service.d.ts +52 -0
- package/dist/services/claim-service.d.ts.map +1 -0
- package/dist/services/claim-service.js +134 -0
- package/dist/services/claim-service.js.map +1 -0
- package/dist/services/daemon-service.d.ts +214 -0
- package/dist/services/daemon-service.d.ts.map +1 -0
- package/dist/services/daemon-service.js +522 -0
- package/dist/services/daemon-service.js.map +1 -0
- package/dist/services/deduplication-service.d.ts +67 -0
- package/dist/services/deduplication-service.d.ts.map +1 -0
- package/dist/services/deduplication-service.js +145 -0
- package/dist/services/deduplication-service.js.map +1 -0
- package/dist/services/dep-service.d.ts +14 -0
- package/dist/services/dep-service.d.ts.map +1 -0
- package/dist/services/dep-service.js +34 -0
- package/dist/services/dep-service.js.map +1 -0
- package/dist/services/diversifier-service.d.ts +46 -0
- package/dist/services/diversifier-service.d.ts.map +1 -0
- package/dist/services/diversifier-service.js +197 -0
- package/dist/services/diversifier-service.js.map +1 -0
- package/dist/services/edge-service.d.ts +78 -0
- package/dist/services/edge-service.d.ts.map +1 -0
- package/dist/services/edge-service.js +158 -0
- package/dist/services/edge-service.js.map +1 -0
- package/dist/services/embedding-service.d.ts +138 -0
- package/dist/services/embedding-service.d.ts.map +1 -0
- package/dist/services/embedding-service.js +318 -0
- package/dist/services/embedding-service.js.map +1 -0
- package/dist/services/feedback-tracker.d.ts +64 -0
- package/dist/services/feedback-tracker.d.ts.map +1 -0
- package/dist/services/feedback-tracker.js +110 -0
- package/dist/services/feedback-tracker.js.map +1 -0
- package/dist/services/file-learning-service.d.ts +17 -0
- package/dist/services/file-learning-service.d.ts.map +1 -0
- package/dist/services/file-learning-service.js +41 -0
- package/dist/services/file-learning-service.js.map +1 -0
- package/dist/services/file-watcher-service.d.ts +141 -0
- package/dist/services/file-watcher-service.d.ts.map +1 -0
- package/dist/services/file-watcher-service.js +278 -0
- package/dist/services/file-watcher-service.js.map +1 -0
- package/dist/services/graph-expansion.d.ts +155 -0
- package/dist/services/graph-expansion.d.ts.map +1 -0
- package/dist/services/graph-expansion.js +466 -0
- package/dist/services/graph-expansion.js.map +1 -0
- package/dist/services/hierarchy-service.d.ts +16 -0
- package/dist/services/hierarchy-service.d.ts.map +1 -0
- package/dist/services/hierarchy-service.js +66 -0
- package/dist/services/hierarchy-service.js.map +1 -0
- package/dist/services/index.d.ts +36 -0
- package/dist/services/index.d.ts.map +1 -0
- package/dist/services/index.js +36 -0
- package/dist/services/index.js.map +1 -0
- package/dist/services/learning-service.d.ts +39 -0
- package/dist/services/learning-service.d.ts.map +1 -0
- package/dist/services/learning-service.js +151 -0
- package/dist/services/learning-service.js.map +1 -0
- package/dist/services/migration-service.d.ts +67 -0
- package/dist/services/migration-service.d.ts.map +1 -0
- package/dist/services/migration-service.js +144 -0
- package/dist/services/migration-service.js.map +1 -0
- package/dist/services/orchestrator-service.d.ts +52 -0
- package/dist/services/orchestrator-service.d.ts.map +1 -0
- package/dist/services/orchestrator-service.js +203 -0
- package/dist/services/orchestrator-service.js.map +1 -0
- package/dist/services/promotion-service.d.ts +67 -0
- package/dist/services/promotion-service.d.ts.map +1 -0
- package/dist/services/promotion-service.js +151 -0
- package/dist/services/promotion-service.js.map +1 -0
- package/dist/services/query-expansion-service.d.ts +55 -0
- package/dist/services/query-expansion-service.d.ts.map +1 -0
- package/dist/services/query-expansion-service.js +174 -0
- package/dist/services/query-expansion-service.js.map +1 -0
- package/dist/services/ready-service.d.ts +16 -0
- package/dist/services/ready-service.d.ts.map +1 -0
- package/dist/services/ready-service.js +70 -0
- package/dist/services/ready-service.js.map +1 -0
- package/dist/services/reranker-service.d.ts +51 -0
- package/dist/services/reranker-service.d.ts.map +1 -0
- package/dist/services/reranker-service.js +128 -0
- package/dist/services/reranker-service.js.map +1 -0
- package/dist/services/retriever-service.d.ts +49 -0
- package/dist/services/retriever-service.d.ts.map +1 -0
- package/dist/services/retriever-service.js +419 -0
- package/dist/services/retriever-service.js.map +1 -0
- package/dist/services/score-service.d.ts +43 -0
- package/dist/services/score-service.d.ts.map +1 -0
- package/dist/services/score-service.js +82 -0
- package/dist/services/score-service.js.map +1 -0
- package/dist/services/swarm-verification.d.ts +104 -0
- package/dist/services/swarm-verification.d.ts.map +1 -0
- package/dist/services/swarm-verification.js +400 -0
- package/dist/services/swarm-verification.js.map +1 -0
- package/dist/services/sync-service.d.ts +115 -0
- package/dist/services/sync-service.d.ts.map +1 -0
- package/dist/services/sync-service.js +350 -0
- package/dist/services/sync-service.js.map +1 -0
- package/dist/services/task-service.d.ts +22 -0
- package/dist/services/task-service.d.ts.map +1 -0
- package/dist/services/task-service.js +221 -0
- package/dist/services/task-service.js.map +1 -0
- package/dist/services/worker-process.d.ts +41 -0
- package/dist/services/worker-process.d.ts.map +1 -0
- package/dist/services/worker-process.js +280 -0
- package/dist/services/worker-process.js.map +1 -0
- package/dist/services/worker-service.d.ts +74 -0
- package/dist/services/worker-service.d.ts.map +1 -0
- package/dist/services/worker-service.js +148 -0
- package/dist/services/worker-service.js.map +1 -0
- package/dist/utils/glob.d.ts +15 -0
- package/dist/utils/glob.d.ts.map +1 -0
- package/dist/utils/glob.js +27 -0
- package/dist/utils/glob.js.map +1 -0
- package/dist/utils/math.d.ts +6 -0
- package/dist/utils/math.d.ts.map +1 -0
- package/dist/utils/math.js +21 -0
- package/dist/utils/math.js.map +1 -0
- package/package.json +72 -0
|
@@ -0,0 +1,419 @@
|
|
|
1
|
+
import { Context, Effect, Layer, Option } from "effect";
|
|
2
|
+
import { LearningRepository } from "../repo/learning-repo.js";
|
|
3
|
+
import { EmbeddingService } from "./embedding-service.js";
|
|
4
|
+
import { QueryExpansionService } from "./query-expansion-service.js";
|
|
5
|
+
import { RerankerService } from "./reranker-service.js";
|
|
6
|
+
import { GraphExpansionService } from "./graph-expansion.js";
|
|
7
|
+
import { FeedbackTrackerService } from "./feedback-tracker.js";
|
|
8
|
+
import { cosineSimilarity } from "../utils/math.js";
|
|
9
|
+
/** RRF constant - standard value from the original paper */
|
|
10
|
+
const RRF_K = 60;
|
|
11
|
+
/** Default weights for recency (used as boost on top of RRF) */
|
|
12
|
+
const DEFAULT_RECENCY_WEIGHT = 0.1;
|
|
13
|
+
const MAX_AGE_DAYS = 30;
|
|
14
|
+
/** Boost weights for outcome and frequency */
|
|
15
|
+
const OUTCOME_BOOST = 0.05;
|
|
16
|
+
const FREQUENCY_BOOST = 0.02;
|
|
17
|
+
/** Position-aware bonuses for items ranking highly in any retrieval system */
|
|
18
|
+
const TOP_1_BONUS = 0.05; // Bonus for #1 rank in any system
|
|
19
|
+
const TOP_3_BONUS = 0.02; // Bonus for top 3 in any system
|
|
20
|
+
/** Feedback boost weight - scales the 0-1 feedback score */
|
|
21
|
+
const FEEDBACK_BOOST = 0.05;
|
|
22
|
+
/**
|
|
23
|
+
* RetrieverService provides pluggable retrieval for learnings.
|
|
24
|
+
*
|
|
25
|
+
* Design: PRD-015 specifies retrieval should be pluggable with good defaults.
|
|
26
|
+
* Users can swap out the default BM25+vector+RRF pipeline for their own
|
|
27
|
+
* implementation (Pinecone, Weaviate, Chroma, etc.).
|
|
28
|
+
*/
|
|
29
|
+
export class RetrieverService extends Context.Tag("RetrieverService")() {
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Calculate recency score (0-1) based on age in days.
|
|
33
|
+
* Newer learnings get higher scores.
|
|
34
|
+
*/
|
|
35
|
+
const calculateRecencyScore = (createdAt) => {
|
|
36
|
+
const ageMs = Date.now() - createdAt.getTime();
|
|
37
|
+
const ageDays = ageMs / (1000 * 60 * 60 * 24);
|
|
38
|
+
return Math.max(0, 1 - ageDays / MAX_AGE_DAYS);
|
|
39
|
+
};
|
|
40
|
+
/**
|
|
41
|
+
* Compute vector similarity scores and return ranked results.
|
|
42
|
+
* Rank is 1-indexed (1 = best match).
|
|
43
|
+
*/
|
|
44
|
+
const computeVectorRanking = (learnings, queryEmbedding) => {
|
|
45
|
+
if (!queryEmbedding) {
|
|
46
|
+
return [];
|
|
47
|
+
}
|
|
48
|
+
const withScores = learnings
|
|
49
|
+
.filter(l => l.embedding !== null)
|
|
50
|
+
.map(learning => {
|
|
51
|
+
const similarity = cosineSimilarity(queryEmbedding, learning.embedding);
|
|
52
|
+
// Normalize cosine similarity from [-1, 1] to [0, 1]
|
|
53
|
+
const score = (similarity + 1) / 2;
|
|
54
|
+
return { learning, score };
|
|
55
|
+
})
|
|
56
|
+
.sort((a, b) => b.score - a.score);
|
|
57
|
+
// Add 1-indexed ranks
|
|
58
|
+
return withScores.map((item, idx) => ({
|
|
59
|
+
...item,
|
|
60
|
+
rank: idx + 1
|
|
61
|
+
}));
|
|
62
|
+
};
|
|
63
|
+
/**
|
|
64
|
+
* Reciprocal Rank Fusion (RRF) score calculation.
|
|
65
|
+
* Formula: RRF(d) = Σ 1/(k + rank_i(d))
|
|
66
|
+
*
|
|
67
|
+
* k is a constant (typically 60) that determines how much to weight
|
|
68
|
+
* items that appear in multiple lists vs items that rank highly in one list.
|
|
69
|
+
*
|
|
70
|
+
* @param k - RRF constant (default 60)
|
|
71
|
+
* @param ranks - Array of ranks (1-indexed, 0 means not present in that list)
|
|
72
|
+
*/
|
|
73
|
+
const rrfScore = (k, ...ranks) => {
|
|
74
|
+
return ranks.reduce((sum, rank) => {
|
|
75
|
+
if (rank === 0)
|
|
76
|
+
return sum; // Not present in this list
|
|
77
|
+
return sum + 1 / (k + rank);
|
|
78
|
+
}, 0);
|
|
79
|
+
};
|
|
80
|
+
/**
|
|
81
|
+
* Combine BM25 and vector search results using Reciprocal Rank Fusion (RRF).
|
|
82
|
+
*
|
|
83
|
+
* RRF is a robust method for combining ranked lists that:
|
|
84
|
+
* 1. Does not require score normalization
|
|
85
|
+
* 2. Works well when combining different retrieval systems
|
|
86
|
+
* 3. Is robust to outliers and different score distributions
|
|
87
|
+
*
|
|
88
|
+
* The final relevance score combines:
|
|
89
|
+
* - RRF score from BM25 and vector rankings
|
|
90
|
+
* - Recency boost for newer learnings
|
|
91
|
+
* - Outcome boost for learnings marked as helpful
|
|
92
|
+
* - Frequency boost for frequently retrieved learnings
|
|
93
|
+
*/
|
|
94
|
+
const computeRRFScoring = (bm25Results, vectorRanking) => {
|
|
95
|
+
// Build lookup maps for quick access
|
|
96
|
+
const bm25Map = new Map();
|
|
97
|
+
bm25Results.forEach((result, idx) => {
|
|
98
|
+
bm25Map.set(result.learning.id, { score: result.score, rank: idx + 1 });
|
|
99
|
+
});
|
|
100
|
+
const vectorMap = new Map();
|
|
101
|
+
vectorRanking.forEach(item => {
|
|
102
|
+
vectorMap.set(item.learning.id, { score: item.score, rank: item.rank });
|
|
103
|
+
});
|
|
104
|
+
// Collect all unique learnings from both sources
|
|
105
|
+
const allLearnings = new Map();
|
|
106
|
+
for (const result of bm25Results) {
|
|
107
|
+
allLearnings.set(result.learning.id, result.learning);
|
|
108
|
+
}
|
|
109
|
+
for (const item of vectorRanking) {
|
|
110
|
+
allLearnings.set(item.learning.id, item.learning);
|
|
111
|
+
}
|
|
112
|
+
// Compute RRF scores for all candidates
|
|
113
|
+
const candidates = [];
|
|
114
|
+
for (const [id, learning] of allLearnings) {
|
|
115
|
+
const bm25Info = bm25Map.get(id);
|
|
116
|
+
const vectorInfo = vectorMap.get(id);
|
|
117
|
+
const bm25Rank = bm25Info?.rank ?? 0;
|
|
118
|
+
const vectorRank = vectorInfo?.rank ?? 0;
|
|
119
|
+
const bm25Score = bm25Info?.score ?? 0;
|
|
120
|
+
const vectorScore = vectorInfo?.score ?? 0;
|
|
121
|
+
const recencyScore = calculateRecencyScore(learning.createdAt);
|
|
122
|
+
const rrf = rrfScore(RRF_K, bm25Rank, vectorRank);
|
|
123
|
+
candidates.push({
|
|
124
|
+
learning,
|
|
125
|
+
bm25Score,
|
|
126
|
+
bm25Rank,
|
|
127
|
+
vectorScore,
|
|
128
|
+
vectorRank,
|
|
129
|
+
rrfScore: rrf,
|
|
130
|
+
recencyScore
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
// Sort by RRF score (descending)
|
|
134
|
+
return candidates.sort((a, b) => b.rrfScore - a.rrfScore);
|
|
135
|
+
};
|
|
136
|
+
/**
|
|
137
|
+
* Calculate position-aware bonus based on best rank across retrieval systems.
|
|
138
|
+
* Items ranking #1 in any system get a larger bonus; top 3 get a smaller one.
|
|
139
|
+
*
|
|
140
|
+
* @param ranks - Array of ranks (1-indexed, 0 means not present in that system)
|
|
141
|
+
* @returns Position bonus to add to the score
|
|
142
|
+
*/
|
|
143
|
+
const calculatePositionBonus = (...ranks) => {
|
|
144
|
+
// Filter out zeros (not present in that ranking)
|
|
145
|
+
const validRanks = ranks.filter(r => r > 0);
|
|
146
|
+
if (validRanks.length === 0)
|
|
147
|
+
return 0;
|
|
148
|
+
const bestRank = Math.min(...validRanks);
|
|
149
|
+
if (bestRank === 1)
|
|
150
|
+
return TOP_1_BONUS; // #1 in any system
|
|
151
|
+
if (bestRank <= 3)
|
|
152
|
+
return TOP_3_BONUS; // Top 3 in any system
|
|
153
|
+
return 0;
|
|
154
|
+
};
|
|
155
|
+
/**
|
|
156
|
+
* Convert RRF candidates to final LearningWithScore results.
|
|
157
|
+
* Applies additional boosts for recency, outcome, frequency, position, and feedback.
|
|
158
|
+
*
|
|
159
|
+
* @param candidates - RRF-scored candidates
|
|
160
|
+
* @param recencyWeight - Weight for recency boost
|
|
161
|
+
* @param feedbackScores - Optional map of learning ID to feedback score (0-1)
|
|
162
|
+
*/
|
|
163
|
+
const applyFinalScoring = (candidates, recencyWeight, feedbackScores) => {
|
|
164
|
+
return candidates.map(candidate => {
|
|
165
|
+
const { learning, bm25Score, bm25Rank, vectorScore, vectorRank, rrfScore: rrf, recencyScore } = candidate;
|
|
166
|
+
// Outcome boost: if learning has been marked helpful, boost it
|
|
167
|
+
const outcomeBoost = learning.outcomeScore !== null
|
|
168
|
+
? OUTCOME_BOOST * learning.outcomeScore
|
|
169
|
+
: 0;
|
|
170
|
+
// Frequency boost: learnings that have been retrieved more get a small boost
|
|
171
|
+
const frequencyBoost = FREQUENCY_BOOST * Math.log(1 + learning.usageCount);
|
|
172
|
+
// Position-aware bonus: reward items that rank highly in any retrieval system
|
|
173
|
+
const positionBonus = calculatePositionBonus(bm25Rank, vectorRank);
|
|
174
|
+
// Feedback boost: learnings that were helpful in past runs get boosted
|
|
175
|
+
// feedbackScore is 0-1 with 0.5 being neutral (no feedback)
|
|
176
|
+
const feedbackScore = feedbackScores?.get(learning.id) ?? 0.5;
|
|
177
|
+
const feedbackBoost = FEEDBACK_BOOST * feedbackScore;
|
|
178
|
+
// Final relevance score: RRF as base + boosts
|
|
179
|
+
// RRF score range is [0, 2/k] for two lists, normalize to [0, 1] range
|
|
180
|
+
// Max possible RRF = 2 * 1/(k+1) ≈ 0.0328 for k=60
|
|
181
|
+
// Normalize: multiply by (k+1)/2 to get ~[0, 1]
|
|
182
|
+
const normalizedRRF = rrf * (RRF_K + 1) / 2;
|
|
183
|
+
const relevanceScore = normalizedRRF +
|
|
184
|
+
recencyWeight * recencyScore +
|
|
185
|
+
outcomeBoost +
|
|
186
|
+
frequencyBoost +
|
|
187
|
+
positionBonus +
|
|
188
|
+
feedbackBoost;
|
|
189
|
+
return {
|
|
190
|
+
...learning,
|
|
191
|
+
relevanceScore,
|
|
192
|
+
bm25Score,
|
|
193
|
+
vectorScore,
|
|
194
|
+
recencyScore,
|
|
195
|
+
rrfScore: rrf,
|
|
196
|
+
bm25Rank,
|
|
197
|
+
vectorRank,
|
|
198
|
+
feedbackScore
|
|
199
|
+
};
|
|
200
|
+
}).sort((a, b) => b.relevanceScore - a.relevanceScore);
|
|
201
|
+
};
|
|
202
|
+
/**
|
|
203
|
+
* Noop fallback - returns empty results.
|
|
204
|
+
* Used when retrieval is disabled or for testing without full pipeline.
|
|
205
|
+
*/
|
|
206
|
+
export const RetrieverServiceNoop = Layer.succeed(RetrieverService, {
|
|
207
|
+
search: (_query, _options) => Effect.succeed([]),
|
|
208
|
+
isAvailable: () => Effect.succeed(false)
|
|
209
|
+
});
|
|
210
|
+
/**
|
|
211
|
+
* Live implementation with BM25 + vector + RRF pipeline.
|
|
212
|
+
* Uses the default hybrid search with:
|
|
213
|
+
* - Query expansion via LLM
|
|
214
|
+
* - BM25 full-text search
|
|
215
|
+
* - Vector similarity (when embeddings available)
|
|
216
|
+
* - RRF fusion
|
|
217
|
+
* - Optional LLM re-ranking
|
|
218
|
+
* - Recency/outcome/frequency boosts
|
|
219
|
+
*/
|
|
220
|
+
export const RetrieverServiceLive = Layer.effect(RetrieverService, Effect.gen(function* () {
|
|
221
|
+
const learningRepo = yield* LearningRepository;
|
|
222
|
+
const embeddingService = yield* EmbeddingService;
|
|
223
|
+
const queryExpansionService = yield* QueryExpansionService;
|
|
224
|
+
const rerankerService = yield* RerankerService;
|
|
225
|
+
// GraphExpansionService is optional - graceful degradation when not available
|
|
226
|
+
const graphExpansionServiceOption = yield* Effect.serviceOption(GraphExpansionService);
|
|
227
|
+
const graphExpansionService = Option.getOrNull(graphExpansionServiceOption);
|
|
228
|
+
// FeedbackTrackerService is optional - graceful degradation when not available
|
|
229
|
+
const feedbackTrackerServiceOption = yield* Effect.serviceOption(FeedbackTrackerService);
|
|
230
|
+
const feedbackTrackerService = Option.getOrNull(feedbackTrackerServiceOption);
|
|
231
|
+
// Load recency weight from config
|
|
232
|
+
const recencyWeightStr = yield* learningRepo.getConfig("recency_weight");
|
|
233
|
+
const recencyWeight = recencyWeightStr ? parseFloat(recencyWeightStr) : DEFAULT_RECENCY_WEIGHT;
|
|
234
|
+
/**
|
|
235
|
+
* Apply LLM re-ranking to scored learnings with position-aware blending.
|
|
236
|
+
* Re-ranking uses a specialized model to improve precision.
|
|
237
|
+
* Position-aware blending gives bonuses to items that rank highly
|
|
238
|
+
* across multiple retrieval systems (BM25, vector, AND reranker).
|
|
239
|
+
* Gracefully degrades if reranker is unavailable.
|
|
240
|
+
*/
|
|
241
|
+
const applyReranking = (query, learnings, rerankerWeight = 0.3) => Effect.gen(function* () {
|
|
242
|
+
// Check if reranker is available
|
|
243
|
+
const isAvailable = yield* rerankerService.isAvailable();
|
|
244
|
+
if (!isAvailable || learnings.length === 0) {
|
|
245
|
+
return learnings;
|
|
246
|
+
}
|
|
247
|
+
// Extract document contents for reranking
|
|
248
|
+
const documents = learnings.map(l => l.content);
|
|
249
|
+
// Get reranker scores (graceful degradation on error)
|
|
250
|
+
const reranked = yield* Effect.catchAll(rerankerService.rerank(query, documents), () => Effect.succeed(null));
|
|
251
|
+
if (!reranked) {
|
|
252
|
+
return learnings;
|
|
253
|
+
}
|
|
254
|
+
// Create maps of content to reranker score and rank
|
|
255
|
+
const rerankerScores = new Map();
|
|
256
|
+
const rerankerRanks = new Map();
|
|
257
|
+
reranked.forEach((result, idx) => {
|
|
258
|
+
rerankerScores.set(result.document, result.score);
|
|
259
|
+
rerankerRanks.set(result.document, idx + 1); // 1-indexed rank
|
|
260
|
+
});
|
|
261
|
+
// Blend reranker scores with existing relevance scores using position-aware bonuses
|
|
262
|
+
// Formula: final = (1 - weight) * existing + weight * reranker + positionBonus
|
|
263
|
+
return learnings.map(learning => {
|
|
264
|
+
const rerankerScore = rerankerScores.get(learning.content) ?? 0;
|
|
265
|
+
const rerankerRank = rerankerRanks.get(learning.content) ?? 0;
|
|
266
|
+
// Calculate position bonus across all three systems (BM25, vector, reranker)
|
|
267
|
+
const positionBonus = calculatePositionBonus(learning.bm25Rank, learning.vectorRank, rerankerRank);
|
|
268
|
+
// Weighted blend plus position-aware bonus
|
|
269
|
+
const blendedScore = (1 - rerankerWeight) * learning.relevanceScore +
|
|
270
|
+
rerankerWeight * rerankerScore +
|
|
271
|
+
positionBonus;
|
|
272
|
+
return {
|
|
273
|
+
...learning,
|
|
274
|
+
relevanceScore: blendedScore,
|
|
275
|
+
rerankerScore // Add reranker score to output
|
|
276
|
+
};
|
|
277
|
+
}).sort((a, b) => b.relevanceScore - a.relevanceScore);
|
|
278
|
+
});
|
|
279
|
+
/**
|
|
280
|
+
* Perform BM25 search across multiple queries and merge results.
|
|
281
|
+
* Uses RRF to combine rankings from each query.
|
|
282
|
+
*/
|
|
283
|
+
const multiQueryBM25Search = (queries, limit) => Effect.gen(function* () {
|
|
284
|
+
// Search for each query
|
|
285
|
+
const allResults = [];
|
|
286
|
+
for (const query of queries) {
|
|
287
|
+
const results = yield* learningRepo.bm25Search(query, limit);
|
|
288
|
+
allResults.push([...results]);
|
|
289
|
+
}
|
|
290
|
+
// Merge results using best rank across all queries
|
|
291
|
+
const learningRanks = new Map();
|
|
292
|
+
for (const results of allResults) {
|
|
293
|
+
results.forEach((result, idx) => {
|
|
294
|
+
const rank = idx + 1;
|
|
295
|
+
const existing = learningRanks.get(result.learning.id);
|
|
296
|
+
if (!existing || rank < existing.bestRank) {
|
|
297
|
+
learningRanks.set(result.learning.id, {
|
|
298
|
+
learning: result.learning,
|
|
299
|
+
bestRank: rank,
|
|
300
|
+
bestScore: result.score
|
|
301
|
+
});
|
|
302
|
+
}
|
|
303
|
+
});
|
|
304
|
+
}
|
|
305
|
+
// Convert to BM25Result format, sorted by best rank
|
|
306
|
+
const merged = [...learningRanks.values()]
|
|
307
|
+
.sort((a, b) => a.bestRank - b.bestRank)
|
|
308
|
+
.map(item => ({ learning: item.learning, score: item.bestScore }));
|
|
309
|
+
return merged;
|
|
310
|
+
});
|
|
311
|
+
/**
|
|
312
|
+
* Apply graph expansion to seed learnings and merge with existing results.
|
|
313
|
+
* Gracefully degrades if expansion fails or GraphExpansionService is unavailable.
|
|
314
|
+
*/
|
|
315
|
+
const applyGraphExpansion = (seeds, options) => Effect.gen(function* () {
|
|
316
|
+
const graphOpts = options.graphExpansion;
|
|
317
|
+
// Skip if not enabled, no seeds, or GraphExpansionService unavailable
|
|
318
|
+
if (!graphOpts?.enabled || seeds.length === 0 || !graphExpansionService) {
|
|
319
|
+
return seeds;
|
|
320
|
+
}
|
|
321
|
+
// Convert top-k seeds to SeedLearning format for expansion
|
|
322
|
+
const seedCount = Math.min(seeds.length, 10); // Default top-k seeds
|
|
323
|
+
const seedLearnings = seeds.slice(0, seedCount).map(s => ({
|
|
324
|
+
learning: s,
|
|
325
|
+
score: s.relevanceScore
|
|
326
|
+
}));
|
|
327
|
+
// Perform graph expansion (graceful degradation on error)
|
|
328
|
+
const expansionResult = yield* Effect.catchAll(graphExpansionService.expand(seedLearnings, {
|
|
329
|
+
depth: graphOpts.depth ?? 2,
|
|
330
|
+
decayFactor: graphOpts.decayFactor ?? 0.7,
|
|
331
|
+
maxNodes: graphOpts.maxNodes ?? 100,
|
|
332
|
+
edgeTypes: graphOpts.edgeTypes
|
|
333
|
+
}), () => Effect.succeed(null));
|
|
334
|
+
if (!expansionResult) {
|
|
335
|
+
// Graph expansion failed, return original seeds with hops=0
|
|
336
|
+
return seeds.map(s => ({
|
|
337
|
+
...s,
|
|
338
|
+
expansionHops: 0,
|
|
339
|
+
expansionPath: [s.id],
|
|
340
|
+
sourceEdge: null
|
|
341
|
+
}));
|
|
342
|
+
}
|
|
343
|
+
// Create a set of seed IDs to track which learnings are direct matches
|
|
344
|
+
const seedIds = new Set(seeds.map(s => s.id));
|
|
345
|
+
// Mark seed learnings with expansion metadata (hops=0)
|
|
346
|
+
const seedsWithMeta = seeds.map(s => ({
|
|
347
|
+
...s,
|
|
348
|
+
expansionHops: 0,
|
|
349
|
+
expansionPath: [s.id],
|
|
350
|
+
sourceEdge: null
|
|
351
|
+
}));
|
|
352
|
+
// Convert expanded learnings to LearningWithScore format
|
|
353
|
+
// Only include learnings that aren't already in the seed set (avoid duplicates)
|
|
354
|
+
const expandedWithScores = expansionResult.expanded
|
|
355
|
+
.filter(e => !seedIds.has(e.learning.id))
|
|
356
|
+
.map(e => ({
|
|
357
|
+
...e.learning,
|
|
358
|
+
relevanceScore: e.decayedScore,
|
|
359
|
+
bm25Score: 0,
|
|
360
|
+
vectorScore: 0,
|
|
361
|
+
recencyScore: calculateRecencyScore(e.learning.createdAt),
|
|
362
|
+
rrfScore: 0,
|
|
363
|
+
bm25Rank: 0,
|
|
364
|
+
vectorRank: 0,
|
|
365
|
+
expansionHops: e.hops,
|
|
366
|
+
expansionPath: e.path,
|
|
367
|
+
sourceEdge: e.sourceEdge
|
|
368
|
+
}));
|
|
369
|
+
// Merge seeds and expanded, sort by relevance score
|
|
370
|
+
const merged = [...seedsWithMeta, ...expandedWithScores]
|
|
371
|
+
.sort((a, b) => b.relevanceScore - a.relevanceScore);
|
|
372
|
+
return merged;
|
|
373
|
+
});
|
|
374
|
+
return {
|
|
375
|
+
search: (query, options) => Effect.gen(function* () {
|
|
376
|
+
const { limit = 10, minScore = 0.1 } = options ?? {};
|
|
377
|
+
// Expand query using LLM (graceful degradation - returns original if unavailable)
|
|
378
|
+
const expansionResult = yield* Effect.catchAll(queryExpansionService.expand(query), () => Effect.succeed({ original: query, expanded: [query], wasExpanded: false }));
|
|
379
|
+
// Get BM25 search results across all expanded queries (ranked list 1)
|
|
380
|
+
const bm25Results = yield* multiQueryBM25Search(expansionResult.expanded, limit * 3);
|
|
381
|
+
// Try to get query embedding for vector search (graceful degradation)
|
|
382
|
+
// Use original query for embedding since expanded queries may be noisier
|
|
383
|
+
const queryEmbedding = yield* Effect.option(embeddingService.embed(query));
|
|
384
|
+
const queryEmbeddingValue = Option.getOrNull(queryEmbedding);
|
|
385
|
+
// Get all learnings that have embeddings for vector ranking
|
|
386
|
+
const learningsWithEmbeddings = yield* learningRepo.findWithEmbeddings(limit * 3);
|
|
387
|
+
// Compute vector ranking (ranked list 2)
|
|
388
|
+
const vectorRanking = computeVectorRanking(learningsWithEmbeddings, queryEmbeddingValue);
|
|
389
|
+
// Combine using RRF
|
|
390
|
+
const candidates = computeRRFScoring(bm25Results, vectorRanking);
|
|
391
|
+
// Fetch feedback scores for all candidates in a single batch (graceful degradation)
|
|
392
|
+
let feedbackScores;
|
|
393
|
+
if (feedbackTrackerService && candidates.length > 0) {
|
|
394
|
+
const learningIds = candidates.map(c => c.learning.id);
|
|
395
|
+
feedbackScores = yield* Effect.catchAll(feedbackTrackerService.getFeedbackScores(learningIds), () => Effect.succeed(new Map(learningIds.map(id => [id, 0.5]))));
|
|
396
|
+
}
|
|
397
|
+
// Apply final scoring with boosts (including feedback)
|
|
398
|
+
const scored = applyFinalScoring(candidates, recencyWeight, feedbackScores);
|
|
399
|
+
// Apply graph expansion if enabled (after initial RRF scoring)
|
|
400
|
+
const withGraphExpansion = yield* applyGraphExpansion(scored, options ?? {});
|
|
401
|
+
// Apply LLM re-ranking to top candidates for improved precision
|
|
402
|
+
// Only re-rank a reasonable number of candidates to balance quality vs latency
|
|
403
|
+
const topCandidates = withGraphExpansion.slice(0, Math.min(limit * 2, 20));
|
|
404
|
+
const reranked = yield* applyReranking(query, topCandidates);
|
|
405
|
+
// Filter by minimum score and limit
|
|
406
|
+
return reranked
|
|
407
|
+
.filter(r => r.relevanceScore >= minScore)
|
|
408
|
+
.slice(0, limit);
|
|
409
|
+
}),
|
|
410
|
+
isAvailable: () => Effect.succeed(true)
|
|
411
|
+
};
|
|
412
|
+
}));
|
|
413
|
+
/**
|
|
414
|
+
* Auto-detecting layer that always uses Live since BM25 is always available.
|
|
415
|
+
* The Live implementation gracefully degrades vector search when embeddings
|
|
416
|
+
* are unavailable, so Auto just delegates to Live.
|
|
417
|
+
*/
|
|
418
|
+
export const RetrieverServiceAuto = RetrieverServiceLive;
|
|
419
|
+
//# sourceMappingURL=retriever-service.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"retriever-service.js","sourceRoot":"","sources":["../../src/services/retriever-service.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { Context, Effect, Layer } from "effect";
|
|
2
|
+
import { TaskRepository } from "../repo/task-repo.js";
|
|
3
|
+
import { DependencyRepository } from "../repo/dep-repo.js";
|
|
4
|
+
import { TaskNotFoundError, DatabaseError } from "../errors.js";
|
|
5
|
+
import { HierarchyService } from "./hierarchy-service.js";
|
|
6
|
+
import type { Task, TaskId } from "@jamesaphoenix/tx-types";
|
|
7
|
+
/**
|
|
8
|
+
* Score breakdown showing each adjustment factor (for CLI display)
|
|
9
|
+
*/
|
|
10
|
+
export interface ScoreBreakdown {
|
|
11
|
+
readonly baseScore: number;
|
|
12
|
+
readonly blockingBonus: number;
|
|
13
|
+
readonly blockingCount: number;
|
|
14
|
+
readonly ageBonus: number;
|
|
15
|
+
readonly ageHours: number;
|
|
16
|
+
readonly depthPenalty: number;
|
|
17
|
+
readonly depth: number;
|
|
18
|
+
readonly blockedPenalty: number;
|
|
19
|
+
readonly finalScore: number;
|
|
20
|
+
}
|
|
21
|
+
declare const ScoreService_base: Context.TagClass<ScoreService, "ScoreService", {
|
|
22
|
+
/**
|
|
23
|
+
* Calculate the final score with dynamic adjustments
|
|
24
|
+
*/
|
|
25
|
+
readonly calculate: (task: Task) => Effect.Effect<number, DatabaseError>;
|
|
26
|
+
/**
|
|
27
|
+
* Calculate score for a task by ID
|
|
28
|
+
*/
|
|
29
|
+
readonly calculateById: (id: TaskId) => Effect.Effect<number, TaskNotFoundError | DatabaseError>;
|
|
30
|
+
/**
|
|
31
|
+
* Get detailed score breakdown for display
|
|
32
|
+
*/
|
|
33
|
+
readonly getBreakdown: (task: Task) => Effect.Effect<ScoreBreakdown, DatabaseError>;
|
|
34
|
+
/**
|
|
35
|
+
* Get score breakdown by task ID
|
|
36
|
+
*/
|
|
37
|
+
readonly getBreakdownById: (id: TaskId) => Effect.Effect<ScoreBreakdown, TaskNotFoundError | DatabaseError>;
|
|
38
|
+
}>;
|
|
39
|
+
export declare class ScoreService extends ScoreService_base {
|
|
40
|
+
}
|
|
41
|
+
export declare const ScoreServiceLive: Layer.Layer<ScoreService, never, TaskRepository | DependencyRepository | HierarchyService>;
|
|
42
|
+
export {};
|
|
43
|
+
//# sourceMappingURL=score-service.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"score-service.d.ts","sourceRoot":"","sources":["../../src/services/score-service.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,QAAQ,CAAA;AAC/C,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAA;AACrD,OAAO,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAA;AAC1D,OAAO,EAAE,iBAAiB,EAAE,aAAa,EAAE,MAAM,cAAc,CAAA;AAC/D,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAA;AACzD,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,yBAAyB,CAAA;AAE3D;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAA;IAC1B,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAA;IAC9B,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAA;IAC9B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAA;IACzB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAA;IACzB,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAA;IAC7B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;IACtB,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAA;IAC/B,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAA;CAC5B;;IAKG;;OAEG;wBACiB,CAAC,IAAI,EAAE,IAAI,KAAK,MAAM,CAAC,MAAM,CAAC,MAAM,EAAE,aAAa,CAAC;IAExE;;OAEG;4BACqB,CAAC,EAAE,EAAE,MAAM,KAAK,MAAM,CAAC,MAAM,CAAC,MAAM,EAAE,iBAAiB,GAAG,aAAa,CAAC;IAEhG;;OAEG;2BACoB,CAAC,IAAI,EAAE,IAAI,KAAK,MAAM,CAAC,MAAM,CAAC,cAAc,EAAE,aAAa,CAAC;IAEnF;;OAEG;+BACwB,CAAC,EAAE,EAAE,MAAM,KAAK,MAAM,CAAC,MAAM,CAAC,cAAc,EAAE,iBAAiB,GAAG,aAAa,CAAC;;AArB/G,qBAAa,YAAa,SAAQ,iBAuB/B;CAAG;AAEN,eAAO,MAAM,gBAAgB,4FAoG5B,CAAA"}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import { Context, Effect, Layer } from "effect";
|
|
2
|
+
import { TaskRepository } from "../repo/task-repo.js";
|
|
3
|
+
import { DependencyRepository } from "../repo/dep-repo.js";
|
|
4
|
+
import { TaskNotFoundError } from "../errors.js";
|
|
5
|
+
import { HierarchyService } from "./hierarchy-service.js";
|
|
6
|
+
export class ScoreService extends Context.Tag("ScoreService")() {
|
|
7
|
+
}
|
|
8
|
+
export const ScoreServiceLive = Layer.effect(ScoreService, Effect.gen(function* () {
|
|
9
|
+
const taskRepo = yield* TaskRepository;
|
|
10
|
+
const depRepo = yield* DependencyRepository;
|
|
11
|
+
const hierarchySvc = yield* HierarchyService;
|
|
12
|
+
const computeBreakdown = (task, blockingCount, depth) => {
|
|
13
|
+
// Base score from DB
|
|
14
|
+
const baseScore = task.score;
|
|
15
|
+
// Blocking bonus: +25 per task this task blocks
|
|
16
|
+
const blockingBonus = blockingCount * 25;
|
|
17
|
+
// Age bonus: old tasks shouldn't rot
|
|
18
|
+
const ageMs = Date.now() - task.createdAt.getTime();
|
|
19
|
+
const ageHours = ageMs / (1000 * 60 * 60);
|
|
20
|
+
let ageBonus = 0;
|
|
21
|
+
if (ageHours > 48) {
|
|
22
|
+
ageBonus = 100;
|
|
23
|
+
}
|
|
24
|
+
else if (ageHours > 24) {
|
|
25
|
+
ageBonus = 50;
|
|
26
|
+
}
|
|
27
|
+
// Depth penalty: prefer root tasks over deep subtasks
|
|
28
|
+
const depthPenalty = depth * 10;
|
|
29
|
+
// Blocked status penalty: blocked tasks should not be prioritized
|
|
30
|
+
const blockedPenalty = task.status === "blocked" ? 1000 : 0;
|
|
31
|
+
// Final calculation
|
|
32
|
+
const finalScore = baseScore + blockingBonus + ageBonus - depthPenalty - blockedPenalty;
|
|
33
|
+
return {
|
|
34
|
+
baseScore,
|
|
35
|
+
blockingBonus,
|
|
36
|
+
blockingCount,
|
|
37
|
+
ageBonus,
|
|
38
|
+
ageHours: Math.floor(ageHours),
|
|
39
|
+
depthPenalty,
|
|
40
|
+
depth,
|
|
41
|
+
blockedPenalty,
|
|
42
|
+
finalScore
|
|
43
|
+
};
|
|
44
|
+
};
|
|
45
|
+
const getTaskContext = (task) => Effect.gen(function* () {
|
|
46
|
+
// Get how many tasks this task blocks
|
|
47
|
+
const blockingIds = yield* depRepo.getBlockingIds(task.id);
|
|
48
|
+
const blockingCount = blockingIds.length;
|
|
49
|
+
// Get depth in hierarchy
|
|
50
|
+
const depth = yield* hierarchySvc.getDepth(task.id).pipe(Effect.catchTag("TaskNotFoundError", () => Effect.succeed(0)));
|
|
51
|
+
return { blockingCount, depth };
|
|
52
|
+
});
|
|
53
|
+
return {
|
|
54
|
+
calculate: (task) => Effect.gen(function* () {
|
|
55
|
+
const ctx = yield* getTaskContext(task);
|
|
56
|
+
const breakdown = computeBreakdown(task, ctx.blockingCount, ctx.depth);
|
|
57
|
+
return breakdown.finalScore;
|
|
58
|
+
}),
|
|
59
|
+
calculateById: (id) => Effect.gen(function* () {
|
|
60
|
+
const task = yield* taskRepo.findById(id);
|
|
61
|
+
if (!task) {
|
|
62
|
+
return yield* Effect.fail(new TaskNotFoundError({ id }));
|
|
63
|
+
}
|
|
64
|
+
const ctx = yield* getTaskContext(task);
|
|
65
|
+
const breakdown = computeBreakdown(task, ctx.blockingCount, ctx.depth);
|
|
66
|
+
return breakdown.finalScore;
|
|
67
|
+
}),
|
|
68
|
+
getBreakdown: (task) => Effect.gen(function* () {
|
|
69
|
+
const ctx = yield* getTaskContext(task);
|
|
70
|
+
return computeBreakdown(task, ctx.blockingCount, ctx.depth);
|
|
71
|
+
}),
|
|
72
|
+
getBreakdownById: (id) => Effect.gen(function* () {
|
|
73
|
+
const task = yield* taskRepo.findById(id);
|
|
74
|
+
if (!task) {
|
|
75
|
+
return yield* Effect.fail(new TaskNotFoundError({ id }));
|
|
76
|
+
}
|
|
77
|
+
const ctx = yield* getTaskContext(task);
|
|
78
|
+
return computeBreakdown(task, ctx.blockingCount, ctx.depth);
|
|
79
|
+
})
|
|
80
|
+
};
|
|
81
|
+
}));
|
|
82
|
+
//# sourceMappingURL=score-service.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"score-service.js","sourceRoot":"","sources":["../../src/services/score-service.ts"],"names":[],"mappings":"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"}
|