ds4-context-core 0.1.1 → 0.2.0-beta.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.
Files changed (121) hide show
  1. package/README.md +17 -4
  2. package/dist/adapter/conformance.d.ts +35 -0
  3. package/dist/adapter/conformance.d.ts.map +1 -0
  4. package/dist/adapter/conformance.js +260 -0
  5. package/dist/adapter/conformance.js.map +1 -0
  6. package/dist/adapter/runtime-adapter.d.ts +119 -0
  7. package/dist/adapter/runtime-adapter.d.ts.map +1 -0
  8. package/dist/adapter/runtime-adapter.js +289 -0
  9. package/dist/adapter/runtime-adapter.js.map +1 -0
  10. package/dist/config/config-loader.d.ts +1 -0
  11. package/dist/config/config-loader.d.ts.map +1 -1
  12. package/dist/config/config-loader.js +107 -1
  13. package/dist/config/config-loader.js.map +1 -1
  14. package/dist/config/config.d.ts +45 -0
  15. package/dist/config/config.d.ts.map +1 -1
  16. package/dist/config/config.js +28 -0
  17. package/dist/config/config.js.map +1 -1
  18. package/dist/core/canonical-message.d.ts +2 -1
  19. package/dist/core/canonical-message.d.ts.map +1 -1
  20. package/dist/index.d.ts +12 -0
  21. package/dist/index.d.ts.map +1 -1
  22. package/dist/index.js +12 -0
  23. package/dist/index.js.map +1 -1
  24. package/dist/manifest/context-manifest.d.ts +12 -0
  25. package/dist/manifest/context-manifest.d.ts.map +1 -1
  26. package/dist/memory/memory-manager.d.ts +7 -1
  27. package/dist/memory/memory-manager.d.ts.map +1 -1
  28. package/dist/memory/memory-manager.js +100 -3
  29. package/dist/memory/memory-manager.js.map +1 -1
  30. package/dist/memory/memory-types.d.ts +43 -0
  31. package/dist/memory/memory-types.d.ts.map +1 -1
  32. package/dist/memory/memory-types.js.map +1 -1
  33. package/dist/persistence/migrations.d.ts +2 -1
  34. package/dist/persistence/migrations.d.ts.map +1 -1
  35. package/dist/persistence/migrations.js +155 -25
  36. package/dist/persistence/migrations.js.map +1 -1
  37. package/dist/persistence/repositories/artifact-repository.d.ts +3 -1
  38. package/dist/persistence/repositories/artifact-repository.d.ts.map +1 -1
  39. package/dist/persistence/repositories/artifact-repository.js +16 -27
  40. package/dist/persistence/repositories/artifact-repository.js.map +1 -1
  41. package/dist/persistence/repositories/context-manifest-repository.d.ts +3 -1
  42. package/dist/persistence/repositories/context-manifest-repository.d.ts.map +1 -1
  43. package/dist/persistence/repositories/context-manifest-repository.js +10 -18
  44. package/dist/persistence/repositories/context-manifest-repository.js.map +1 -1
  45. package/dist/persistence/repositories/context-quality-repository.d.ts +21 -0
  46. package/dist/persistence/repositories/context-quality-repository.d.ts.map +1 -0
  47. package/dist/persistence/repositories/context-quality-repository.js +83 -0
  48. package/dist/persistence/repositories/context-quality-repository.js.map +1 -0
  49. package/dist/persistence/repositories/embedding-repository.d.ts +37 -0
  50. package/dist/persistence/repositories/embedding-repository.d.ts.map +1 -0
  51. package/dist/persistence/repositories/embedding-repository.js +142 -0
  52. package/dist/persistence/repositories/embedding-repository.js.map +1 -0
  53. package/dist/persistence/repositories/lease-repository.d.ts +22 -0
  54. package/dist/persistence/repositories/lease-repository.d.ts.map +1 -0
  55. package/dist/persistence/repositories/lease-repository.js +113 -0
  56. package/dist/persistence/repositories/lease-repository.js.map +1 -0
  57. package/dist/persistence/repositories/memory-repository.d.ts +34 -3
  58. package/dist/persistence/repositories/memory-repository.d.ts.map +1 -1
  59. package/dist/persistence/repositories/memory-repository.js +426 -64
  60. package/dist/persistence/repositories/memory-repository.js.map +1 -1
  61. package/dist/persistence/repositories/project-knowledge-repository.d.ts +28 -5
  62. package/dist/persistence/repositories/project-knowledge-repository.d.ts.map +1 -1
  63. package/dist/persistence/repositories/project-knowledge-repository.js +123 -53
  64. package/dist/persistence/repositories/project-knowledge-repository.js.map +1 -1
  65. package/dist/persistence/repositories/session-index-repository.d.ts +9 -1
  66. package/dist/persistence/repositories/session-index-repository.d.ts.map +1 -1
  67. package/dist/persistence/repositories/session-index-repository.js +38 -17
  68. package/dist/persistence/repositories/session-index-repository.js.map +1 -1
  69. package/dist/persistence/repositories/summary-repository.d.ts +3 -1
  70. package/dist/persistence/repositories/summary-repository.d.ts.map +1 -1
  71. package/dist/persistence/repositories/summary-repository.js +35 -31
  72. package/dist/persistence/repositories/summary-repository.js.map +1 -1
  73. package/dist/persistence/sqlite.d.ts +10 -0
  74. package/dist/persistence/sqlite.d.ts.map +1 -1
  75. package/dist/persistence/sqlite.js +41 -12
  76. package/dist/persistence/sqlite.js.map +1 -1
  77. package/dist/persistence/write-coordinator.d.ts +37 -0
  78. package/dist/persistence/write-coordinator.d.ts.map +1 -0
  79. package/dist/persistence/write-coordinator.js +120 -0
  80. package/dist/persistence/write-coordinator.js.map +1 -0
  81. package/dist/planner/context-planner.d.ts +5 -0
  82. package/dist/planner/context-planner.d.ts.map +1 -1
  83. package/dist/planner/context-planner.js +41 -62
  84. package/dist/planner/context-planner.js.map +1 -1
  85. package/dist/project/file-indexer.d.ts +5 -3
  86. package/dist/project/file-indexer.d.ts.map +1 -1
  87. package/dist/project/file-indexer.js +108 -42
  88. package/dist/project/file-indexer.js.map +1 -1
  89. package/dist/project/project-knowledge.d.ts +15 -3
  90. package/dist/project/project-knowledge.d.ts.map +1 -1
  91. package/dist/project/project-knowledge.js +168 -42
  92. package/dist/project/project-knowledge.js.map +1 -1
  93. package/dist/project/symbol-parser.d.ts +48 -0
  94. package/dist/project/symbol-parser.d.ts.map +1 -0
  95. package/dist/project/symbol-parser.js +427 -0
  96. package/dist/project/symbol-parser.js.map +1 -0
  97. package/dist/quality/context-quality.d.ts +172 -0
  98. package/dist/quality/context-quality.d.ts.map +1 -0
  99. package/dist/quality/context-quality.js +624 -0
  100. package/dist/quality/context-quality.js.map +1 -0
  101. package/dist/ranking/learned-ranker.d.ts +174 -0
  102. package/dist/ranking/learned-ranker.d.ts.map +1 -0
  103. package/dist/ranking/learned-ranker.js +782 -0
  104. package/dist/ranking/learned-ranker.js.map +1 -0
  105. package/dist/retrieval/embedding.d.ts +92 -0
  106. package/dist/retrieval/embedding.d.ts.map +1 -0
  107. package/dist/retrieval/embedding.js +56 -0
  108. package/dist/retrieval/embedding.js.map +1 -0
  109. package/dist/retrieval/retrieval-engine.d.ts +9 -1
  110. package/dist/retrieval/retrieval-engine.d.ts.map +1 -1
  111. package/dist/retrieval/retrieval-engine.js +105 -7
  112. package/dist/retrieval/retrieval-engine.js.map +1 -1
  113. package/dist/retrieval/semantic-index.d.ts +30 -0
  114. package/dist/retrieval/semantic-index.d.ts.map +1 -0
  115. package/dist/retrieval/semantic-index.js +284 -0
  116. package/dist/retrieval/semantic-index.js.map +1 -0
  117. package/dist/retrieval/semantic-quality.d.ts +52 -0
  118. package/dist/retrieval/semantic-quality.d.ts.map +1 -0
  119. package/dist/retrieval/semantic-quality.js +117 -0
  120. package/dist/retrieval/semantic-quality.js.map +1 -0
  121. package/package.json +1 -1
@@ -1,5 +1,6 @@
1
1
  import type { DatabaseSync } from "node:sqlite";
2
2
  import type { TokenCalibrationSample } from "../../core/model-awareness.ts";
3
+ import { SqliteWriteCoordinator } from "../write-coordinator.ts";
3
4
  import type { ContextManifest } from "../../manifest/context-manifest.ts";
4
5
  export interface ProviderTokenUsage {
5
6
  inputTokens: number;
@@ -8,7 +9,8 @@ export interface ProviderTokenUsage {
8
9
  }
9
10
  export declare class ContextManifestRepository {
10
11
  private readonly database;
11
- constructor(database: DatabaseSync);
12
+ private readonly writes;
13
+ constructor(database: DatabaseSync, writes?: SqliteWriteCoordinator);
12
14
  save(manifest: ContextManifest): void;
13
15
  get(manifestId: string): ContextManifest | undefined;
14
16
  getLatest(sessionId: string): ContextManifest | undefined;
@@ -1 +1 @@
1
- {"version":3,"file":"context-manifest-repository.d.ts","sourceRoot":"","sources":["../../../src/persistence/repositories/context-manifest-repository.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAChD,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,+BAA+B,CAAC;AAC5E,OAAO,KAAK,EACV,eAAe,EAEhB,MAAM,oCAAoC,CAAC;AAgB5C,MAAM,WAAW,kBAAkB;IACjC,WAAW,EAAE,MAAM,CAAC;IACpB,eAAe,EAAE,MAAM,CAAC;IACxB,gBAAgB,EAAE,MAAM,CAAC;CAC1B;AAiBD,qBAAa,yBAAyB;IACxB,OAAO,CAAC,QAAQ,CAAC,QAAQ;gBAAR,QAAQ,EAAE,YAAY;IAEnD,IAAI,CAAC,QAAQ,EAAE,eAAe,GAAG,IAAI;IA2CrC,GAAG,CAAC,UAAU,EAAE,MAAM,GAAG,eAAe,GAAG,SAAS;IAOpD,SAAS,CAAC,SAAS,EAAE,MAAM,GAAG,eAAe,GAAG,SAAS;IAWzD,mBAAmB,CACjB,UAAU,EAAE,MAAM,EAClB,KAAK,EAAE,kBAAkB,EACzB,SAAS,EAAE,MAAM,GAChB,eAAe,GAAG,SAAS;IA6E9B,iBAAiB,CAAC,UAAU,EAAE,MAAM,EAAE,iBAAiB,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,eAAe,GAAG,SAAS;IAQhH,sBAAsB,CACpB,QAAQ,EAAE,MAAM,EAChB,KAAK,EAAE,MAAM,EACb,KAAK,EAAE,MAAM,EACb,gBAAgB,SAAa,GAC5B,sBAAsB,EAAE;CAmB5B"}
1
+ {"version":3,"file":"context-manifest-repository.d.ts","sourceRoot":"","sources":["../../../src/persistence/repositories/context-manifest-repository.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAChD,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,+BAA+B,CAAC;AAC5E,OAAO,EAAE,sBAAsB,EAAE,MAAM,yBAAyB,CAAC;AACjE,OAAO,KAAK,EACV,eAAe,EAEhB,MAAM,oCAAoC,CAAC;AAgB5C,MAAM,WAAW,kBAAkB;IACjC,WAAW,EAAE,MAAM,CAAC;IACpB,eAAe,EAAE,MAAM,CAAC;IACxB,gBAAgB,EAAE,MAAM,CAAC;CAC1B;AAiBD,qBAAa,yBAAyB;IAElC,OAAO,CAAC,QAAQ,CAAC,QAAQ;IACzB,OAAO,CAAC,QAAQ,CAAC,MAAM;gBADN,QAAQ,EAAE,YAAY,EACtB,MAAM,yBAAuC;IAGhE,IAAI,CAAC,QAAQ,EAAE,eAAe,GAAG,IAAI;IA2CrC,GAAG,CAAC,UAAU,EAAE,MAAM,GAAG,eAAe,GAAG,SAAS;IAOpD,SAAS,CAAC,SAAS,EAAE,MAAM,GAAG,eAAe,GAAG,SAAS;IAWzD,mBAAmB,CACjB,UAAU,EAAE,MAAM,EAClB,KAAK,EAAE,kBAAkB,EACzB,SAAS,EAAE,MAAM,GAChB,eAAe,GAAG,SAAS;IAkE9B,iBAAiB,CAAC,UAAU,EAAE,MAAM,EAAE,iBAAiB,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,eAAe,GAAG,SAAS;IAQhH,sBAAsB,CACpB,QAAQ,EAAE,MAAM,EAChB,KAAK,EAAE,MAAM,EACb,KAAK,EAAE,MAAM,EACb,gBAAgB,SAAa,GAC5B,sBAAsB,EAAE;CAmB5B"}
@@ -1,3 +1,4 @@
1
+ import { SqliteWriteCoordinator } from "../write-coordinator.js";
1
2
  function validTokenCount(value) {
2
3
  return Number.isSafeInteger(value) && value >= 0;
3
4
  }
@@ -13,11 +14,13 @@ function providerUsage(input) {
13
14
  }
14
15
  export class ContextManifestRepository {
15
16
  database;
16
- constructor(database) {
17
+ writes;
18
+ constructor(database, writes = new SqliteWriteCoordinator(database)) {
17
19
  this.database = database;
20
+ this.writes = writes;
18
21
  }
19
22
  save(manifest) {
20
- this.database.prepare(`
23
+ this.writes.execute("context-manifest-save", () => this.database.prepare(`
21
24
  INSERT INTO context_manifests(
22
25
  manifest_id, session_id, created_at, provider, model,
23
26
  estimated_tokens, actual_tokens, manifest_json,
@@ -35,7 +38,7 @@ export class ContextManifestRepository {
35
38
  input_tokens = excluded.input_tokens,
36
39
  cache_read_tokens = excluded.cache_read_tokens,
37
40
  cache_write_tokens = excluded.cache_write_tokens
38
- `).run(manifest.id, manifest.sessionId, manifest.createdAt, manifest.provider, manifest.model, manifest.estimatedInputTokens, manifest.actualInputTokens ?? null, JSON.stringify(manifest), manifest.promptHash, manifest.policyVersion, manifest.plannerVersion, manifest.branchLeafId ?? null, manifest.contextWindow, manifest.outputReserve, manifest.hardInputLimit, manifest.targetInputTokens, manifest.piReportedContextTokens ?? null, manifest.providerUsage?.inputTokens ?? null, manifest.providerUsage?.cacheReadTokens ?? null, manifest.providerUsage?.cacheWriteTokens ?? null);
41
+ `).run(manifest.id, manifest.sessionId, manifest.createdAt, manifest.provider, manifest.model, manifest.estimatedInputTokens, manifest.actualInputTokens ?? null, JSON.stringify(manifest), manifest.promptHash, manifest.policyVersion, manifest.plannerVersion, manifest.branchLeafId ?? null, manifest.contextWindow, manifest.outputReserve, manifest.hardInputLimit, manifest.targetInputTokens, manifest.piReportedContextTokens ?? null, manifest.providerUsage?.inputTokens ?? null, manifest.providerUsage?.cacheReadTokens ?? null, manifest.providerUsage?.cacheWriteTokens ?? null));
39
42
  }
40
43
  get(manifestId) {
41
44
  const row = this.database.prepare("SELECT manifest_json, actual_tokens FROM context_manifests WHERE manifest_id = ?").get(manifestId);
@@ -62,22 +65,17 @@ export class ContextManifestRepository {
62
65
  const recordedUsage = providerUsage(usage);
63
66
  if (recordedUsage.totalInputTokens <= 0)
64
67
  return this.get(manifestId);
65
- this.database.exec("BEGIN IMMEDIATE");
66
- try {
68
+ return this.writes.transaction("context-manifest-provider-usage", () => {
67
69
  const row = this.database.prepare(`
68
70
  SELECT manifest_json, actual_tokens
69
71
  FROM context_manifests
70
72
  WHERE manifest_id = ?
71
73
  `).get(manifestId);
72
- if (!row) {
73
- this.database.exec("COMMIT");
74
+ if (!row)
74
75
  return undefined;
75
- }
76
76
  const manifest = parseManifest(row.manifest_json);
77
- if (row.actual_tokens !== null) {
78
- this.database.exec("COMMIT");
77
+ if (row.actual_tokens !== null)
79
78
  return manifest;
80
- }
81
79
  const updated = {
82
80
  ...manifest,
83
81
  actualInputTokens: recordedUsage.totalInputTokens,
@@ -97,14 +95,8 @@ export class ContextManifestRepository {
97
95
  ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
98
96
  `).run(manifest.provider, manifest.model, manifest.estimatedInputTokens, recordedUsage.totalInputTokens, recordedUsage.totalInputTokens / manifest.estimatedInputTokens, createdAt, manifestId, manifest.modelAwareness?.calibration.estimator ?? "chars-v1", recordedUsage.inputTokens, recordedUsage.cacheReadTokens, recordedUsage.cacheWriteTokens);
99
97
  }
100
- this.database.exec("COMMIT");
101
98
  return updated;
102
- }
103
- catch (error) {
104
- if (this.database.isTransaction)
105
- this.database.exec("ROLLBACK");
106
- throw error;
107
- }
99
+ });
108
100
  }
109
101
  recordActualInput(manifestId, actualInputTokens, createdAt) {
110
102
  return this.recordProviderUsage(manifestId, {
@@ -1 +1 @@
1
- {"version":3,"file":"context-manifest-repository.js","sourceRoot":"","sources":["../../../src/persistence/repositories/context-manifest-repository.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"context-manifest-repository.js","sourceRoot":"","sources":["../../../src/persistence/repositories/context-manifest-repository.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,21 @@
1
+ import type { DatabaseSync } from "node:sqlite";
2
+ import { SqliteWriteCoordinator } from "../write-coordinator.ts";
3
+ import { qualityTiming, type ContextQualityAggregate, type ContextQualitySample } from "../../quality/context-quality.ts";
4
+ export interface StoredContextQualitySamples {
5
+ samples: ContextQualitySample[];
6
+ ignoredSamples: number;
7
+ }
8
+ export interface StoredContextQualityAggregate extends StoredContextQualitySamples {
9
+ aggregate: ContextQualityAggregate;
10
+ timing: ReturnType<typeof qualityTiming>;
11
+ }
12
+ export declare class ContextQualityRepository {
13
+ private readonly database;
14
+ private readonly writes;
15
+ constructor(database: DatabaseSync, writes?: SqliteWriteCoordinator);
16
+ save(sample: ContextQualitySample, recordedAt: number, maxSamples: number): boolean;
17
+ list(limit?: number): StoredContextQualitySamples;
18
+ aggregate(limit?: number): StoredContextQualityAggregate;
19
+ clear(): void;
20
+ }
21
+ //# sourceMappingURL=context-quality-repository.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"context-quality-repository.d.ts","sourceRoot":"","sources":["../../../src/persistence/repositories/context-quality-repository.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAChD,OAAO,EAAE,sBAAsB,EAAE,MAAM,yBAAyB,CAAC;AACjE,OAAO,EAGL,aAAa,EACb,KAAK,uBAAuB,EAC5B,KAAK,oBAAoB,EAC1B,MAAM,kCAAkC,CAAC;AAM1C,MAAM,WAAW,2BAA2B;IAC1C,OAAO,EAAE,oBAAoB,EAAE,CAAC;IAChC,cAAc,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,WAAW,6BAA8B,SAAQ,2BAA2B;IAChF,SAAS,EAAE,uBAAuB,CAAC;IACnC,MAAM,EAAE,UAAU,CAAC,OAAO,aAAa,CAAC,CAAC;CAC1C;AAWD,qBAAa,wBAAwB;IAEjC,OAAO,CAAC,QAAQ,CAAC,QAAQ;IACzB,OAAO,CAAC,QAAQ,CAAC,MAAM;gBADN,QAAQ,EAAE,YAAY,EACtB,MAAM,yBAAuC;IAGhE,IAAI,CAAC,MAAM,EAAE,oBAAoB,EAAE,UAAU,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO;IAyCnF,IAAI,CAAC,KAAK,SAAS,GAAG,2BAA2B;IAkBjD,SAAS,CAAC,KAAK,SAAS,GAAG,6BAA6B;IASxD,KAAK,IAAI,IAAI;CAGd"}
@@ -0,0 +1,83 @@
1
+ import { SqliteWriteCoordinator } from "../write-coordinator.js";
2
+ import { aggregateContextQuality, isContextQualitySample, qualityTiming, } from "../../quality/context-quality.js";
3
+ function parseSample(value) {
4
+ try {
5
+ const parsed = JSON.parse(value);
6
+ return isContextQualitySample(parsed) ? parsed : undefined;
7
+ }
8
+ catch {
9
+ return undefined;
10
+ }
11
+ }
12
+ export class ContextQualityRepository {
13
+ database;
14
+ writes;
15
+ constructor(database, writes = new SqliteWriteCoordinator(database)) {
16
+ this.database = database;
17
+ this.writes = writes;
18
+ }
19
+ save(sample, recordedAt, maxSamples) {
20
+ if (!isContextQualitySample(sample)
21
+ || !Number.isSafeInteger(recordedAt)
22
+ || recordedAt < 0
23
+ || !Number.isSafeInteger(maxSamples)
24
+ || maxSamples <= 0)
25
+ return false;
26
+ return this.writes.transaction("context-quality-save", () => {
27
+ this.database.prepare(`
28
+ INSERT INTO context_quality_samples(
29
+ sample_id, strategy_id, corpus_version, planner_version,
30
+ profile_key, recorded_at, planning_duration_ms, sample_json
31
+ ) VALUES (?, ?, ?, ?, ?, ?, ?, ?)
32
+ ON CONFLICT(sample_id, strategy_id) DO UPDATE SET
33
+ corpus_version = excluded.corpus_version,
34
+ planner_version = excluded.planner_version,
35
+ profile_key = excluded.profile_key,
36
+ recorded_at = excluded.recorded_at,
37
+ planning_duration_ms = excluded.planning_duration_ms,
38
+ sample_json = excluded.sample_json
39
+ `).run(sample.sampleId, sample.strategyId, sample.corpusVersion, sample.plannerVersion, sample.profileKey, recordedAt, sample.timing?.planningDurationMs ?? null, JSON.stringify(sample));
40
+ this.database.prepare(`
41
+ DELETE FROM context_quality_samples
42
+ WHERE (sample_id, strategy_id) IN (
43
+ SELECT sample_id, strategy_id FROM context_quality_samples
44
+ ORDER BY recorded_at DESC, sample_id DESC, strategy_id DESC
45
+ LIMIT -1 OFFSET ?
46
+ )
47
+ `).run(maxSamples);
48
+ return true;
49
+ });
50
+ }
51
+ list(limit = 10_000) {
52
+ if (!Number.isSafeInteger(limit) || limit <= 0)
53
+ return { samples: [], ignoredSamples: 0 };
54
+ const rows = this.database.prepare(`
55
+ SELECT sample_json
56
+ FROM context_quality_samples
57
+ ORDER BY recorded_at ASC, sample_id ASC, strategy_id ASC
58
+ LIMIT ?
59
+ `).all(limit);
60
+ const samples = [];
61
+ let ignoredSamples = 0;
62
+ for (const row of rows) {
63
+ const sample = parseSample(row.sample_json);
64
+ if (sample)
65
+ samples.push(sample);
66
+ else
67
+ ignoredSamples++;
68
+ }
69
+ return { samples, ignoredSamples };
70
+ }
71
+ aggregate(limit = 10_000) {
72
+ const stored = this.list(limit);
73
+ return {
74
+ ...stored,
75
+ aggregate: aggregateContextQuality(stored.samples),
76
+ timing: qualityTiming(stored.samples),
77
+ };
78
+ }
79
+ clear() {
80
+ this.writes.execute("context-quality-clear", () => this.database.exec("DELETE FROM context_quality_samples"));
81
+ }
82
+ }
83
+ //# sourceMappingURL=context-quality-repository.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"context-quality-repository.js","sourceRoot":"","sources":["../../../src/persistence/repositories/context-quality-repository.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,37 @@
1
+ import type { DatabaseSync } from "node:sqlite";
2
+ import { SqliteWriteCoordinator } from "../write-coordinator.ts";
3
+ import { type EmbeddingModelIdentity, type EmbeddingSourceKind, type SemanticSearchHit } from "../../retrieval/embedding.ts";
4
+ export interface StoredEmbedding {
5
+ sourceKind: EmbeddingSourceKind;
6
+ scopeId: string;
7
+ sourceKey: string;
8
+ sourceGroup: string;
9
+ sourceHash: string;
10
+ chunkingVersion: string;
11
+ provider: string;
12
+ model: string;
13
+ dimensions: number;
14
+ vector: readonly number[];
15
+ indexedAt: number;
16
+ }
17
+ export interface EmbeddingSearchResult {
18
+ hits: SemanticSearchHit[];
19
+ scannedVectors: number;
20
+ corruptVectors: number;
21
+ }
22
+ export declare class EmbeddingRepository {
23
+ private readonly database;
24
+ private readonly writes;
25
+ constructor(database: DatabaseSync, writes?: SqliteWriteCoordinator);
26
+ getVector(kind: EmbeddingSourceKind, scopeId: string, sourceKey: string, sourceHash: string, chunkingVersion: string, identity: EmbeddingModelIdentity): readonly number[] | undefined;
27
+ upsert(rows: readonly StoredEmbedding[]): void;
28
+ /** Remove rows whose canonical source key/hash/chunk version is no longer current. */
29
+ pruneSources(kind: EmbeddingSourceKind, scopeId: string, sources: readonly {
30
+ sourceKey: string;
31
+ sourceHash: string;
32
+ chunkingVersion: string;
33
+ }[]): number;
34
+ searchSimilar(kind: EmbeddingSourceKind, scopeId: string, identity: EmbeddingModelIdentity, queryVector: readonly number[], limit: number, maximumRows: number): EmbeddingSearchResult;
35
+ countProfile(kind: EmbeddingSourceKind, scopeId: string, identity: EmbeddingModelIdentity): number;
36
+ }
37
+ //# sourceMappingURL=embedding-repository.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"embedding-repository.d.ts","sourceRoot":"","sources":["../../../src/persistence/repositories/embedding-repository.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAChD,OAAO,EAAE,sBAAsB,EAAE,MAAM,yBAAyB,CAAC;AACjE,OAAO,EAEL,KAAK,sBAAsB,EAC3B,KAAK,mBAAmB,EACxB,KAAK,iBAAiB,EAEvB,MAAM,8BAA8B,CAAC;AAEtC,MAAM,WAAW,eAAe;IAC9B,UAAU,EAAE,mBAAmB,CAAC;IAChC,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;IACnB,eAAe,EAAE,MAAM,CAAC;IACxB,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,SAAS,MAAM,EAAE,CAAC;IAC1B,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,qBAAqB;IACpC,IAAI,EAAE,iBAAiB,EAAE,CAAC;IAC1B,cAAc,EAAE,MAAM,CAAC;IACvB,cAAc,EAAE,MAAM,CAAC;CACxB;AAoBD,qBAAa,mBAAmB;IAE5B,OAAO,CAAC,QAAQ,CAAC,QAAQ;IACzB,OAAO,CAAC,QAAQ,CAAC,MAAM;gBADN,QAAQ,EAAE,YAAY,EACtB,MAAM,yBAAuC;IAGhE,SAAS,CACP,IAAI,EAAE,mBAAmB,EACzB,OAAO,EAAE,MAAM,EACf,SAAS,EAAE,MAAM,EACjB,UAAU,EAAE,MAAM,EAClB,eAAe,EAAE,MAAM,EACvB,QAAQ,EAAE,sBAAsB,GAC/B,SAAS,MAAM,EAAE,GAAG,SAAS;IAoBhC,MAAM,CAAC,IAAI,EAAE,SAAS,eAAe,EAAE,GAAG,IAAI;IAoC9C,sFAAsF;IACtF,YAAY,CACV,IAAI,EAAE,mBAAmB,EACzB,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,SAAS;QAAE,SAAS,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,CAAC;QAAC,eAAe,EAAE,MAAM,CAAA;KAAE,EAAE,GACrF,MAAM;IAiCT,aAAa,CACX,IAAI,EAAE,mBAAmB,EACzB,OAAO,EAAE,MAAM,EACf,QAAQ,EAAE,sBAAsB,EAChC,WAAW,EAAE,SAAS,MAAM,EAAE,EAC9B,KAAK,EAAE,MAAM,EACb,WAAW,EAAE,MAAM,GAClB,qBAAqB;IAqDxB,YAAY,CACV,IAAI,EAAE,mBAAmB,EACzB,OAAO,EAAE,MAAM,EACf,QAAQ,EAAE,sBAAsB,GAC/B,MAAM;CAeV"}
@@ -0,0 +1,142 @@
1
+ import { SqliteWriteCoordinator } from "../write-coordinator.js";
2
+ import { cosineSimilarity, validEmbeddingVector, } from "../../retrieval/embedding.js";
3
+ function parseVector(value, dimensions) {
4
+ try {
5
+ const parsed = JSON.parse(value);
6
+ if (!Array.isArray(parsed))
7
+ return undefined;
8
+ const vector = parsed.filter((item) => typeof item === "number");
9
+ return validEmbeddingVector(vector, dimensions) ? vector : undefined;
10
+ }
11
+ catch {
12
+ return undefined;
13
+ }
14
+ }
15
+ export class EmbeddingRepository {
16
+ database;
17
+ writes;
18
+ constructor(database, writes = new SqliteWriteCoordinator(database)) {
19
+ this.database = database;
20
+ this.writes = writes;
21
+ }
22
+ getVector(kind, scopeId, sourceKey, sourceHash, chunkingVersion, identity) {
23
+ const row = this.database.prepare(`
24
+ SELECT vector_json
25
+ FROM derived_embeddings
26
+ WHERE source_kind = ? AND scope_id = ? AND source_key = ?
27
+ AND source_hash = ? AND chunking_version = ?
28
+ AND embedding_provider = ? AND embedding_model = ? AND dimensions = ?
29
+ `).get(kind, scopeId, sourceKey, sourceHash, chunkingVersion, identity.provider, identity.model, identity.dimensions);
30
+ return row ? parseVector(row.vector_json, identity.dimensions) : undefined;
31
+ }
32
+ upsert(rows) {
33
+ if (rows.length === 0)
34
+ return;
35
+ this.writes.transaction("embedding-upsert", () => {
36
+ const statement = this.database.prepare(`
37
+ INSERT INTO derived_embeddings(
38
+ source_kind, scope_id, source_key, source_group, source_hash,
39
+ chunking_version, embedding_provider, embedding_model, dimensions,
40
+ vector_json, indexed_at
41
+ ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
42
+ ON CONFLICT(
43
+ source_kind, scope_id, source_key, source_hash, chunking_version,
44
+ embedding_provider, embedding_model, dimensions
45
+ ) DO UPDATE SET
46
+ source_group = excluded.source_group,
47
+ vector_json = excluded.vector_json,
48
+ indexed_at = excluded.indexed_at
49
+ `);
50
+ for (const row of rows) {
51
+ if (!validEmbeddingVector(row.vector, row.dimensions))
52
+ continue;
53
+ statement.run(row.sourceKind, row.scopeId, row.sourceKey, row.sourceGroup, row.sourceHash, row.chunkingVersion, row.provider, row.model, row.dimensions, JSON.stringify(row.vector), row.indexedAt);
54
+ }
55
+ });
56
+ }
57
+ /** Remove rows whose canonical source key/hash/chunk version is no longer current. */
58
+ pruneSources(kind, scopeId, sources) {
59
+ return this.writes.transaction("embedding-prune", () => {
60
+ this.database.exec(`
61
+ CREATE TEMP TABLE IF NOT EXISTS ds4_current_embedding_sources (
62
+ source_key TEXT NOT NULL,
63
+ source_hash TEXT NOT NULL,
64
+ chunking_version TEXT NOT NULL,
65
+ PRIMARY KEY(source_key, source_hash, chunking_version)
66
+ ) WITHOUT ROWID, STRICT;
67
+ DELETE FROM ds4_current_embedding_sources;
68
+ `);
69
+ const insert = this.database.prepare(`
70
+ INSERT OR IGNORE INTO ds4_current_embedding_sources(
71
+ source_key, source_hash, chunking_version
72
+ ) VALUES (?, ?, ?)
73
+ `);
74
+ for (const source of sources) {
75
+ insert.run(source.sourceKey, source.sourceHash, source.chunkingVersion);
76
+ }
77
+ const result = this.database.prepare(`
78
+ DELETE FROM derived_embeddings
79
+ WHERE source_kind = ? AND scope_id = ?
80
+ AND NOT EXISTS (
81
+ SELECT 1 FROM ds4_current_embedding_sources AS current
82
+ WHERE current.source_key = derived_embeddings.source_key
83
+ AND current.source_hash = derived_embeddings.source_hash
84
+ AND current.chunking_version = derived_embeddings.chunking_version
85
+ )
86
+ `).run(kind, scopeId);
87
+ return Number(result.changes);
88
+ });
89
+ }
90
+ searchSimilar(kind, scopeId, identity, queryVector, limit, maximumRows) {
91
+ if (!validEmbeddingVector(queryVector, identity.dimensions)) {
92
+ return { hits: [], scannedVectors: 0, corruptVectors: 0 };
93
+ }
94
+ const rows = this.database.prepare(`
95
+ SELECT source_key, source_hash, chunking_version, vector_json
96
+ FROM derived_embeddings
97
+ WHERE source_kind = ? AND scope_id = ?
98
+ AND embedding_provider = ? AND embedding_model = ? AND dimensions = ?
99
+ ORDER BY source_key, source_hash, chunking_version
100
+ LIMIT ?
101
+ `).all(kind, scopeId, identity.provider, identity.model, identity.dimensions, maximumRows);
102
+ let corruptVectors = 0;
103
+ const scored = [];
104
+ for (const row of rows) {
105
+ const vector = parseVector(row.vector_json, identity.dimensions);
106
+ if (!vector) {
107
+ corruptVectors++;
108
+ continue;
109
+ }
110
+ const similarity = cosineSimilarity(queryVector, vector);
111
+ if (similarity === undefined || !Number.isFinite(similarity)) {
112
+ corruptVectors++;
113
+ continue;
114
+ }
115
+ scored.push({
116
+ sourceKey: row.source_key,
117
+ sourceHash: row.source_hash,
118
+ chunkingVersion: row.chunking_version,
119
+ similarity: Math.round(similarity * 1_000_000) / 1_000_000,
120
+ });
121
+ }
122
+ scored.sort((left, right) => right.similarity - left.similarity
123
+ || left.sourceKey.localeCompare(right.sourceKey)
124
+ || left.sourceHash.localeCompare(right.sourceHash)
125
+ || left.chunkingVersion.localeCompare(right.chunkingVersion));
126
+ return {
127
+ hits: scored.slice(0, Math.max(0, limit)).map((hit, rank) => ({ ...hit, rank })),
128
+ scannedVectors: rows.length,
129
+ corruptVectors,
130
+ };
131
+ }
132
+ countProfile(kind, scopeId, identity) {
133
+ const row = this.database.prepare(`
134
+ SELECT count(*) AS count
135
+ FROM derived_embeddings
136
+ WHERE source_kind = ? AND scope_id = ?
137
+ AND embedding_provider = ? AND embedding_model = ? AND dimensions = ?
138
+ `).get(kind, scopeId, identity.provider, identity.model, identity.dimensions);
139
+ return row.count;
140
+ }
141
+ }
142
+ //# sourceMappingURL=embedding-repository.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"embedding-repository.js","sourceRoot":"","sources":["../../../src/persistence/repositories/embedding-repository.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,22 @@
1
+ import type { DatabaseSync } from "node:sqlite";
2
+ import { SqliteWriteCoordinator } from "../write-coordinator.ts";
3
+ export interface ResourceLease {
4
+ resourceType: string;
5
+ resourceKey: string;
6
+ ownerId: string;
7
+ fencingToken: number;
8
+ acquiredAt: number;
9
+ expiresAt: number;
10
+ }
11
+ export declare class LeaseRepository {
12
+ private readonly database;
13
+ private readonly writes;
14
+ constructor(database: DatabaseSync, writes?: SqliteWriteCoordinator);
15
+ acquire(resourceType: string, resourceKey: string, ownerId: string, acquiredAt: number, durationMs: number): ResourceLease | undefined;
16
+ renew(lease: ResourceLease, renewedAt: number, durationMs: number): ResourceLease | undefined;
17
+ isHeld(lease: ResourceLease, at: number): boolean;
18
+ release(lease: ResourceLease): boolean;
19
+ get(resourceType: string, resourceKey: string): ResourceLease | undefined;
20
+ deleteExpired(expiredAt: number): number;
21
+ }
22
+ //# sourceMappingURL=lease-repository.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lease-repository.d.ts","sourceRoot":"","sources":["../../../src/persistence/repositories/lease-repository.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAChD,OAAO,EAAE,sBAAsB,EAAE,MAAM,yBAAyB,CAAC;AAEjE,MAAM,WAAW,aAAa;IAC5B,YAAY,EAAE,MAAM,CAAC;IACrB,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC;IAChB,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;CACnB;AAuCD,qBAAa,eAAe;IAExB,OAAO,CAAC,QAAQ,CAAC,QAAQ;IACzB,OAAO,CAAC,QAAQ,CAAC,MAAM;gBADN,QAAQ,EAAE,YAAY,EACtB,MAAM,yBAAuC;IAGhE,OAAO,CACL,YAAY,EAAE,MAAM,EACpB,WAAW,EAAE,MAAM,EACnB,OAAO,EAAE,MAAM,EACf,UAAU,EAAE,MAAM,EAClB,UAAU,EAAE,MAAM,GACjB,aAAa,GAAG,SAAS;IA2B5B,KAAK,CAAC,KAAK,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,aAAa,GAAG,SAAS;IAyB7F,MAAM,CAAC,KAAK,EAAE,aAAa,EAAE,EAAE,EAAE,MAAM,GAAG,OAAO;IAejD,OAAO,CAAC,KAAK,EAAE,aAAa,GAAG,OAAO;IAUtC,GAAG,CAAC,YAAY,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,aAAa,GAAG,SAAS;IASzE,aAAa,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM;CAMzC"}
@@ -0,0 +1,113 @@
1
+ import { SqliteWriteCoordinator } from "../write-coordinator.js";
2
+ function leaseFromRow(row) {
3
+ return {
4
+ resourceType: row.resource_type,
5
+ resourceKey: row.resource_key,
6
+ ownerId: row.owner_id,
7
+ fencingToken: row.fencing_token,
8
+ acquiredAt: row.acquired_at,
9
+ expiresAt: row.expires_at,
10
+ };
11
+ }
12
+ function validIdentity(value) {
13
+ return value.trim() === value && value.length > 0 && value.length <= 4_096;
14
+ }
15
+ function validateRequest(resourceType, resourceKey, ownerId, at) {
16
+ if (!validIdentity(resourceType))
17
+ throw new Error("Lease resourceType must be a non-empty trimmed string");
18
+ if (!validIdentity(resourceKey))
19
+ throw new Error("Lease resourceKey must be a non-empty trimmed string");
20
+ if (!validIdentity(ownerId))
21
+ throw new Error("Lease ownerId must be a non-empty trimmed string");
22
+ if (!Number.isSafeInteger(at) || at < 0)
23
+ throw new Error("Lease timestamp must be a non-negative integer");
24
+ }
25
+ function validateDuration(durationMs) {
26
+ if (!Number.isSafeInteger(durationMs) || durationMs < 1 || durationMs > 86_400_000) {
27
+ throw new Error("Lease durationMs must be an integer between 1 and 86400000");
28
+ }
29
+ }
30
+ export class LeaseRepository {
31
+ database;
32
+ writes;
33
+ constructor(database, writes = new SqliteWriteCoordinator(database)) {
34
+ this.database = database;
35
+ this.writes = writes;
36
+ }
37
+ acquire(resourceType, resourceKey, ownerId, acquiredAt, durationMs) {
38
+ validateRequest(resourceType, resourceKey, ownerId, acquiredAt);
39
+ validateDuration(durationMs);
40
+ const expiresAt = acquiredAt + durationMs;
41
+ if (!Number.isSafeInteger(expiresAt))
42
+ throw new Error("Lease expiry exceeds the safe integer range");
43
+ return this.writes.execute("lease-acquire", () => {
44
+ const row = this.database.prepare(`
45
+ INSERT INTO resource_leases(
46
+ resource_type, resource_key, owner_id, fencing_token, acquired_at, expires_at
47
+ ) VALUES (?, ?, ?, 1, ?, ?)
48
+ ON CONFLICT(resource_type, resource_key) DO UPDATE SET
49
+ owner_id = excluded.owner_id,
50
+ fencing_token = CASE
51
+ WHEN resource_leases.owner_id = excluded.owner_id THEN resource_leases.fencing_token
52
+ ELSE resource_leases.fencing_token + 1
53
+ END,
54
+ acquired_at = excluded.acquired_at,
55
+ expires_at = excluded.expires_at
56
+ WHERE resource_leases.owner_id = excluded.owner_id
57
+ OR resource_leases.expires_at <= excluded.acquired_at
58
+ RETURNING resource_type, resource_key, owner_id, fencing_token, acquired_at, expires_at
59
+ `).get(resourceType, resourceKey, ownerId, acquiredAt, expiresAt);
60
+ return row ? leaseFromRow(row) : undefined;
61
+ });
62
+ }
63
+ renew(lease, renewedAt, durationMs) {
64
+ validateRequest(lease.resourceType, lease.resourceKey, lease.ownerId, renewedAt);
65
+ validateDuration(durationMs);
66
+ const expiresAt = Math.max(lease.expiresAt, renewedAt + durationMs);
67
+ if (!Number.isSafeInteger(expiresAt))
68
+ throw new Error("Lease expiry exceeds the safe integer range");
69
+ return this.writes.execute("lease-renew", () => {
70
+ const row = this.database.prepare(`
71
+ UPDATE resource_leases
72
+ SET expires_at = ?
73
+ WHERE resource_type = ? AND resource_key = ? AND owner_id = ?
74
+ AND fencing_token = ? AND expires_at > ?
75
+ RETURNING resource_type, resource_key, owner_id, fencing_token, acquired_at, expires_at
76
+ `).get(expiresAt, lease.resourceType, lease.resourceKey, lease.ownerId, lease.fencingToken, renewedAt);
77
+ return row ? leaseFromRow(row) : undefined;
78
+ });
79
+ }
80
+ isHeld(lease, at) {
81
+ if (!Number.isSafeInteger(at) || at < 0)
82
+ return false;
83
+ return this.database.prepare(`
84
+ SELECT 1 AS held FROM resource_leases
85
+ WHERE resource_type = ? AND resource_key = ? AND owner_id = ?
86
+ AND fencing_token = ? AND expires_at > ?
87
+ `).get(lease.resourceType, lease.resourceKey, lease.ownerId, lease.fencingToken, at) !== undefined;
88
+ }
89
+ release(lease) {
90
+ return this.writes.execute("lease-release", () => {
91
+ const result = this.database.prepare(`
92
+ DELETE FROM resource_leases
93
+ WHERE resource_type = ? AND resource_key = ? AND owner_id = ? AND fencing_token = ?
94
+ `).run(lease.resourceType, lease.resourceKey, lease.ownerId, lease.fencingToken);
95
+ return result.changes === 1;
96
+ });
97
+ }
98
+ get(resourceType, resourceKey) {
99
+ if (!validIdentity(resourceType) || !validIdentity(resourceKey))
100
+ return undefined;
101
+ const row = this.database.prepare(`
102
+ SELECT resource_type, resource_key, owner_id, fencing_token, acquired_at, expires_at
103
+ FROM resource_leases WHERE resource_type = ? AND resource_key = ?
104
+ `).get(resourceType, resourceKey);
105
+ return row ? leaseFromRow(row) : undefined;
106
+ }
107
+ deleteExpired(expiredAt) {
108
+ if (!Number.isSafeInteger(expiredAt) || expiredAt < 0)
109
+ return 0;
110
+ return this.writes.execute("lease-delete-expired", () => Number(this.database.prepare("DELETE FROM resource_leases WHERE expires_at <= ?").run(expiredAt).changes));
111
+ }
112
+ }
113
+ //# sourceMappingURL=lease-repository.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lease-repository.js","sourceRoot":"","sources":["../../../src/persistence/repositories/lease-repository.ts"],"names":[],"mappings":"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"}