entroly-wasm 1.0.23 → 1.0.25

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/js/server.js CHANGED
@@ -4,7 +4,7 @@
4
4
  //
5
5
  // Architecture: MCP Client → JSON-RPC (stdio) → Node.js → Wasm Engine → Results
6
6
 
7
- const { WasmEntrolyEngine } = require('../pkg/entroly_wasm');
7
+ const { WasmEntrolyEngine, qccr_select } = require('../pkg/entroly_wasm');
8
8
  const { EntrolyConfig } = require('./config');
9
9
  const { CheckpointManager, persistIndex, loadIndex } = require('./checkpoint');
10
10
  const { autoIndex, startIncrementalWatcher } = require('./auto_index');
@@ -226,7 +226,35 @@ class EntrolyMCPServer {
226
226
  const budget = args.token_budget || this.config.defaultTokenBudget;
227
227
  const query = args.query || '';
228
228
  const profile = this.taskProfiles.applyToEngine(this.engine, query);
229
- const result = this.engine.optimize(budget, query);
229
+ // ── Query-conditioned selection via QCCR (Rust SSOT) ──
230
+ // Routes npm's optimize_context through the SAME ranking + sentence
231
+ // selection as pip/MCP/SDK (the shared entroly-qccr crate). Any failure
232
+ // falls back to the native knapsack so optimize never breaks.
233
+ let result;
234
+ if (query.trim()) {
235
+ try {
236
+ const candidates = this.engine.export_fragments();
237
+ const slim = JSON.stringify(candidates.map(f => ({ source: f.source || '', content: f.content || '' })));
238
+ const selected = JSON.parse(qccr_select(slim, budget, query, '{}', '[]'));
239
+ const tok = (f) => f.token_count || Math.floor(((f.content || '').length) / 4);
240
+ const tokensUsed = selected.reduce((a, f) => a + tok(f), 0);
241
+ const totalInput = candidates.reduce((a, f) => a + tok(f), 0);
242
+ result = {
243
+ selected_fragments: selected,
244
+ selected,
245
+ selected_count: selected.length,
246
+ tokens_used: tokensUsed,
247
+ tokens_saved: Math.max(0, totalInput - tokensUsed),
248
+ total_fragments: candidates.length,
249
+ selector: 'qccr',
250
+ };
251
+ } catch (_) {
252
+ result = this.engine.optimize(budget, query);
253
+ result.selector = 'knapsack_fallback';
254
+ }
255
+ } else {
256
+ result = this.engine.optimize(budget, query);
257
+ }
230
258
  result._taskProfile = { taskType: profile.taskType, confidence: profile.confidence };
231
259
  // Record value to the shared sink (mirrors entroly/server.py).
232
260
  try {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "entroly-wasm",
3
- "version": "1.0.23",
3
+ "version": "1.0.25",
4
4
  "description": "Auditable context control plane for AI agents: context receipts, local optimization, MCP, and app SDK helpers. Pure WebAssembly, no Python dependency.",
5
5
  "main": "index.js",
6
6
  "types": "index.d.ts",
@@ -207,4 +207,21 @@ export function classify_query_transition(prev_hash: bigint, current_query: stri
207
207
 
208
208
  export function optimize_task_profiles(episodes_json: string): any;
209
209
 
210
+ /**
211
+ * Expand a query into its retrieval vocabulary; returns a sorted JSON array.
212
+ */
213
+ export function qccr_expand_query(query: string): string;
214
+
215
+ /**
216
+ * Rank files; returns a JSON array of `[index, score]` pairs, best-first.
217
+ */
218
+ export function qccr_rank_files(sources: string[], texts: string[], query: string, overrides_json: string): string;
219
+
220
+ /**
221
+ * Full QCCR selection (rank + sentence-MMR + emit + trim). `fragments_json`
222
+ * is a JSON array of `{source, content}`; `preferred_json` is the optional
223
+ * file order (or "[]"); returns a JSON array of selected fragments.
224
+ */
225
+ export function qccr_select(fragments_json: string, token_budget: number, query: string, overrides_json: string, preferred_json: string): string;
226
+
210
227
  export function reward_weighted_optimize(episodes_json: string, current_weights_json: string): any;
@@ -488,6 +488,90 @@ function optimize_task_profiles(episodes_json) {
488
488
  }
489
489
  exports.optimize_task_profiles = optimize_task_profiles;
490
490
 
491
+ /**
492
+ * Expand a query into its retrieval vocabulary; returns a sorted JSON array.
493
+ * @param {string} query
494
+ * @returns {string}
495
+ */
496
+ function qccr_expand_query(query) {
497
+ let deferred2_0;
498
+ let deferred2_1;
499
+ try {
500
+ const ptr0 = passStringToWasm0(query, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
501
+ const len0 = WASM_VECTOR_LEN;
502
+ const ret = wasm.qccr_expand_query(ptr0, len0);
503
+ deferred2_0 = ret[0];
504
+ deferred2_1 = ret[1];
505
+ return getStringFromWasm0(ret[0], ret[1]);
506
+ } finally {
507
+ wasm.__wbindgen_free(deferred2_0, deferred2_1, 1);
508
+ }
509
+ }
510
+ exports.qccr_expand_query = qccr_expand_query;
511
+
512
+ /**
513
+ * Rank files; returns a JSON array of `[index, score]` pairs, best-first.
514
+ * @param {string[]} sources
515
+ * @param {string[]} texts
516
+ * @param {string} query
517
+ * @param {string} overrides_json
518
+ * @returns {string}
519
+ */
520
+ function qccr_rank_files(sources, texts, query, overrides_json) {
521
+ let deferred5_0;
522
+ let deferred5_1;
523
+ try {
524
+ const ptr0 = passArrayJsValueToWasm0(sources, wasm.__wbindgen_malloc);
525
+ const len0 = WASM_VECTOR_LEN;
526
+ const ptr1 = passArrayJsValueToWasm0(texts, wasm.__wbindgen_malloc);
527
+ const len1 = WASM_VECTOR_LEN;
528
+ const ptr2 = passStringToWasm0(query, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
529
+ const len2 = WASM_VECTOR_LEN;
530
+ const ptr3 = passStringToWasm0(overrides_json, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
531
+ const len3 = WASM_VECTOR_LEN;
532
+ const ret = wasm.qccr_rank_files(ptr0, len0, ptr1, len1, ptr2, len2, ptr3, len3);
533
+ deferred5_0 = ret[0];
534
+ deferred5_1 = ret[1];
535
+ return getStringFromWasm0(ret[0], ret[1]);
536
+ } finally {
537
+ wasm.__wbindgen_free(deferred5_0, deferred5_1, 1);
538
+ }
539
+ }
540
+ exports.qccr_rank_files = qccr_rank_files;
541
+
542
+ /**
543
+ * Full QCCR selection (rank + sentence-MMR + emit + trim). `fragments_json`
544
+ * is a JSON array of `{source, content}`; `preferred_json` is the optional
545
+ * file order (or "[]"); returns a JSON array of selected fragments.
546
+ * @param {string} fragments_json
547
+ * @param {number} token_budget
548
+ * @param {string} query
549
+ * @param {string} overrides_json
550
+ * @param {string} preferred_json
551
+ * @returns {string}
552
+ */
553
+ function qccr_select(fragments_json, token_budget, query, overrides_json, preferred_json) {
554
+ let deferred5_0;
555
+ let deferred5_1;
556
+ try {
557
+ const ptr0 = passStringToWasm0(fragments_json, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
558
+ const len0 = WASM_VECTOR_LEN;
559
+ const ptr1 = passStringToWasm0(query, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
560
+ const len1 = WASM_VECTOR_LEN;
561
+ const ptr2 = passStringToWasm0(overrides_json, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
562
+ const len2 = WASM_VECTOR_LEN;
563
+ const ptr3 = passStringToWasm0(preferred_json, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
564
+ const len3 = WASM_VECTOR_LEN;
565
+ const ret = wasm.qccr_select(ptr0, len0, token_budget, ptr1, len1, ptr2, len2, ptr3, len3);
566
+ deferred5_0 = ret[0];
567
+ deferred5_1 = ret[1];
568
+ return getStringFromWasm0(ret[0], ret[1]);
569
+ } finally {
570
+ wasm.__wbindgen_free(deferred5_0, deferred5_1, 1);
571
+ }
572
+ }
573
+ exports.qccr_select = qccr_select;
574
+
491
575
  /**
492
576
  * @param {string} episodes_json
493
577
  * @param {string} current_weights_json
@@ -509,6 +593,14 @@ exports.reward_weighted_optimize = reward_weighted_optimize;
509
593
  function __wbg_get_imports() {
510
594
  const import0 = {
511
595
  __proto__: null,
596
+ __wbg___wbindgen_string_get_914df97fcfa788f2: function(arg0, arg1) {
597
+ const obj = arg1;
598
+ const ret = typeof(obj) === 'string' ? obj : undefined;
599
+ var ptr1 = isLikeNone(ret) ? 0 : passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
600
+ var len1 = WASM_VECTOR_LEN;
601
+ getDataViewMemory0().setInt32(arg0 + 4 * 1, len1, true);
602
+ getDataViewMemory0().setInt32(arg0 + 4 * 0, ptr1, true);
603
+ },
512
604
  __wbg___wbindgen_throw_81fc77679af83bc6: function(arg0, arg1) {
513
605
  throw new Error(getStringFromWasm0(arg0, arg1));
514
606
  },
@@ -547,6 +639,14 @@ function addToExternrefTable0(obj) {
547
639
  return idx;
548
640
  }
549
641
 
642
+ let cachedDataViewMemory0 = null;
643
+ function getDataViewMemory0() {
644
+ if (cachedDataViewMemory0 === null || cachedDataViewMemory0.buffer.detached === true || (cachedDataViewMemory0.buffer.detached === undefined && cachedDataViewMemory0.buffer !== wasm.memory.buffer)) {
645
+ cachedDataViewMemory0 = new DataView(wasm.memory.buffer);
646
+ }
647
+ return cachedDataViewMemory0;
648
+ }
649
+
550
650
  function getStringFromWasm0(ptr, len) {
551
651
  ptr = ptr >>> 0;
552
652
  return decodeText(ptr, len);
@@ -569,6 +669,20 @@ function handleError(f, args) {
569
669
  }
570
670
  }
571
671
 
672
+ function isLikeNone(x) {
673
+ return x === undefined || x === null;
674
+ }
675
+
676
+ function passArrayJsValueToWasm0(array, malloc) {
677
+ const ptr = malloc(array.length * 4, 4) >>> 0;
678
+ for (let i = 0; i < array.length; i++) {
679
+ const add = addToExternrefTable0(array[i]);
680
+ getDataViewMemory0().setUint32(ptr + 4 * i, add, true);
681
+ }
682
+ WASM_VECTOR_LEN = array.length;
683
+ return ptr;
684
+ }
685
+
572
686
  function passStringToWasm0(arg, malloc, realloc) {
573
687
  if (realloc === undefined) {
574
688
  const buf = cachedTextEncoder.encode(arg);
Binary file