@equationalapplications/core-llm-wiki 4.3.0 → 4.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/README.md CHANGED
@@ -398,6 +398,71 @@ await wikiMemory.write('user-123', {
398
398
  const memory = await wikiMemory.read('user-123', 'coding style preferences');
399
399
  ```
400
400
 
401
+ ### Multi-entity weighted reads
402
+
403
+ `read()` accepts either one entity id or an array of entity ids. Facts are always merged globally before `maxResults` is applied. For single-entity reads, tasks are uncapped and events are capped at 10. For multi-entity reads, tasks are capped at `min(20 × entity count, 200)` and events at `min(10 × entity count, 100)` — per-entity representation in the returned bundle is not guaranteed.
404
+
405
+ ```ts
406
+ const memory = await wikiMemory.read(['tier_wisdom', 'tier_fact', 'tier_working'], 'Which source should I trust?', {
407
+ maxResults: 8,
408
+ tierWeights: {
409
+ tier_wisdom: 2,
410
+ tier_fact: 1,
411
+ tier_working: 0.25,
412
+ },
413
+ });
414
+
415
+ console.log(memory.metadata);
416
+ console.log(memory.factScores);
417
+ ```
418
+
419
+ ### Librarian prompt override contract
420
+
421
+ Core does not own a provider-specific synthesis API, but it exports prompt utilities for applications that synthesize answers from weighted retrieval results.
422
+
423
+ ```ts
424
+ import {
425
+ DEFAULT_LIBRARIAN_SYNTHESIS_PROMPT,
426
+ formatContext,
427
+ hydrateLibrarianPrompt,
428
+ mapLibrarianOptionsToReadOptions,
429
+ validateLibrarianPromptTemplate,
430
+ } from '@equationalapplications/core-llm-wiki';
431
+
432
+ const options = {
433
+ entityWeights: { tier_wisdom: 2, tier_fact: 1, tier_working: 0.25 },
434
+ systemPrompt: `You are a strict fact checker.
435
+ Question:
436
+ {{query}}
437
+
438
+ Retrieved context:
439
+ {{context}}
440
+
441
+ {{tasks}}`,
442
+ };
443
+
444
+ const query = 'Which source should I trust for recent project decisions?';
445
+
446
+ const memory = await wikiMemory.read(['tier_wisdom', 'tier_fact', 'tier_working'], query, {
447
+ ...mapLibrarianOptionsToReadOptions(options),
448
+ maxResults: 8,
449
+ });
450
+
451
+ const template = options.systemPrompt ?? DEFAULT_LIBRARIAN_SYNTHESIS_PROMPT;
452
+ const warnings = validateLibrarianPromptTemplate(template, {
453
+ custom: options.systemPrompt != null,
454
+ taskCount: memory.tasks.length,
455
+ });
456
+
457
+ for (const warning of warnings) console.warn(warning);
458
+
459
+ const finalPrompt = hydrateLibrarianPrompt(template, {
460
+ query,
461
+ context: formatContext(memory, { includeEntityIds: true, includeFactScores: true }),
462
+ tasks: formatContext({ facts: [], tasks: memory.tasks, events: [] }, { format: 'plain' }),
463
+ });
464
+ ```
465
+
401
466
  ## Adapter Interface
402
467
 
403
468
  Implement `SQLiteAdapter` to use your platform's SQLite driver:
package/dist/index.d.mts CHANGED
@@ -313,6 +313,8 @@ interface FormatContextOptions {
313
313
  maxEvents?: number;
314
314
  includeConfidence?: boolean;
315
315
  includeTags?: boolean;
316
+ includeEntityIds?: boolean;
317
+ includeFactScores?: boolean;
316
318
  factWeights?: {
317
319
  confidence?: number;
318
320
  accessCount?: number;
@@ -531,6 +533,28 @@ declare function formatMemoryDump(dump: MemoryDump): FormattedMemoryDump;
531
533
 
532
534
  declare function parseEmbedding(blob: Uint8Array | null | undefined, text: string | null | undefined): Float32Array | null;
533
535
 
536
+ interface LibrarianOptions {
537
+ /** If provided, replaces the default Librarian system instructions. */
538
+ systemPrompt?: string;
539
+ /** entity_id -> score multiplier, forwarded to WikiMemory.read() as tierWeights. */
540
+ entityWeights?: Record<string, number>;
541
+ /** Forwarded to WikiMemory.read() for zero-weight filler context. */
542
+ includeZeroWeightEntities?: boolean;
543
+ temperature?: number;
544
+ }
545
+ interface LibrarianPromptVariables {
546
+ context: string;
547
+ tasks: string;
548
+ query: string;
549
+ }
550
+ declare const DEFAULT_LIBRARIAN_SYNTHESIS_PROMPT = "You are a careful memory synthesis assistant.\nUse only the retrieved context when answering the request.\nPreserve source provenance when facts come from different entity namespaces.\n\nRequest:\n{{query}}\n\nRetrieved context:\n{{context}}\n\nOpen tasks:\n{{tasks}}";
551
+ declare function hydrateLibrarianPrompt(template: string, variables: LibrarianPromptVariables): string;
552
+ declare function validateLibrarianPromptTemplate(template: string, options: {
553
+ custom: boolean;
554
+ taskCount: number;
555
+ }): string[];
556
+ declare function mapLibrarianOptionsToReadOptions(options: LibrarianOptions): Pick<ReadOptions, 'tierWeights' | 'includeZeroWeightEntities'>;
557
+
534
558
  declare function createWiki(db: SQLiteAdapter, options: WikiOptions): WikiMemory;
535
559
 
536
- export { type EntityStatus, type ExtractedFact, type ExtractedTask, type FormatContextOptions, type FormattedMemoryDump, type LLMProvider, type MemoryBundle, type MemoryDump, PrunePartialFailureError, type ReadOptions, type SQLiteAdapter, type VectorRanker, type VectorRankerFallback, type VectorRankerRankArgs, type VectorRankerSemanticResult, WikiBusyError, type WikiBusyOperation, type WikiCheckpoint, type WikiConfig, type WikiEvent, type WikiFact, WikiMemory, type WikiOptions, type WikiTask, createWiki, formatContext, formatMemoryDump, parseEmbedding };
560
+ export { DEFAULT_LIBRARIAN_SYNTHESIS_PROMPT, type EntityStatus, type ExtractedFact, type ExtractedTask, type FormatContextOptions, type FormattedMemoryDump, type LLMProvider, type LibrarianOptions, type LibrarianPromptVariables, type MemoryBundle, type MemoryDump, PrunePartialFailureError, type ReadOptions, type SQLiteAdapter, type VectorRanker, type VectorRankerFallback, type VectorRankerRankArgs, type VectorRankerSemanticResult, WikiBusyError, type WikiBusyOperation, type WikiCheckpoint, type WikiConfig, type WikiEvent, type WikiFact, WikiMemory, type WikiOptions, type WikiTask, createWiki, formatContext, formatMemoryDump, hydrateLibrarianPrompt, mapLibrarianOptionsToReadOptions, parseEmbedding, validateLibrarianPromptTemplate };
package/dist/index.d.ts CHANGED
@@ -313,6 +313,8 @@ interface FormatContextOptions {
313
313
  maxEvents?: number;
314
314
  includeConfidence?: boolean;
315
315
  includeTags?: boolean;
316
+ includeEntityIds?: boolean;
317
+ includeFactScores?: boolean;
316
318
  factWeights?: {
317
319
  confidence?: number;
318
320
  accessCount?: number;
@@ -531,6 +533,28 @@ declare function formatMemoryDump(dump: MemoryDump): FormattedMemoryDump;
531
533
 
532
534
  declare function parseEmbedding(blob: Uint8Array | null | undefined, text: string | null | undefined): Float32Array | null;
533
535
 
536
+ interface LibrarianOptions {
537
+ /** If provided, replaces the default Librarian system instructions. */
538
+ systemPrompt?: string;
539
+ /** entity_id -> score multiplier, forwarded to WikiMemory.read() as tierWeights. */
540
+ entityWeights?: Record<string, number>;
541
+ /** Forwarded to WikiMemory.read() for zero-weight filler context. */
542
+ includeZeroWeightEntities?: boolean;
543
+ temperature?: number;
544
+ }
545
+ interface LibrarianPromptVariables {
546
+ context: string;
547
+ tasks: string;
548
+ query: string;
549
+ }
550
+ declare const DEFAULT_LIBRARIAN_SYNTHESIS_PROMPT = "You are a careful memory synthesis assistant.\nUse only the retrieved context when answering the request.\nPreserve source provenance when facts come from different entity namespaces.\n\nRequest:\n{{query}}\n\nRetrieved context:\n{{context}}\n\nOpen tasks:\n{{tasks}}";
551
+ declare function hydrateLibrarianPrompt(template: string, variables: LibrarianPromptVariables): string;
552
+ declare function validateLibrarianPromptTemplate(template: string, options: {
553
+ custom: boolean;
554
+ taskCount: number;
555
+ }): string[];
556
+ declare function mapLibrarianOptionsToReadOptions(options: LibrarianOptions): Pick<ReadOptions, 'tierWeights' | 'includeZeroWeightEntities'>;
557
+
534
558
  declare function createWiki(db: SQLiteAdapter, options: WikiOptions): WikiMemory;
535
559
 
536
- export { type EntityStatus, type ExtractedFact, type ExtractedTask, type FormatContextOptions, type FormattedMemoryDump, type LLMProvider, type MemoryBundle, type MemoryDump, PrunePartialFailureError, type ReadOptions, type SQLiteAdapter, type VectorRanker, type VectorRankerFallback, type VectorRankerRankArgs, type VectorRankerSemanticResult, WikiBusyError, type WikiBusyOperation, type WikiCheckpoint, type WikiConfig, type WikiEvent, type WikiFact, WikiMemory, type WikiOptions, type WikiTask, createWiki, formatContext, formatMemoryDump, parseEmbedding };
560
+ export { DEFAULT_LIBRARIAN_SYNTHESIS_PROMPT, type EntityStatus, type ExtractedFact, type ExtractedTask, type FormatContextOptions, type FormattedMemoryDump, type LLMProvider, type LibrarianOptions, type LibrarianPromptVariables, type MemoryBundle, type MemoryDump, PrunePartialFailureError, type ReadOptions, type SQLiteAdapter, type VectorRanker, type VectorRankerFallback, type VectorRankerRankArgs, type VectorRankerSemanticResult, WikiBusyError, type WikiBusyOperation, type WikiCheckpoint, type WikiConfig, type WikiEvent, type WikiFact, WikiMemory, type WikiOptions, type WikiTask, createWiki, formatContext, formatMemoryDump, hydrateLibrarianPrompt, mapLibrarianOptionsToReadOptions, parseEmbedding, validateLibrarianPromptTemplate };
package/dist/index.js CHANGED
@@ -1064,14 +1064,14 @@ After running the migration SQL, restart your application.`
1064
1064
  );
1065
1065
  }
1066
1066
  }
1067
- const entityScope = this._entityInClause(scoredEntityIds);
1067
+ const mismatchScope = this._entityInClause(entityIds);
1068
1068
  const mismatchedCount = await this.db.getFirstAsync(
1069
1069
  `SELECT COUNT(*) AS cnt FROM ${this.prefix}entries
1070
- WHERE ${entityScope.clause} AND deleted_at IS NULL
1070
+ WHERE ${mismatchScope.clause} AND deleted_at IS NULL
1071
1071
  AND embedding_blob IS NOT NULL
1072
1072
  AND (CAST(length(embedding_blob) AS INTEGER) % 4 = 0)
1073
1073
  AND (CAST(length(embedding_blob) AS INTEGER) / 4) != ?`,
1074
- [...entityScope.params, queryVec.length]
1074
+ [...mismatchScope.params, queryVec.length]
1075
1075
  );
1076
1076
  if (mismatchedCount && mismatchedCount.cnt > 0) {
1077
1077
  throw new Error(
@@ -1131,16 +1131,16 @@ After running the migration SQL, restart your application.`
1131
1131
  }
1132
1132
  } else {
1133
1133
  if (useRanker) {
1134
- const entityScope2 = this._entityInClause(scoredEntityIds);
1134
+ const entityScope = this._entityInClause(scoredEntityIds);
1135
1135
  candidateRows = await this.db.getAllAsync(
1136
- `SELECT id, entity_id, updated_at, access_count FROM ${this.prefix}entries WHERE ${entityScope2.clause} AND deleted_at IS NULL`,
1137
- entityScope2.params
1136
+ `SELECT id, entity_id, updated_at, access_count FROM ${this.prefix}entries WHERE ${entityScope.clause} AND deleted_at IS NULL`,
1137
+ entityScope.params
1138
1138
  );
1139
1139
  } else {
1140
- const entityScope2 = this._entityInClause(scoredEntityIds);
1140
+ const entityScope = this._entityInClause(scoredEntityIds);
1141
1141
  candidateRows = await this.db.getAllAsync(
1142
- `SELECT id, entity_id, embedding_blob, embedding, updated_at, access_count FROM ${this.prefix}entries WHERE ${entityScope2.clause} AND deleted_at IS NULL`,
1143
- entityScope2.params
1142
+ `SELECT id, entity_id, embedding_blob, embedding, updated_at, access_count FROM ${this.prefix}entries WHERE ${entityScope.clause} AND deleted_at IS NULL`,
1143
+ entityScope.params
1144
1144
  );
1145
1145
  }
1146
1146
  if (weight !== void 0 && weight < 1) {
@@ -1159,32 +1159,42 @@ After running the migration SQL, restart your application.`
1159
1159
  const entityCacheKey = entityIds.length === 1 ? entityIds[0] : entityIds.join("\0");
1160
1160
  let scored;
1161
1161
  if (useRanker) {
1162
- const candidateIds = entityIds.length > 1 || effectivePreFilterLimit !== void 0 ? candidateRows.map((r) => r.id) : void 0;
1162
+ const candidateRowsByEntity = /* @__PURE__ */ new Map();
1163
+ for (const row of candidateRows) {
1164
+ const rows = candidateRowsByEntity.get(row.entity_id) ?? [];
1165
+ rows.push(row);
1166
+ candidateRowsByEntity.set(row.entity_id, rows);
1167
+ }
1163
1168
  try {
1164
- const oversampledLimit = Math.max(maxResults * 2, maxResults + 50);
1165
- scored = await this._rankWithVectorRanker({
1166
- entityId: entityCacheKey,
1167
- queryVec,
1168
- candidateIds,
1169
- candidateRows,
1170
- weight,
1171
- miniSearchScores,
1172
- limit: oversampledLimit
1173
- });
1174
- if (scored.length > 0) {
1175
- const scoredIds2 = new Set(scored.map((s) => s.id));
1176
- const metaMap = /* @__PURE__ */ new Map();
1177
- for (const r of candidateRows) {
1178
- if (scoredIds2.has(r.id)) {
1179
- metaMap.set(r.id, { updated_at: r.updated_at, access_count: r.access_count });
1180
- }
1181
- }
1182
- scored = scored.map((s) => {
1183
- const meta = metaMap.get(s.id);
1184
- return { ...s, updated_at: meta?.updated_at ?? null, access_count: meta?.access_count ?? null };
1185
- });
1186
- }
1169
+ const rankerResultsByEntity = await Promise.all(
1170
+ scoredEntityIds.filter((id) => (candidateRowsByEntity.get(id)?.length ?? 0) > 0).map(async (scopedEntityId) => {
1171
+ const rowsForEntity = candidateRowsByEntity.get(scopedEntityId) ?? [];
1172
+ const candidateIds = effectivePreFilterLimit !== void 0 ? rowsForEntity.map((row) => row.id) : void 0;
1173
+ const ranked = await this._rankWithVectorRanker({
1174
+ entityId: scopedEntityId,
1175
+ queryVec,
1176
+ candidateIds,
1177
+ candidateRows: rowsForEntity,
1178
+ weight,
1179
+ miniSearchScores,
1180
+ limit: Math.max(maxResults * 2, maxResults + 50)
1181
+ });
1182
+ return ranked.map((row) => ({ ...row, entity_id: scopedEntityId }));
1183
+ })
1184
+ );
1185
+ scored = rankerResultsByEntity.flat();
1187
1186
  const scoredIds = new Set(scored.map((s) => s.id));
1187
+ const metadataById = new Map(
1188
+ candidateRows.filter((row) => scoredIds.has(row.id)).map((row) => [row.id, row])
1189
+ );
1190
+ scored = scored.map((row) => {
1191
+ const metadata = metadataById.get(row.id);
1192
+ return {
1193
+ ...row,
1194
+ updated_at: metadata?.updated_at ?? null,
1195
+ access_count: metadata?.access_count ?? null
1196
+ };
1197
+ });
1188
1198
  const isHybrid = weight !== void 0 && weight < 1;
1189
1199
  const maxBackfill = isHybrid ? maxResults : Math.max(0, maxResults - scored.length);
1190
1200
  if (maxBackfill > 0) {
@@ -1332,21 +1342,17 @@ After running the migration SQL, restart your application.`
1332
1342
  });
1333
1343
  const keywordOversampledLimit = Math.max(maxResults * 2, maxResults + 50);
1334
1344
  const topResults = msResults.slice(0, keywordOversampledLimit);
1335
- const resultIds = new Set(topResults.map((r) => r.id));
1336
- const candidateMap = /* @__PURE__ */ new Map();
1337
- for (const r of candidateRows) {
1338
- if (resultIds.has(r.id)) {
1339
- candidateMap.set(r.id, { entity_id: r.entity_id, updated_at: r.updated_at, access_count: r.access_count });
1340
- }
1341
- }
1342
- scored = topResults.map((r) => {
1343
- const meta = candidateMap.get(r.id);
1345
+ const topResultIds = new Set(topResults.map((r) => r.id));
1346
+ const candidateMap = new Map(candidateRows.filter((r) => topResultIds.has(r.id)).map((row) => [row.id, row]));
1347
+ scored = topResults.map((result) => {
1348
+ const metadata = candidateMap.get(result.id);
1349
+ const entityForScore = metadata?.entity_id ?? result.entity_id ?? "";
1344
1350
  return {
1345
- id: r.id,
1346
- entity_id: meta?.entity_id ?? r.entity_id,
1347
- score: r.score ?? 0,
1348
- access_count: meta?.access_count ?? null,
1349
- updated_at: meta?.updated_at ?? null
1351
+ id: result.id,
1352
+ entity_id: entityForScore,
1353
+ score: result.score ?? 0,
1354
+ access_count: metadata?.access_count ?? null,
1355
+ updated_at: metadata?.updated_at ?? null
1350
1356
  };
1351
1357
  });
1352
1358
  } else {
@@ -2787,16 +2793,20 @@ function scoreFactFor(fact, weights, now) {
2787
2793
  const recencyDecay = Math.exp(-ageDays / 30);
2788
2794
  return confW * weights.confidence + Math.log(1 + fact.access_count) * weights.accessCount + recencyDecay * weights.recency;
2789
2795
  }
2790
- function renderFactMarkdown(fact, includeConfidence, includeTags) {
2796
+ function renderFactMarkdown(fact, includeConfidence, includeTags, includeEntityIds, score) {
2791
2797
  const confPart = includeConfidence ? ` (${fact.confidence})` : "";
2792
2798
  const tagPart = includeTags && fact.tags.length > 0 ? ` [${fact.tags.join(", ")}]` : "";
2793
- return `- **${fact.title}**${confPart}${tagPart}
2799
+ const sourcePart = includeEntityIds ? ` {entity_id=${fact.entity_id}}` : "";
2800
+ const scorePart = score !== void 0 ? ` {score=${score.toFixed(4)}}` : "";
2801
+ return `- **${fact.title}**${confPart}${tagPart}${sourcePart}${scorePart}
2794
2802
  ${fact.body.replace(/\n/g, "\n ")}`;
2795
2803
  }
2796
- function renderFactPlain(fact, includeConfidence, includeTags) {
2804
+ function renderFactPlain(fact, includeConfidence, includeTags, includeEntityIds, score) {
2797
2805
  const confPart = includeConfidence ? ` (${fact.confidence})` : "";
2798
2806
  const tagPart = includeTags && fact.tags.length > 0 ? ` [${fact.tags.join(", ")}]` : "";
2799
- return `${fact.title}${confPart}${tagPart}: ${fact.body}`;
2807
+ const sourcePart = includeEntityIds ? ` {entity_id=${fact.entity_id}}` : "";
2808
+ const scorePart = score !== void 0 ? ` {score=${score.toFixed(4)}}` : "";
2809
+ return `${fact.title}${confPart}${tagPart}${sourcePart}${scorePart}: ${fact.body}`;
2800
2810
  }
2801
2811
  function renderTaskMarkdown(task) {
2802
2812
  return `- [P${task.priority}] ${task.description.replace(/\n/g, "\n ")} (${task.status})`;
@@ -2820,6 +2830,8 @@ function formatContext(bundle, options) {
2820
2830
  maxEvents: options?.maxEvents ?? 10,
2821
2831
  includeConfidence: options?.includeConfidence ?? true,
2822
2832
  includeTags: options?.includeTags ?? true,
2833
+ includeEntityIds: options?.includeEntityIds ?? false,
2834
+ includeFactScores: options?.includeFactScores ?? false,
2823
2835
  factWeights: {
2824
2836
  confidence: options?.factWeights?.confidence ?? 1,
2825
2837
  accessCount: options?.factWeights?.accessCount ?? 0.3,
@@ -2831,7 +2843,7 @@ function formatContext(bundle, options) {
2831
2843
  validateMaxOption(opts.maxEvents, "maxEvents");
2832
2844
  const weights = opts.factWeights;
2833
2845
  const now = Date.now();
2834
- const sortedFacts = [...bundle.facts].sort((a, b) => scoreFactFor(b, weights, now) - scoreFactFor(a, weights, now)).slice(0, opts.maxFacts);
2846
+ const sortedFacts = bundle.factScores ? [...bundle.facts].slice(0, opts.maxFacts) : [...bundle.facts].sort((a, b) => scoreFactFor(b, weights, now) - scoreFactFor(a, weights, now)).slice(0, opts.maxFacts);
2835
2847
  const sortedTasks = [...bundle.tasks].sort((a, b) => b.priority - a.priority || a.created_at - b.created_at).slice(0, opts.maxTasks);
2836
2848
  const sortedEvents = [...bundle.events].sort((a, b) => b.created_at - a.created_at).slice(0, opts.maxEvents);
2837
2849
  if (sortedFacts.length === 0 && sortedTasks.length === 0 && sortedEvents.length === 0) {
@@ -2845,7 +2857,7 @@ function formatContext(bundle, options) {
2845
2857
  lines.push("");
2846
2858
  lines.push("### Known Facts");
2847
2859
  for (const fact of sortedFacts) {
2848
- lines.push(renderFactMarkdown(fact, opts.includeConfidence, opts.includeTags));
2860
+ lines.push(renderFactMarkdown(fact, opts.includeConfidence, opts.includeTags, opts.includeEntityIds, opts.includeFactScores ? bundle.factScores?.[fact.id] : void 0));
2849
2861
  }
2850
2862
  }
2851
2863
  if (sortedTasks.length > 0) {
@@ -2866,7 +2878,7 @@ function formatContext(bundle, options) {
2866
2878
  if (sortedFacts.length > 0) {
2867
2879
  lines.push("KNOWN FACTS:");
2868
2880
  for (const fact of sortedFacts) {
2869
- lines.push(renderFactPlain(fact, opts.includeConfidence, opts.includeTags));
2881
+ lines.push(renderFactPlain(fact, opts.includeConfidence, opts.includeTags, opts.includeEntityIds, opts.includeFactScores ? bundle.factScores?.[fact.id] : void 0));
2870
2882
  }
2871
2883
  }
2872
2884
  if (sortedTasks.length > 0) {
@@ -2985,17 +2997,60 @@ function formatMemoryDump(dump) {
2985
2997
  };
2986
2998
  }
2987
2999
 
3000
+ // src/librarianPrompt.ts
3001
+ var DEFAULT_LIBRARIAN_SYNTHESIS_PROMPT = `You are a careful memory synthesis assistant.
3002
+ Use only the retrieved context when answering the request.
3003
+ Preserve source provenance when facts come from different entity namespaces.
3004
+
3005
+ Request:
3006
+ {{query}}
3007
+
3008
+ Retrieved context:
3009
+ {{context}}
3010
+
3011
+ Open tasks:
3012
+ {{tasks}}`;
3013
+ function hydrateLibrarianPrompt(template, variables) {
3014
+ return template.replace(/\{\{(context|tasks|query)\}\}/g, (_, key) => variables[key]);
3015
+ }
3016
+ function validateLibrarianPromptTemplate(template, options) {
3017
+ if (!options.custom) return [];
3018
+ const warnings = [];
3019
+ if (!template.includes("{{context}}")) {
3020
+ warnings.push("Custom Librarian systemPrompt omits {{context}}; retrieved memory will not be injected.");
3021
+ }
3022
+ if (!template.includes("{{query}}")) {
3023
+ warnings.push("Custom Librarian systemPrompt omits {{query}}; the original request will not be injected.");
3024
+ }
3025
+ if (options.taskCount > 0 && !template.includes("{{tasks}}")) {
3026
+ warnings.push("Custom Librarian systemPrompt omits {{tasks}} while retrieved tasks are available.");
3027
+ }
3028
+ return warnings;
3029
+ }
3030
+ function mapLibrarianOptionsToReadOptions(options) {
3031
+ const readOptions = {};
3032
+ if (options.entityWeights !== void 0) readOptions.tierWeights = options.entityWeights;
3033
+ if (options.includeZeroWeightEntities !== void 0) {
3034
+ readOptions.includeZeroWeightEntities = options.includeZeroWeightEntities;
3035
+ }
3036
+ return readOptions;
3037
+ }
3038
+
2988
3039
  // src/index.ts
2989
3040
  function createWiki(db, options) {
2990
3041
  return new WikiMemory(db, options);
2991
3042
  }
2992
3043
 
3044
+ exports.DEFAULT_LIBRARIAN_SYNTHESIS_PROMPT = DEFAULT_LIBRARIAN_SYNTHESIS_PROMPT;
2993
3045
  exports.PrunePartialFailureError = PrunePartialFailureError;
2994
3046
  exports.WikiBusyError = WikiBusyError;
2995
3047
  exports.WikiMemory = WikiMemory;
2996
3048
  exports.createWiki = createWiki;
2997
3049
  exports.formatContext = formatContext;
2998
3050
  exports.formatMemoryDump = formatMemoryDump;
3051
+ exports.hydrateLibrarianPrompt = hydrateLibrarianPrompt;
3052
+ exports.mapLibrarianOptionsToReadOptions = mapLibrarianOptionsToReadOptions;
2999
3053
  exports.parseEmbedding = parseEmbedding;
3054
+ exports.validateLibrarianPromptTemplate = validateLibrarianPromptTemplate;
3000
3055
  //# sourceMappingURL=index.js.map
3001
3056
  //# sourceMappingURL=index.js.map