@jamesaphoenix/tx-core 0.4.4 → 0.5.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.
- package/dist/db.d.ts +4 -9
- package/dist/db.d.ts.map +1 -1
- package/dist/db.js +6 -80
- package/dist/db.js.map +1 -1
- package/dist/errors.d.ts +67 -10
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js +44 -10
- package/dist/errors.js.map +1 -1
- package/dist/index.d.ts +12 -7
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +22 -28
- package/dist/index.js.map +1 -1
- package/dist/layer.d.ts +22 -10
- package/dist/layer.d.ts.map +1 -1
- package/dist/layer.js +97 -39
- package/dist/layer.js.map +1 -1
- package/dist/mappers/anchor.d.ts +28 -0
- package/dist/mappers/anchor.d.ts.map +1 -0
- package/dist/mappers/anchor.js +105 -0
- package/dist/mappers/anchor.js.map +1 -0
- package/dist/mappers/candidate.d.ts +25 -0
- package/dist/mappers/candidate.d.ts.map +1 -0
- package/dist/mappers/candidate.js +83 -0
- package/dist/mappers/candidate.js.map +1 -0
- package/dist/mappers/doc.d.ts +2 -4
- package/dist/mappers/doc.d.ts.map +1 -1
- package/dist/mappers/doc.js +7 -4
- package/dist/mappers/doc.js.map +1 -1
- package/dist/mappers/edge.d.ts +19 -0
- package/dist/mappers/edge.d.ts.map +1 -0
- package/dist/mappers/edge.js +81 -0
- package/dist/mappers/edge.js.map +1 -0
- package/dist/mappers/index.d.ts +7 -3
- package/dist/mappers/index.d.ts.map +1 -1
- package/dist/mappers/index.js +14 -6
- package/dist/mappers/index.js.map +1 -1
- package/dist/mappers/message.d.ts +15 -0
- package/dist/mappers/message.d.ts.map +1 -0
- package/dist/mappers/message.js +58 -0
- package/dist/mappers/message.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 +245 -0
- package/dist/repo/anchor-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 +164 -0
- package/dist/repo/candidate-repo.js.map +1 -0
- package/dist/repo/compaction-repo.d.ts +41 -0
- package/dist/repo/compaction-repo.d.ts.map +1 -0
- package/dist/repo/compaction-repo.js +84 -0
- package/dist/repo/compaction-repo.js.map +1 -0
- package/dist/repo/doc-repo.d.ts +68 -51
- package/dist/repo/doc-repo.d.ts.map +1 -1
- package/dist/repo/doc-repo.js +120 -54
- package/dist/repo/doc-repo.js.map +1 -1
- 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 +258 -0
- package/dist/repo/edge-repo.js.map +1 -0
- package/dist/repo/index.d.ts +8 -3
- package/dist/repo/index.d.ts.map +1 -1
- package/dist/repo/index.js +7 -2
- package/dist/repo/index.js.map +1 -1
- package/dist/repo/message-repo.d.ts +55 -0
- package/dist/repo/message-repo.d.ts.map +1 -0
- package/dist/repo/message-repo.js +132 -0
- package/dist/repo/message-repo.js.map +1 -0
- package/dist/services/agent-service.d.ts +18 -23
- package/dist/services/agent-service.d.ts.map +1 -1
- package/dist/services/agent-service.js +9 -0
- package/dist/services/agent-service.js.map +1 -1
- 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 +102 -0
- package/dist/services/anchor-verification.d.ts.map +1 -0
- package/dist/services/anchor-verification.js +817 -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 +427 -0
- package/dist/services/ast-grep-service.js.map +1 -0
- package/dist/services/attempt-service.d.ts.map +1 -1
- package/dist/services/attempt-service.js +4 -1
- package/dist/services/attempt-service.js.map +1 -1
- package/dist/services/auto-sync-service.d.ts.map +1 -1
- package/dist/services/auto-sync-service.js +7 -7
- package/dist/services/auto-sync-service.js.map +1 -1
- package/dist/services/candidate-extractor-service.d.ts +44 -0
- package/dist/services/candidate-extractor-service.d.ts.map +1 -0
- package/dist/services/candidate-extractor-service.js +175 -0
- package/dist/services/candidate-extractor-service.js.map +1 -0
- package/dist/services/claim-service.d.ts.map +1 -1
- package/dist/services/claim-service.js +0 -8
- package/dist/services/claim-service.js.map +1 -1
- package/dist/services/compaction-service.d.ts +105 -0
- package/dist/services/compaction-service.d.ts.map +1 -0
- package/dist/services/compaction-service.js +281 -0
- package/dist/services/compaction-service.js.map +1 -0
- package/dist/services/cycle-scan-service.d.ts +1 -5
- package/dist/services/cycle-scan-service.d.ts.map +1 -1
- package/dist/services/cycle-scan-service.js +49 -19
- package/dist/services/cycle-scan-service.js.map +1 -1
- package/dist/services/daemon-service.d.ts +2 -8
- package/dist/services/daemon-service.d.ts.map +1 -1
- package/dist/services/daemon-service.js +21 -35
- package/dist/services/daemon-service.js.map +1 -1
- package/dist/services/doc-service.d.ts +25 -32
- package/dist/services/doc-service.d.ts.map +1 -1
- package/dist/services/doc-service.js +206 -190
- package/dist/services/doc-service.js.map +1 -1
- 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 +2 -2
- package/dist/services/embedding-service.d.ts.map +1 -1
- package/dist/services/embedding-service.js +7 -13
- package/dist/services/embedding-service.js.map +1 -1
- 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-watcher-service.d.ts.map +1 -1
- package/dist/services/file-watcher-service.js +1 -3
- package/dist/services/file-watcher-service.js.map +1 -1
- package/dist/services/graph-expansion.d.ts +158 -0
- package/dist/services/graph-expansion.d.ts.map +1 -0
- package/dist/services/graph-expansion.js +487 -0
- package/dist/services/graph-expansion.js.map +1 -0
- package/dist/services/index.d.ts +19 -8
- package/dist/services/index.d.ts.map +1 -1
- package/dist/services/index.js +18 -7
- package/dist/services/index.js.map +1 -1
- package/dist/services/learning-service.d.ts.map +1 -1
- package/dist/services/learning-service.js +22 -14
- package/dist/services/learning-service.js.map +1 -1
- package/dist/services/llm-service.d.ts +61 -39
- package/dist/services/llm-service.d.ts.map +1 -1
- package/dist/services/llm-service.js +199 -113
- package/dist/services/llm-service.js.map +1 -1
- package/dist/services/message-service.d.ts +57 -0
- package/dist/services/message-service.d.ts.map +1 -0
- package/dist/services/message-service.js +78 -0
- package/dist/services/message-service.js.map +1 -0
- package/dist/services/orchestrator-service.d.ts.map +1 -1
- package/dist/services/orchestrator-service.js +19 -20
- package/dist/services/orchestrator-service.js.map +1 -1
- 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 +7 -22
- package/dist/services/query-expansion-service.d.ts.map +1 -1
- package/dist/services/query-expansion-service.js +41 -75
- package/dist/services/query-expansion-service.js.map +1 -1
- package/dist/services/retriever-service.d.ts +8 -5
- package/dist/services/retriever-service.d.ts.map +1 -1
- package/dist/services/retriever-service.js +150 -15
- package/dist/services/retriever-service.js.map +1 -1
- 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 +406 -0
- package/dist/services/swarm-verification.js.map +1 -0
- package/dist/services/sync-service.d.ts.map +1 -1
- package/dist/services/sync-service.js +8 -9
- package/dist/services/sync-service.js.map +1 -1
- package/dist/services/task-service.d.ts.map +1 -1
- package/dist/services/task-service.js +3 -8
- package/dist/services/task-service.js.map +1 -1
- package/dist/services/tracing-service.js +6 -6
- package/dist/services/tracing-service.js.map +1 -1
- package/dist/services/transcript-adapter.d.ts.map +1 -1
- package/dist/services/transcript-adapter.js +1 -1
- package/dist/services/transcript-adapter.js.map +1 -1
- package/dist/services/worker-process.d.ts.map +1 -1
- package/dist/services/worker-process.js +8 -30
- package/dist/services/worker-process.js.map +1 -1
- package/dist/utils/doc-hash.d.ts +0 -4
- package/dist/utils/doc-hash.d.ts.map +1 -1
- package/dist/utils/doc-hash.js.map +1 -1
- package/dist/utils/doc-renderer.d.ts +31 -26
- package/dist/utils/doc-renderer.d.ts.map +1 -1
- package/dist/utils/doc-renderer.js +0 -7
- package/dist/utils/doc-renderer.js.map +1 -1
- package/dist/utils/llm-json.d.ts +17 -0
- package/dist/utils/llm-json.d.ts.map +1 -0
- package/dist/utils/llm-json.js +51 -0
- package/dist/utils/llm-json.js.map +1 -0
- package/dist/utils/toml-config.d.ts +10 -16
- package/dist/utils/toml-config.d.ts.map +1 -1
- package/dist/utils/toml-config.js +3 -1
- package/dist/utils/toml-config.js.map +1 -1
- package/dist/worker/run-worker.d.ts.map +1 -1
- package/dist/worker/run-worker.js +2 -7
- package/dist/worker/run-worker.js.map +1 -1
- package/package.json +9 -8
|
@@ -49,15 +49,14 @@ export const OrchestratorServiceLive = Layer.effect(OrchestratorService, Effect.
|
|
|
49
49
|
// Use: Run the wrapped effect
|
|
50
50
|
() => effect,
|
|
51
51
|
// Release: Commit on success, rollback on failure
|
|
52
|
-
(_, exit) =>
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
}).pipe(Effect.catchAll((rollbackError) => Effect.log(`ROLLBACK failed: ${rollbackError.cause}`))));
|
|
52
|
+
(_, exit) => Effect.sync(() => {
|
|
53
|
+
if (Exit.isSuccess(exit)) {
|
|
54
|
+
db.exec("COMMIT");
|
|
55
|
+
}
|
|
56
|
+
else {
|
|
57
|
+
db.exec("ROLLBACK");
|
|
58
|
+
}
|
|
59
|
+
}));
|
|
61
60
|
return {
|
|
62
61
|
start: (config) => Effect.gen(function* () {
|
|
63
62
|
const currentState = yield* stateRepo.get();
|
|
@@ -146,23 +145,23 @@ export const OrchestratorServiceLive = Layer.effect(OrchestratorService, Effect.
|
|
|
146
145
|
let orphanedTasksRecovered = 0;
|
|
147
146
|
let orphanedClaimsReleased = 0;
|
|
148
147
|
let staleStatesFixed = 0;
|
|
149
|
-
// 1. Detect dead workers (missed
|
|
150
|
-
//
|
|
151
|
-
//
|
|
152
|
-
//
|
|
148
|
+
// 1. Detect dead workers (missed 1+ heartbeats)
|
|
149
|
+
// Changed from 2 to 1 to reduce worst-case detection time from ~90s to ~60s.
|
|
150
|
+
// With missedHeartbeats: 2, if worker dies at t=1 after heartbeat at t=0,
|
|
151
|
+
// detection doesn't occur until t=90+ (60s threshold + 30s reconcile delay).
|
|
153
152
|
const deadWorkers = yield* workerService.findDead({
|
|
154
|
-
missedHeartbeats:
|
|
153
|
+
missedHeartbeats: 1
|
|
155
154
|
});
|
|
156
155
|
for (const worker of deadWorkers) {
|
|
157
|
-
yield* workerService.markDead(worker.id).pipe(Effect.catchAll((
|
|
156
|
+
yield* workerService.markDead(worker.id).pipe(Effect.catchAll(() => Effect.void));
|
|
158
157
|
// Release any claims held by this dead worker
|
|
159
|
-
yield* claimService.releaseByWorker(worker.id).pipe(Effect.catchAll((
|
|
158
|
+
yield* claimService.releaseByWorker(worker.id).pipe(Effect.catchAll(() => Effect.succeed(0)));
|
|
160
159
|
deadWorkersFound++;
|
|
161
160
|
}
|
|
162
161
|
// 2. Expire stale claims (past lease expiration)
|
|
163
162
|
const expiredClaims = yield* claimService.getExpired();
|
|
164
163
|
for (const claim of expiredClaims) {
|
|
165
|
-
yield* claimService.expire(claim.id).pipe(Effect.catchAll((
|
|
164
|
+
yield* claimService.expire(claim.id).pipe(Effect.catchAll(() => Effect.void));
|
|
166
165
|
// Atomically recover task status based on blocker states.
|
|
167
166
|
// Single UPDATE with subquery eliminates TOCTOU race between
|
|
168
167
|
// reading blocker statuses and writing the new task status.
|
|
@@ -186,7 +185,7 @@ export const OrchestratorServiceLive = Layer.effect(OrchestratorService, Effect.
|
|
|
186
185
|
const busyWorkers = yield* workerService.list({ status: ["busy"] });
|
|
187
186
|
for (const worker of busyWorkers) {
|
|
188
187
|
if (worker.currentTaskId === null) {
|
|
189
|
-
yield* workerService.updateStatus(worker.id, "idle").pipe(Effect.catchAll((
|
|
188
|
+
yield* workerService.updateStatus(worker.id, "idle").pipe(Effect.catchAll(() => Effect.void));
|
|
190
189
|
staleStatesFixed++;
|
|
191
190
|
}
|
|
192
191
|
}
|
|
@@ -195,7 +194,7 @@ export const OrchestratorServiceLive = Layer.effect(OrchestratorService, Effect.
|
|
|
195
194
|
if (worker.currentTaskId) {
|
|
196
195
|
const task = yield* taskRepo.findById(worker.currentTaskId);
|
|
197
196
|
if (!task || task.status !== "active") {
|
|
198
|
-
yield* workerService.updateStatus(worker.id, "idle").pipe(Effect.catchAll((
|
|
197
|
+
yield* workerService.updateStatus(worker.id, "idle").pipe(Effect.catchAll(() => Effect.void));
|
|
199
198
|
staleStatesFixed++;
|
|
200
199
|
}
|
|
201
200
|
}
|
|
@@ -205,7 +204,7 @@ export const OrchestratorServiceLive = Layer.effect(OrchestratorService, Effect.
|
|
|
205
204
|
// (e.g., if claim release failed after tx done)
|
|
206
205
|
const orphanedClaims = yield* claimService.getOrphanedClaims();
|
|
207
206
|
for (const claim of orphanedClaims) {
|
|
208
|
-
yield* claimService.expire(claim.id).pipe(Effect.catchAll((
|
|
207
|
+
yield* claimService.expire(claim.id).pipe(Effect.catchAll(() => Effect.void));
|
|
209
208
|
orphanedClaimsReleased++;
|
|
210
209
|
}
|
|
211
210
|
const reconcileTime = Date.now() - startTime;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"orchestrator-service.js","sourceRoot":"","sources":["../../src/services/orchestrator-service.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,QAAQ,CAAA;AACrD,OAAO,EAAE,YAAY,EAAE,MAAM,UAAU,CAAA;AACvC,OAAO,EAAE,2BAA2B,EAAE,MAAM,oCAAoC,CAAA;AAChF,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAA;AACrD,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAA;AACvD,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAA;AACnD,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAA;AACjD,OAAO,EAAE,aAAa,EAAE,iBAAiB,EAAqB,MAAM,cAAc,CAAA;AAelF;;GAEG;AACH,MAAM,cAAc,GAAiC;IACnD,cAAc,EAAE,CAAC;IACjB,wBAAwB,EAAE,EAAE;IAC5B,oBAAoB,EAAE,EAAE;IACxB,wBAAwB,EAAE,EAAE;IAC5B,sBAAsB,EAAE,GAAG;IAC3B,gBAAgB,EAAE,EAAE;CACrB,CAAA;AAED,MAAM,OAAO,mBAAoB,SAAQ,OAAO,CAAC,GAAG,CAAC,qBAAqB,CAAC,EA+BxE;CAAG;AAEN,MAAM,CAAC,MAAM,uBAAuB,GAAG,KAAK,CAAC,MAAM,CACjD,mBAAmB,EACnB,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC;IAClB,MAAM,EAAE,GAAG,KAAK,CAAC,CAAC,YAAY,CAAA;IAC9B,MAAM,SAAS,GAAG,KAAK,CAAC,CAAC,2BAA2B,CAAA;IACpD,MAAM,aAAa,GAAG,KAAK,CAAC,CAAC,aAAa,CAAA;IAC1C,MAAM,YAAY,GAAG,KAAK,CAAC,CAAC,YAAY,CAAA;IACxC,MAAM,QAAQ,GAAG,KAAK,CAAC,CAAC,cAAc,CAAA;IACtC,MAAM,SAAS,GAAG,KAAK,CAAC,CAAC,eAAe,CAAA;IAExC;;;;OAIG;IACH,MAAM,eAAe,GAAG,CACtB,MAA2B,EACU,EAAE,CACvC,MAAM,CAAC,iBAAiB;IACtB,6BAA6B;IAC7B,MAAM,CAAC,GAAG,CAAC;QACT,GAAG,EAAE,GAAG,EAAE;YACR,EAAE,CAAC,IAAI,CAAC,iBAAiB,CAAC,CAAA;YAC1B,OAAO,SAAS,CAAA;QAClB,CAAC;QACD,KAAK,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,IAAI,aAAa,CAAC,EAAE,KAAK,EAAE,CAAC;KAC/C,CAAC;IACF,8BAA8B;IAC9B,GAAG,EAAE,CAAC,MAAM;IACZ,kDAAkD;IAClD,CAAC,CAAC,EAAE,IAAI,EAAE,EAAE,CACV,
|
|
1
|
+
{"version":3,"file":"orchestrator-service.js","sourceRoot":"","sources":["../../src/services/orchestrator-service.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { Context, Effect, Layer } from "effect";
|
|
2
|
+
import { CandidateNotFoundError, DatabaseError, ValidationError } from "../errors.js";
|
|
3
|
+
import { CandidateRepository } from "../repo/candidate-repo.js";
|
|
4
|
+
import { LearningService } from "./learning-service.js";
|
|
5
|
+
import { EdgeService } from "./edge-service.js";
|
|
6
|
+
import type { LearningCandidate, CandidateFilter, CandidateId, Learning } from "@jamesaphoenix/tx-types";
|
|
7
|
+
/**
|
|
8
|
+
* Result of promoting a candidate to the learnings table.
|
|
9
|
+
*/
|
|
10
|
+
export interface PromotionResult {
|
|
11
|
+
/** The updated candidate with promoted status */
|
|
12
|
+
readonly candidate: LearningCandidate;
|
|
13
|
+
/** The newly created learning */
|
|
14
|
+
readonly learning: Learning;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Result of auto-promotion batch operation.
|
|
18
|
+
*/
|
|
19
|
+
export interface AutoPromoteResult {
|
|
20
|
+
/** Number of candidates auto-promoted */
|
|
21
|
+
readonly promoted: number;
|
|
22
|
+
/** Number of candidates skipped (already processed or low confidence) */
|
|
23
|
+
readonly skipped: number;
|
|
24
|
+
/** Number of candidates that failed to promote */
|
|
25
|
+
readonly failed: number;
|
|
26
|
+
/** IDs of promoted learnings */
|
|
27
|
+
readonly learningIds: readonly number[];
|
|
28
|
+
}
|
|
29
|
+
declare const PromotionService_base: Context.TagClass<PromotionService, "PromotionService", {
|
|
30
|
+
/**
|
|
31
|
+
* List candidates matching the given filter.
|
|
32
|
+
* Supports filtering by status, confidence, category, and pagination.
|
|
33
|
+
*/
|
|
34
|
+
readonly list: (filter: CandidateFilter) => Effect.Effect<readonly LearningCandidate[], DatabaseError>;
|
|
35
|
+
/**
|
|
36
|
+
* Promote a candidate to the learnings table.
|
|
37
|
+
* Creates a new learning and updates the candidate status to 'promoted'.
|
|
38
|
+
*/
|
|
39
|
+
readonly promote: (id: CandidateId) => Effect.Effect<PromotionResult, CandidateNotFoundError | DatabaseError>;
|
|
40
|
+
/**
|
|
41
|
+
* Reject a candidate with a reason.
|
|
42
|
+
* Updates the candidate status to 'rejected' and stores the rejection reason.
|
|
43
|
+
*/
|
|
44
|
+
readonly reject: (id: CandidateId, reason: string) => Effect.Effect<LearningCandidate, CandidateNotFoundError | ValidationError | DatabaseError>;
|
|
45
|
+
/**
|
|
46
|
+
* Auto-promote high-confidence candidates.
|
|
47
|
+
* Promotes all pending candidates with 'high' confidence level.
|
|
48
|
+
* Uses 'auto' as the reviewer identifier.
|
|
49
|
+
*/
|
|
50
|
+
readonly autoPromote: () => Effect.Effect<AutoPromoteResult, DatabaseError>;
|
|
51
|
+
/**
|
|
52
|
+
* Get all pending candidates awaiting review.
|
|
53
|
+
* Convenience method equivalent to list({ status: 'pending' }).
|
|
54
|
+
*/
|
|
55
|
+
readonly getPending: () => Effect.Effect<readonly LearningCandidate[], DatabaseError>;
|
|
56
|
+
}>;
|
|
57
|
+
/**
|
|
58
|
+
* PromotionService manages the lifecycle of learning candidates,
|
|
59
|
+
* including listing, promoting to learnings, rejecting, and auto-promotion.
|
|
60
|
+
*
|
|
61
|
+
* @see PRD-015 for the knowledge promotion pipeline
|
|
62
|
+
*/
|
|
63
|
+
export declare class PromotionService extends PromotionService_base {
|
|
64
|
+
}
|
|
65
|
+
export declare const PromotionServiceLive: Layer.Layer<PromotionService, never, CandidateRepository | EdgeService | LearningService>;
|
|
66
|
+
export {};
|
|
67
|
+
//# sourceMappingURL=promotion-service.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"promotion-service.d.ts","sourceRoot":"","sources":["../../src/services/promotion-service.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,QAAQ,CAAA;AAC/C,OAAO,EAAE,sBAAsB,EAAE,aAAa,EAAE,eAAe,EAAE,MAAM,cAAc,CAAA;AACrF,OAAO,EAAE,mBAAmB,EAAE,MAAM,2BAA2B,CAAA;AAC/D,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAA;AACvD,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAA;AAC/C,OAAO,KAAK,EACV,iBAAiB,EACjB,eAAe,EACf,WAAW,EACX,QAAQ,EACT,MAAM,yBAAyB,CAAA;AAEhC;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,iDAAiD;IACjD,QAAQ,CAAC,SAAS,EAAE,iBAAiB,CAAA;IACrC,iCAAiC;IACjC,QAAQ,CAAC,QAAQ,EAAE,QAAQ,CAAA;CAC5B;AAED;;GAEG;AACH,MAAM,WAAW,iBAAiB;IAChC,yCAAyC;IACzC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAA;IACzB,yEAAyE;IACzE,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;IACxB,kDAAkD;IAClD,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;IACvB,gCAAgC;IAChC,QAAQ,CAAC,WAAW,EAAE,SAAS,MAAM,EAAE,CAAA;CACxC;;IAWG;;;OAGG;mBACY,CAAC,MAAM,EAAE,eAAe,KAAK,MAAM,CAAC,MAAM,CAAC,SAAS,iBAAiB,EAAE,EAAE,aAAa,CAAC;IAEtG;;;OAGG;sBACe,CAAC,EAAE,EAAE,WAAW,KAAK,MAAM,CAAC,MAAM,CAAC,eAAe,EAAE,sBAAsB,GAAG,aAAa,CAAC;IAE7G;;;OAGG;qBACc,CAAC,EAAE,EAAE,WAAW,EAAE,MAAM,EAAE,MAAM,KAAK,MAAM,CAAC,MAAM,CAAC,iBAAiB,EAAE,sBAAsB,GAAG,eAAe,GAAG,aAAa,CAAC;IAEhJ;;;;OAIG;0BACmB,MAAM,MAAM,CAAC,MAAM,CAAC,iBAAiB,EAAE,aAAa,CAAC;IAE3E;;;OAGG;yBACkB,MAAM,MAAM,CAAC,MAAM,CAAC,SAAS,iBAAiB,EAAE,EAAE,aAAa,CAAC;;AAtCzF;;;;;GAKG;AACH,qBAAa,gBAAiB,SAAQ,qBAkCnC;CAAG;AAKN,eAAO,MAAM,oBAAoB,2FAiLhC,CAAA"}
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
import { Context, Effect, Layer } from "effect";
|
|
2
|
+
import { CandidateNotFoundError, DatabaseError, ValidationError } from "../errors.js";
|
|
3
|
+
import { CandidateRepository } from "../repo/candidate-repo.js";
|
|
4
|
+
import { LearningService } from "./learning-service.js";
|
|
5
|
+
import { EdgeService } from "./edge-service.js";
|
|
6
|
+
/**
|
|
7
|
+
* PromotionService manages the lifecycle of learning candidates,
|
|
8
|
+
* including listing, promoting to learnings, rejecting, and auto-promotion.
|
|
9
|
+
*
|
|
10
|
+
* @see PRD-015 for the knowledge promotion pipeline
|
|
11
|
+
*/
|
|
12
|
+
export class PromotionService extends Context.Tag("PromotionService")() {
|
|
13
|
+
}
|
|
14
|
+
/** Duplicate detection threshold for auto-promotion (0.85 = high similarity) */
|
|
15
|
+
const DUPLICATE_MIN_SCORE = 0.85;
|
|
16
|
+
export const PromotionServiceLive = Layer.effect(PromotionService, Effect.gen(function* () {
|
|
17
|
+
const candidateRepo = yield* CandidateRepository;
|
|
18
|
+
const learningService = yield* LearningService;
|
|
19
|
+
const edgeService = yield* EdgeService;
|
|
20
|
+
/**
|
|
21
|
+
* Promote a single candidate with optional reviewer identifier.
|
|
22
|
+
* Internal helper shared by promote() and autoPromote().
|
|
23
|
+
*/
|
|
24
|
+
const promoteCandidate = (candidate, reviewedBy) => Effect.gen(function* () {
|
|
25
|
+
// Create learning from candidate content
|
|
26
|
+
// Map ValidationError to DatabaseError (validation should not fail for existing candidates)
|
|
27
|
+
const learning = yield* Effect.mapError(learningService.create({
|
|
28
|
+
content: candidate.content,
|
|
29
|
+
sourceType: "run",
|
|
30
|
+
sourceRef: candidate.sourceRunId ?? candidate.sourceFile,
|
|
31
|
+
category: candidate.category
|
|
32
|
+
}), (error) => error._tag === "ValidationError"
|
|
33
|
+
? new DatabaseError({ cause: error })
|
|
34
|
+
: error);
|
|
35
|
+
// Create DERIVED_FROM edge for provenance tracking
|
|
36
|
+
// Link the learning back to its source (run or task)
|
|
37
|
+
if (candidate.sourceRunId) {
|
|
38
|
+
yield* Effect.catchAll(edgeService.createEdge({
|
|
39
|
+
edgeType: "DERIVED_FROM",
|
|
40
|
+
sourceType: "learning",
|
|
41
|
+
sourceId: String(learning.id),
|
|
42
|
+
targetType: "run",
|
|
43
|
+
targetId: candidate.sourceRunId,
|
|
44
|
+
weight: 1.0
|
|
45
|
+
}), () => Effect.void // Ignore edge creation failures
|
|
46
|
+
);
|
|
47
|
+
}
|
|
48
|
+
else if (candidate.sourceTaskId) {
|
|
49
|
+
yield* Effect.catchAll(edgeService.createEdge({
|
|
50
|
+
edgeType: "DERIVED_FROM",
|
|
51
|
+
sourceType: "learning",
|
|
52
|
+
sourceId: String(learning.id),
|
|
53
|
+
targetType: "task",
|
|
54
|
+
targetId: candidate.sourceTaskId,
|
|
55
|
+
weight: 1.0
|
|
56
|
+
}), () => Effect.void // Ignore edge creation failures
|
|
57
|
+
);
|
|
58
|
+
}
|
|
59
|
+
// Update candidate status to promoted
|
|
60
|
+
const now = new Date();
|
|
61
|
+
const updatedCandidate = yield* candidateRepo.update(candidate.id, {
|
|
62
|
+
status: "promoted",
|
|
63
|
+
reviewedAt: now,
|
|
64
|
+
reviewedBy,
|
|
65
|
+
promotedLearningId: learning.id
|
|
66
|
+
});
|
|
67
|
+
if (!updatedCandidate) {
|
|
68
|
+
return yield* Effect.fail(new CandidateNotFoundError({ id: candidate.id }));
|
|
69
|
+
}
|
|
70
|
+
return { candidate: updatedCandidate, learning };
|
|
71
|
+
});
|
|
72
|
+
return {
|
|
73
|
+
list: (filter) => candidateRepo.findByFilter(filter),
|
|
74
|
+
promote: (id) => Effect.gen(function* () {
|
|
75
|
+
const candidate = yield* candidateRepo.findById(id);
|
|
76
|
+
if (!candidate) {
|
|
77
|
+
return yield* Effect.fail(new CandidateNotFoundError({ id }));
|
|
78
|
+
}
|
|
79
|
+
return yield* promoteCandidate(candidate, "manual");
|
|
80
|
+
}),
|
|
81
|
+
reject: (id, reason) => Effect.gen(function* () {
|
|
82
|
+
// Validate reason is provided
|
|
83
|
+
if (!reason || reason.trim().length === 0) {
|
|
84
|
+
return yield* Effect.fail(new ValidationError({ reason: "Rejection reason is required" }));
|
|
85
|
+
}
|
|
86
|
+
const candidate = yield* candidateRepo.findById(id);
|
|
87
|
+
if (!candidate) {
|
|
88
|
+
return yield* Effect.fail(new CandidateNotFoundError({ id }));
|
|
89
|
+
}
|
|
90
|
+
const now = new Date();
|
|
91
|
+
const updatedCandidate = yield* candidateRepo.update(id, {
|
|
92
|
+
status: "rejected",
|
|
93
|
+
reviewedAt: now,
|
|
94
|
+
reviewedBy: "manual",
|
|
95
|
+
rejectionReason: reason.trim()
|
|
96
|
+
});
|
|
97
|
+
if (!updatedCandidate) {
|
|
98
|
+
return yield* Effect.fail(new CandidateNotFoundError({ id }));
|
|
99
|
+
}
|
|
100
|
+
return updatedCandidate;
|
|
101
|
+
}),
|
|
102
|
+
autoPromote: () => Effect.gen(function* () {
|
|
103
|
+
// Get all pending high-confidence candidates
|
|
104
|
+
const candidates = yield* candidateRepo.findByFilter({
|
|
105
|
+
status: "pending",
|
|
106
|
+
confidence: "high"
|
|
107
|
+
});
|
|
108
|
+
let promoted = 0;
|
|
109
|
+
let skipped = 0;
|
|
110
|
+
let failed = 0;
|
|
111
|
+
const learningIds = [];
|
|
112
|
+
for (const candidate of candidates) {
|
|
113
|
+
// Check for duplicates using semantic search
|
|
114
|
+
const searchResult = yield* Effect.catchAll(learningService.search({
|
|
115
|
+
query: candidate.content,
|
|
116
|
+
limit: 1,
|
|
117
|
+
minScore: DUPLICATE_MIN_SCORE
|
|
118
|
+
}), () => Effect.succeed([]));
|
|
119
|
+
// If a highly similar learning exists, skip this candidate
|
|
120
|
+
if (searchResult.length > 0) {
|
|
121
|
+
skipped++;
|
|
122
|
+
// Mark as merged with the existing learning
|
|
123
|
+
yield* Effect.catchAll(candidateRepo.update(candidate.id, {
|
|
124
|
+
status: "merged",
|
|
125
|
+
reviewedAt: new Date(),
|
|
126
|
+
reviewedBy: "auto",
|
|
127
|
+
promotedLearningId: searchResult[0].id
|
|
128
|
+
}), () => Effect.void);
|
|
129
|
+
continue;
|
|
130
|
+
}
|
|
131
|
+
// Promote the candidate
|
|
132
|
+
const result = yield* Effect.either(promoteCandidate(candidate, "auto"));
|
|
133
|
+
if (result._tag === "Right") {
|
|
134
|
+
promoted++;
|
|
135
|
+
learningIds.push(result.right.learning.id);
|
|
136
|
+
}
|
|
137
|
+
else {
|
|
138
|
+
failed++;
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
return {
|
|
142
|
+
promoted,
|
|
143
|
+
skipped,
|
|
144
|
+
failed,
|
|
145
|
+
learningIds
|
|
146
|
+
};
|
|
147
|
+
}),
|
|
148
|
+
getPending: () => candidateRepo.findByFilter({ status: "pending" })
|
|
149
|
+
};
|
|
150
|
+
}));
|
|
151
|
+
//# sourceMappingURL=promotion-service.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"promotion-service.js","sourceRoot":"","sources":["../../src/services/promotion-service.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,27 +1,13 @@
|
|
|
1
1
|
import { Context, Effect, Layer } from "effect";
|
|
2
|
+
import { LlmUnavailableError } from "../errors.js";
|
|
2
3
|
import { LlmService } from "./llm-service.js";
|
|
3
|
-
declare const QueryExpansionUnavailableError_base: new <A extends Record<string, any> = {}>(args: import("effect/Types").Equals<A, {}> extends true ? void : { readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }) => import("effect/Cause").YieldableError & {
|
|
4
|
-
readonly _tag: "QueryExpansionUnavailableError";
|
|
5
|
-
} & Readonly<A>;
|
|
6
4
|
/**
|
|
7
5
|
* Error indicating query expansion is unavailable.
|
|
8
6
|
*/
|
|
9
|
-
export
|
|
10
|
-
readonly reason: string;
|
|
11
|
-
}> {
|
|
12
|
-
get message(): string;
|
|
13
|
-
}
|
|
7
|
+
export { LlmUnavailableError as QueryExpansionUnavailableError };
|
|
14
8
|
/**
|
|
15
9
|
* Result of query expansion.
|
|
16
10
|
*/
|
|
17
|
-
export declare const QueryExpansionResultSchema: {
|
|
18
|
-
/** Original query */
|
|
19
|
-
original: string;
|
|
20
|
-
/** Expanded queries (includes original plus alternatives) */
|
|
21
|
-
expanded: readonly string[];
|
|
22
|
-
/** Whether expansion was performed (false if using noop) */
|
|
23
|
-
wasExpanded: boolean;
|
|
24
|
-
};
|
|
25
11
|
export interface QueryExpansionResult {
|
|
26
12
|
/** Original query */
|
|
27
13
|
readonly original: string;
|
|
@@ -36,7 +22,7 @@ export declare const MAX_EXPANSION_QUERIES = 5;
|
|
|
36
22
|
export declare const MAX_QUERY_LENGTH = 200;
|
|
37
23
|
declare const QueryExpansionService_base: Context.TagClass<QueryExpansionService, "QueryExpansionService", {
|
|
38
24
|
/** Expand a search query into multiple alternative phrasings */
|
|
39
|
-
readonly expand: (query: string) => Effect.Effect<QueryExpansionResult,
|
|
25
|
+
readonly expand: (query: string) => Effect.Effect<QueryExpansionResult, LlmUnavailableError>;
|
|
40
26
|
/** Check if query expansion is available */
|
|
41
27
|
readonly isAvailable: () => Effect.Effect<boolean>;
|
|
42
28
|
}>;
|
|
@@ -44,7 +30,7 @@ declare const QueryExpansionService_base: Context.TagClass<QueryExpansionService
|
|
|
44
30
|
* QueryExpansionService uses an LLM to generate alternative phrasings of search queries.
|
|
45
31
|
* This improves recall by searching for semantically equivalent but differently worded queries.
|
|
46
32
|
*
|
|
47
|
-
* Design: Following DD-006 patterns for LLM integration
|
|
33
|
+
* Design: Following DD-006 patterns for LLM integration.
|
|
48
34
|
* The service gracefully degrades when no LLM backend is available.
|
|
49
35
|
*/
|
|
50
36
|
export declare class QueryExpansionService extends QueryExpansionService_base {
|
|
@@ -63,14 +49,13 @@ export declare const validateExpansions: (query: string, alternatives: unknown[]
|
|
|
63
49
|
*/
|
|
64
50
|
export declare const QueryExpansionServiceNoop: Layer.Layer<QueryExpansionService, never, never>;
|
|
65
51
|
/**
|
|
66
|
-
* Live implementation using centralized LlmService
|
|
67
|
-
*
|
|
52
|
+
* Live implementation using centralized LlmService.
|
|
53
|
+
* Depends on LlmService being provided in the layer context.
|
|
68
54
|
*/
|
|
69
55
|
export declare const QueryExpansionServiceLive: Layer.Layer<QueryExpansionService, never, LlmService>;
|
|
70
56
|
/**
|
|
71
|
-
* Auto-detecting layer
|
|
57
|
+
* Auto-detecting layer — uses Live if LlmService is available, Noop otherwise.
|
|
72
58
|
* This allows graceful degradation when no LLM backend is configured.
|
|
73
59
|
*/
|
|
74
60
|
export declare const QueryExpansionServiceAuto: Layer.Layer<QueryExpansionService, never, LlmService>;
|
|
75
|
-
export {};
|
|
76
61
|
//# sourceMappingURL=query-expansion-service.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"query-expansion-service.d.ts","sourceRoot":"","sources":["../../src/services/query-expansion-service.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,QAAQ,CAAA;
|
|
1
|
+
{"version":3,"file":"query-expansion-service.d.ts","sourceRoot":"","sources":["../../src/services/query-expansion-service.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,QAAQ,CAAA;AAC/C,OAAO,EAAE,mBAAmB,EAAE,MAAM,cAAc,CAAA;AAClD,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAA;AAE7C;;GAEG;AACH,OAAO,EAAE,mBAAmB,IAAI,8BAA8B,EAAE,CAAA;AAEhE;;GAEG;AACH,MAAM,WAAW,oBAAoB;IACnC,qBAAqB;IACrB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAA;IACzB,6DAA6D;IAC7D,QAAQ,CAAC,QAAQ,EAAE,SAAS,MAAM,EAAE,CAAA;IACpC,4DAA4D;IAC5D,QAAQ,CAAC,WAAW,EAAE,OAAO,CAAA;CAC9B;AAED,8FAA8F;AAC9F,eAAO,MAAM,qBAAqB,IAAI,CAAA;AAEtC,6DAA6D;AAC7D,eAAO,MAAM,gBAAgB,MAAM,CAAA;;IAY/B,gEAAgE;qBAC/C,CAAC,KAAK,EAAE,MAAM,KAAK,MAAM,CAAC,MAAM,CAAC,oBAAoB,EAAE,mBAAmB,CAAC;IAC5F,4CAA4C;0BACtB,MAAM,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC;;AAbtD;;;;;;GAMG;AACH,qBAAa,qBAAsB,SAAQ,0BAQxC;CAAG;AAqCN;;;;;;GAMG;AACH,eAAO,MAAM,kBAAkB,GAC7B,OAAO,MAAM,EACb,cAAc,OAAO,EAAE,KACtB,MAAM,EAYR,CAAA;AAED;;;GAGG;AACH,eAAO,MAAM,yBAAyB,kDAUrC,CAAA;AAED;;;GAGG;AACH,eAAO,MAAM,yBAAyB,uDAyCrC,CAAA;AAED;;;GAGG;AACH,eAAO,MAAM,yBAAyB,uDAYrC,CAAA"}
|
|
@@ -1,25 +1,10 @@
|
|
|
1
1
|
import { Context, Effect, Layer } from "effect";
|
|
2
|
-
import {
|
|
2
|
+
import { LlmUnavailableError } from "../errors.js";
|
|
3
3
|
import { LlmService } from "./llm-service.js";
|
|
4
4
|
/**
|
|
5
5
|
* Error indicating query expansion is unavailable.
|
|
6
6
|
*/
|
|
7
|
-
export
|
|
8
|
-
get message() {
|
|
9
|
-
return `Query expansion unavailable: ${this.reason}`;
|
|
10
|
-
}
|
|
11
|
-
}
|
|
12
|
-
/**
|
|
13
|
-
* Result of query expansion.
|
|
14
|
-
*/
|
|
15
|
-
export const QueryExpansionResultSchema = {
|
|
16
|
-
/** Original query */
|
|
17
|
-
original: "",
|
|
18
|
-
/** Expanded queries (includes original plus alternatives) */
|
|
19
|
-
expanded: [],
|
|
20
|
-
/** Whether expansion was performed (false if using noop) */
|
|
21
|
-
wasExpanded: false
|
|
22
|
-
};
|
|
7
|
+
export { LlmUnavailableError as QueryExpansionUnavailableError };
|
|
23
8
|
/** Maximum number of expanded queries (excluding original) to prevent unbounded generation */
|
|
24
9
|
export const MAX_EXPANSION_QUERIES = 5;
|
|
25
10
|
/** Maximum character length for any single expanded query */
|
|
@@ -28,7 +13,7 @@ export const MAX_QUERY_LENGTH = 200;
|
|
|
28
13
|
* QueryExpansionService uses an LLM to generate alternative phrasings of search queries.
|
|
29
14
|
* This improves recall by searching for semantically equivalent but differently worded queries.
|
|
30
15
|
*
|
|
31
|
-
* Design: Following DD-006 patterns for LLM integration
|
|
16
|
+
* Design: Following DD-006 patterns for LLM integration.
|
|
32
17
|
* The service gracefully degrades when no LLM backend is available.
|
|
33
18
|
*/
|
|
34
19
|
export class QueryExpansionService extends Context.Tag("QueryExpansionService")() {
|
|
@@ -44,55 +29,27 @@ Rules:
|
|
|
44
29
|
2. Use synonyms and related terminology
|
|
45
30
|
3. Consider different ways to express the same concept
|
|
46
31
|
4. Do NOT add information not implied by the original query
|
|
47
|
-
5. Output ONLY a JSON array of strings, nothing else
|
|
48
32
|
|
|
49
33
|
Example:
|
|
50
34
|
Input: "fix authentication bug"
|
|
51
|
-
Output: ["resolve auth issue", "debug login problem", "authentication error fix"]
|
|
35
|
+
Output: {"alternatives": ["resolve auth issue", "debug login problem", "authentication error fix"]}
|
|
52
36
|
|
|
53
37
|
Input: "add user profile page"
|
|
54
|
-
Output: ["create profile view", "implement user account page", "build profile screen"]
|
|
38
|
+
Output: {"alternatives": ["create profile view", "implement user account page", "build profile screen"]}
|
|
55
39
|
|
|
56
40
|
Now expand this query:
|
|
57
41
|
`;
|
|
58
|
-
/**
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
const fenceMatch = raw.match(/```(?:json)?\s*\n?([\s\S]*?)```/);
|
|
70
|
-
if (fenceMatch && fenceMatch[1]) {
|
|
71
|
-
try {
|
|
72
|
-
return JSON.parse(fenceMatch[1].trim());
|
|
73
|
-
}
|
|
74
|
-
catch { /* continue */ }
|
|
75
|
-
}
|
|
76
|
-
// Step 3: Find first [ or { and parse from there
|
|
77
|
-
const jsonStart = raw.search(/[[{]/);
|
|
78
|
-
if (jsonStart >= 0) {
|
|
79
|
-
const candidate = raw.slice(jsonStart);
|
|
80
|
-
try {
|
|
81
|
-
return JSON.parse(candidate);
|
|
82
|
-
}
|
|
83
|
-
catch { /* continue */ }
|
|
84
|
-
// Step 4: Find matching bracket and extract
|
|
85
|
-
const openChar = candidate[0];
|
|
86
|
-
const closeChar = openChar === "[" ? "]" : "}";
|
|
87
|
-
const lastClose = candidate.lastIndexOf(closeChar);
|
|
88
|
-
if (lastClose > 0) {
|
|
89
|
-
try {
|
|
90
|
-
return JSON.parse(candidate.slice(0, lastClose + 1));
|
|
91
|
-
}
|
|
92
|
-
catch { /* continue */ }
|
|
93
|
-
}
|
|
94
|
-
}
|
|
95
|
-
return null;
|
|
42
|
+
/** JSON Schema for structured output from the query expansion LLM call */
|
|
43
|
+
const EXPANSION_SCHEMA = {
|
|
44
|
+
type: "object",
|
|
45
|
+
properties: {
|
|
46
|
+
alternatives: {
|
|
47
|
+
type: "array",
|
|
48
|
+
items: { type: "string" },
|
|
49
|
+
},
|
|
50
|
+
},
|
|
51
|
+
required: ["alternatives"],
|
|
52
|
+
additionalProperties: false,
|
|
96
53
|
};
|
|
97
54
|
/**
|
|
98
55
|
* Validate and limit expanded query alternatives.
|
|
@@ -124,42 +81,51 @@ export const QueryExpansionServiceNoop = Layer.succeed(QueryExpansionService, {
|
|
|
124
81
|
isAvailable: () => Effect.succeed(false)
|
|
125
82
|
});
|
|
126
83
|
/**
|
|
127
|
-
* Live implementation using centralized LlmService
|
|
128
|
-
*
|
|
84
|
+
* Live implementation using centralized LlmService.
|
|
85
|
+
* Depends on LlmService being provided in the layer context.
|
|
129
86
|
*/
|
|
130
87
|
export const QueryExpansionServiceLive = Layer.effect(QueryExpansionService, Effect.gen(function* () {
|
|
131
|
-
const
|
|
88
|
+
const llmService = yield* LlmService;
|
|
132
89
|
return {
|
|
133
90
|
expand: (query) => Effect.gen(function* () {
|
|
134
|
-
const
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
91
|
+
const either = yield* Effect.either(llmService.complete({
|
|
92
|
+
prompt: EXPANSION_PROMPT + JSON.stringify(query),
|
|
93
|
+
model: "claude-haiku-4-20250514",
|
|
94
|
+
maxTokens: 256,
|
|
95
|
+
jsonSchema: EXPANSION_SCHEMA,
|
|
96
|
+
}));
|
|
97
|
+
// Graceful degradation: if LLM call fails, return original query
|
|
98
|
+
if (either._tag === "Left") {
|
|
138
99
|
return { original: query, expanded: [query], wasExpanded: false };
|
|
139
100
|
}
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
if (!alternatives || !Array.isArray(alternatives)) {
|
|
101
|
+
const result = either.right;
|
|
102
|
+
if (!result.text) {
|
|
143
103
|
return { original: query, expanded: [query], wasExpanded: false };
|
|
144
104
|
}
|
|
105
|
+
// Structured outputs guarantee valid JSON matching the schema
|
|
106
|
+
const parsed = JSON.parse(result.text);
|
|
145
107
|
// Validate and limit expansion results
|
|
146
|
-
const expanded = validateExpansions(query, alternatives);
|
|
108
|
+
const expanded = validateExpansions(query, parsed.alternatives);
|
|
147
109
|
return {
|
|
148
110
|
original: query,
|
|
149
111
|
expanded,
|
|
150
112
|
wasExpanded: expanded.length > 1
|
|
151
113
|
};
|
|
152
114
|
}),
|
|
153
|
-
isAvailable: () =>
|
|
115
|
+
isAvailable: () => llmService.isAvailable()
|
|
154
116
|
};
|
|
155
117
|
}));
|
|
156
118
|
/**
|
|
157
|
-
* Auto-detecting layer
|
|
119
|
+
* Auto-detecting layer — uses Live if LlmService is available, Noop otherwise.
|
|
158
120
|
* This allows graceful degradation when no LLM backend is configured.
|
|
159
121
|
*/
|
|
160
122
|
export const QueryExpansionServiceAuto = Layer.unwrapEffect(Effect.gen(function* () {
|
|
161
|
-
const
|
|
162
|
-
|
|
163
|
-
|
|
123
|
+
const opt = yield* Effect.serviceOption(LlmService).pipe(Effect.catchAll(() => Effect.succeed({ _tag: "None" })));
|
|
124
|
+
if (opt._tag === "Some") {
|
|
125
|
+
const available = yield* opt.value.isAvailable();
|
|
126
|
+
if (available)
|
|
127
|
+
return QueryExpansionServiceLive;
|
|
128
|
+
}
|
|
129
|
+
return QueryExpansionServiceNoop;
|
|
164
130
|
}));
|
|
165
131
|
//# sourceMappingURL=query-expansion-service.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"query-expansion-service.js","sourceRoot":"","sources":["../../src/services/query-expansion-service.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,QAAQ,CAAA;AAC/C,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"query-expansion-service.js","sourceRoot":"","sources":["../../src/services/query-expansion-service.ts"],"names":[],"mappings":"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"}
|