thumbgate 1.34.3 → 1.37.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.agents/skills/cyberstrike-compare-not-clone/SKILL.md +36 -0
- package/.agents/skills/gitlab-sandbox-allowlist-not-trust/SKILL.md +77 -0
- package/.agents/skills/jit-harness-compare-not-clone/SKILL.md +34 -0
- package/.agents/skills/openui-catalog-compose-honesty/SKILL.md +64 -0
- package/.agents/skills/zvec-grep-compare-not-clone/SKILL.md +34 -0
- package/.claude-plugin/plugin.json +1 -1
- package/.well-known/llms.txt +1 -0
- package/.well-known/mcp/server-card.json +1 -1
- package/CONTRIBUTING.md +95 -0
- package/README.md +195 -632
- package/THIRD_PARTY_NOTICES.md +89 -0
- package/adapters/claude/.mcp.json +2 -2
- package/adapters/forge/forge.yaml +3 -3
- package/adapters/future-agi/.mcp.json +8 -0
- package/adapters/future-agi/FUTURE_AGI.md +23 -0
- package/adapters/future-agi/config.toml +3 -0
- package/adapters/future-agi/future-agi-bridge.js +9 -0
- package/adapters/future-agi/opencode.json +8 -0
- package/adapters/herdr/herdr-plugin.toml +18 -0
- package/adapters/mcp/server-stdio.js +238 -25
- package/adapters/opencode/opencode.json +1 -1
- package/adapters/workos/WORKOS.md +52 -0
- package/bin/cli.js +373 -5
- package/bin/futureagi-bridge +9 -0
- package/config/gate-templates.json +653 -4
- package/config/gates/actor-critic-audit.json +34 -0
- package/config/gates/default.json +21 -2
- package/config/gates/five-walls-governance.json +34 -0
- package/config/gates/future-agi-guardrails.json +34 -0
- package/config/gates/radware-threat-defense-2026.json +61 -0
- package/config/gates/simatree-data-governance.json +33 -0
- package/config/mcp-allowlists.json +4 -0
- package/config/merge-quality-checks.json +10 -1
- package/config/model-candidates.json +382 -24
- package/config/model-tiers.json +18 -0
- package/config/post-deploy-marketing-pages.json +10 -0
- package/config/progressive/01-wire-only.json +11 -0
- package/config/progressive/02-dashboard-empty-ok.json +10 -0
- package/config/progressive/03-one-lesson.json +10 -0
- package/config/progressive/04-warn-fires.json +11 -0
- package/config/progressive/05-strict-optional.json +11 -0
- package/config/progressive/README.md +15 -0
- package/config/schemas/broker-execution-receipt.schema.json +139 -0
- package/config/schemas/provider-execution-attestation-v1.schema.json +58 -0
- package/conformance/provider-attestation/vectors.json +320 -0
- package/docs/specs/provider-execution-attestation-v1.md +69 -0
- package/openapi/openapi.yaml +15 -0
- package/package.json +401 -147
- package/public/about.html +2 -2
- package/public/ai-malpractice-prevention.html +7 -7
- package/public/blog/a-10-dollar-vps-is-not-a-computer.html +143 -0
- package/public/blog/a-receipt-is-not-world-state.html +388 -0
- package/public/blog/git-at-agent-scale.html +374 -0
- package/public/blog/no-llm-in-the-gate.html +133 -0
- package/public/blog.html +80 -0
- package/public/case-studies.html +16 -1
- package/public/compare.html +28 -0
- package/public/diagnostic.html +216 -7
- package/public/docs/connectors.html +39 -0
- package/public/federal.html +2 -2
- package/public/founders.html +639 -0
- package/public/index.html +87 -9
- package/public/install.html +8 -8
- package/public/learn.html +39 -0
- package/public/numbers.html +2 -2
- package/public/peter.html +310 -0
- package/public/platform-partners.html +119 -0
- package/public/pricing.html +24 -3
- package/public/privacy.html +117 -0
- package/public/pro.html +17 -0
- package/public/support.html +62 -0
- package/public/terms.html +130 -0
- package/public/third-party-notices.html +95 -0
- package/public/yt.html +351 -0
- package/scripts/action-receipts.js +133 -3
- package/scripts/adaptive-governance-arena.js +349 -0
- package/scripts/admin-override.js +205 -0
- package/scripts/agent-action-inventory.js +869 -0
- package/scripts/agent-audit-trace.js +42 -2
- package/scripts/agent-egress-policy.js +1117 -0
- package/scripts/agent-memory-lifecycle.js +141 -2
- package/scripts/agent-operations-planner.js +441 -1
- package/scripts/agent-readiness.js +68 -0
- package/scripts/agent-security-central.js +647 -0
- package/scripts/allowlist-bridge-honesty.js +417 -0
- package/scripts/async-job-runner.js +102 -11
- package/scripts/audit-trail.js +212 -0
- package/scripts/auto-promote-gates.js +178 -27
- package/scripts/billing.js +1 -1
- package/scripts/broker-execution-receipts.js +719 -0
- package/scripts/budget-aware-gates-proof.js +423 -0
- package/scripts/claude-feedback-sync.js +29 -3
- package/scripts/claw-harness-production.js +237 -0
- package/scripts/cli-progress.js +111 -0
- package/scripts/cli-schema.js +163 -1
- package/scripts/codex-runbook-flywheel.js +318 -0
- package/scripts/context-footprint.js +186 -0
- package/scripts/contextfs.js +143 -61
- package/scripts/dashboard-limits.js +27 -0
- package/scripts/dashboard.js +279 -9
- package/scripts/deepseek-v4-runtime-guardrails.js +72 -6
- package/scripts/docker-sandbox-planner.js +18 -0
- package/scripts/double-blind-eval-protocol.js +252 -0
- package/scripts/edotenv-rl-gateway.js +259 -0
- package/scripts/ensure-production-search-corpus.js +162 -0
- package/scripts/eval-holdout.js +311 -0
- package/scripts/feedback-aggregate.js +21 -2
- package/scripts/feedback-loop.js +87 -5
- package/scripts/feedback-quality.js +9 -0
- package/scripts/file-ledger-lock.js +4 -1
- package/scripts/financial-control-plane.js +41 -1
- package/scripts/find-dormant-requires.js +118 -0
- package/scripts/fs-utils.js +84 -8
- package/scripts/gate-stats.js +2 -2
- package/scripts/gates-engine.js +859 -58
- package/scripts/generate-case-study-outreach.js +24 -15
- package/scripts/git-at-scale.js +628 -0
- package/scripts/governance-conflict-audit.js +1650 -0
- package/scripts/governance-difficulty-curriculum.js +328 -0
- package/scripts/graphrag-retrieval.js +275 -0
- package/scripts/gurobi-optimizer.js +324 -0
- package/scripts/gurobi_optimizer.py +485 -0
- package/scripts/harness-selector.js +82 -1
- package/scripts/hidden-entry-points.js +284 -0
- package/scripts/human-escalation.js +199 -1
- package/scripts/hybrid-feedback-context.js +152 -19
- package/scripts/intent-governed-execution.js +602 -0
- package/scripts/intervention-policy.js +123 -20
- package/scripts/jit-harness-compose.js +628 -0
- package/scripts/jsonl-watcher.js +10 -0
- package/scripts/lesson-embedding-index.js +95 -12
- package/scripts/lesson-retrieval.js +105 -19
- package/scripts/local-model-profile.js +19 -2
- package/scripts/mailer/resend-mailer.js +1 -1
- package/scripts/matryoshka-embedding.js +235 -0
- package/scripts/mcp-oauth.js +42 -4
- package/scripts/mcp-session-handles.js +1016 -0
- package/scripts/mcp-wiring-doctor.js +314 -0
- package/scripts/memory-firewall.js +115 -2
- package/scripts/memory-scope-readiness.js +299 -0
- package/scripts/memory-vs-rag-route.js +161 -0
- package/scripts/model-tier-router.js +148 -21
- package/scripts/nvidia-specdecode-al-doctor.js +536 -0
- package/scripts/openui-catalog-compose-honesty.js +593 -0
- package/scripts/operational-integrity.js +19 -1
- package/scripts/override-audit.js +213 -0
- package/scripts/package-manager-honesty-doctor.js +458 -0
- package/scripts/pr-manager.js +63 -1
- package/scripts/prove-herdr-adapter.js +52 -0
- package/scripts/prove-memory-pyramid-and-symbolic-canvas.js +95 -0
- package/scripts/prove-workos.js +73 -0
- package/scripts/provider-attestation-conformance.js +192 -0
- package/scripts/provider-receipt-contract.js +136 -0
- package/scripts/qwen38-max-cost-optimizer.js +401 -0
- package/scripts/radware-threat-defense.js +280 -0
- package/scripts/rag-embedding-identity.js +221 -0
- package/scripts/rag-precision-guardrails.js +112 -2
- package/scripts/remote-feedback-capture.js +159 -0
- package/scripts/research-agent-harness.js +256 -0
- package/scripts/rsi-safety-hillclimb.js +200 -0
- package/scripts/rule-sprawl.js +188 -0
- package/scripts/schedule-manager.js +147 -0
- package/scripts/self-heal.js +8 -0
- package/scripts/session-lease.js +415 -0
- package/scripts/simatree-data-governance.js +347 -0
- package/scripts/slo-alert-engine.js +172 -7
- package/scripts/solver-parity.js +539 -0
- package/scripts/stealth-memory-injection-gate.js +333 -0
- package/scripts/switchyard-router.js +366 -0
- package/scripts/telemetry-analytics.js +84 -27
- package/scripts/temporal-decay-weighting.js +138 -0
- package/scripts/test-all.js +165 -0
- package/scripts/token-savings.js +42 -0
- package/scripts/tool-kpi-tracker.js +108 -5
- package/scripts/tool-registry.js +193 -5
- package/scripts/universal-claim-evaluator.js +14 -2
- package/scripts/vector-store.js +279 -9
- package/scripts/workflow-notebook.js +391 -0
- package/scripts/workflow-sentinel.js +111 -12
- package/scripts/workos-production-guard.js +260 -0
- package/scripts/workspace-search-route.js +515 -0
- package/server.json +2 -2
- package/src/agent-identity-boundary.js +76 -0
- package/src/agent-retrieval-cache.js +155 -0
- package/src/alert-noise-ledger.js +502 -0
- package/src/api/server.js +802 -185
- package/src/git-fast-cache.js +220 -0
- package/src/git-wal-sync.js +156 -0
- package/src/hash-anchored-edit.js +82 -0
- package/src/hermes-platform-protocol.js +475 -0
- package/src/hermes-sync-plane.js +241 -0
- package/src/index.js +30 -1
- package/src/iso42001-compliance-guard.js +97 -0
- package/src/latency-budget.js +244 -0
- package/src/mcp-writeguard.js +316 -0
- package/src/miminions-adapter.js +106 -0
- package/src/pipeline-compass.js +104 -0
- package/src/ppl-alert-pipeline.js +284 -0
- package/src/rendezvous-router.js +90 -0
- package/src/security-questionnaire.js +195 -0
package/scripts/contextfs.js
CHANGED
|
@@ -100,7 +100,10 @@ const PACK_TEMPLATES = {
|
|
|
100
100
|
},
|
|
101
101
|
};
|
|
102
102
|
|
|
103
|
-
|
|
103
|
+
const CONTEXT_ENVELOPE_VERSION = 'six-block-v1';
|
|
104
|
+
const CONTEXT_ENVELOPE_KEYS = [
|
|
105
|
+
'goal', 'businessData', 'examples', 'procedures', 'constraints', 'rubric',
|
|
106
|
+
];
|
|
104
107
|
function ensureContextFs() {
|
|
105
108
|
Object.values(NAMESPACES).forEach((subPath) => {
|
|
106
109
|
ensureDir(contextFsPath(subPath));
|
|
@@ -178,12 +181,15 @@ function querySimilarity(tokensA, tokensB) {
|
|
|
178
181
|
return union === 0 ? 0 : intersection / union;
|
|
179
182
|
}
|
|
180
183
|
|
|
181
|
-
function buildSemanticCacheKey({ namespaces, maxItems, maxChars }) {
|
|
184
|
+
function buildSemanticCacheKey({ namespaces, maxItems, maxChars, strategy = 'auto', contextEnvelope = null }) {
|
|
182
185
|
return JSON.stringify({
|
|
183
186
|
retrievalVersion: CONTEXTFS_RETRIEVAL_VERSION,
|
|
184
187
|
namespaces: normalizeNamespaces(namespaces),
|
|
185
188
|
maxItems,
|
|
186
189
|
maxChars,
|
|
190
|
+
strategy,
|
|
191
|
+
contextEnvelopeHash: contextEnvelope ? crypto.createHash('sha256')
|
|
192
|
+
.update(JSON.stringify(contextEnvelope)).digest('hex') : null,
|
|
187
193
|
});
|
|
188
194
|
}
|
|
189
195
|
|
|
@@ -223,16 +229,14 @@ function getSourceHash(namespaces) {
|
|
|
223
229
|
try {
|
|
224
230
|
const stats = fs.statSync(filePath);
|
|
225
231
|
hasher.update(`${file}:${stats.mtimeMs}:${stats.size}`);
|
|
226
|
-
} catch {
|
|
227
|
-
// Skip if file disappeared
|
|
228
|
-
}
|
|
232
|
+
} catch { /* ignore */ }
|
|
229
233
|
}
|
|
230
234
|
}
|
|
231
235
|
}
|
|
232
236
|
return hasher.digest('hex');
|
|
233
237
|
}
|
|
234
238
|
|
|
235
|
-
function findSemanticCacheHit({ query, namespaces, maxItems, maxChars }) {
|
|
239
|
+
function findSemanticCacheHit({ query, namespaces, maxItems, maxChars, strategy = 'auto', contextEnvelope = null }) {
|
|
236
240
|
const { enabled, threshold, ttlSeconds } = getSemanticCacheConfig();
|
|
237
241
|
if (!enabled) return null;
|
|
238
242
|
|
|
@@ -241,14 +245,13 @@ function findSemanticCacheHit({ query, namespaces, maxItems, maxChars }) {
|
|
|
241
245
|
|
|
242
246
|
const now = Date.now();
|
|
243
247
|
const queryTokens = tokenizeQuery(query);
|
|
244
|
-
const key = buildSemanticCacheKey({ namespaces, maxItems, maxChars });
|
|
248
|
+
const key = buildSemanticCacheKey({ namespaces, maxItems, maxChars, strategy, contextEnvelope });
|
|
245
249
|
const currentSourceHash = getSourceHash(namespaces);
|
|
246
250
|
|
|
247
251
|
for (let i = entries.length - 1; i >= 0; i -= 1) {
|
|
248
252
|
const entry = entries[i];
|
|
249
253
|
if (!entry || entry.key !== key || !entry.pack) continue;
|
|
250
254
|
|
|
251
|
-
// Zero-Waste Caching: validate source hash
|
|
252
255
|
if (entry.sourceHash !== currentSourceHash) {
|
|
253
256
|
continue;
|
|
254
257
|
}
|
|
@@ -343,6 +346,86 @@ function normalizeTagList(tags) {
|
|
|
343
346
|
: [];
|
|
344
347
|
}
|
|
345
348
|
|
|
349
|
+
function invalidContextEnvelope(message) {
|
|
350
|
+
return Object.assign(new Error(message), { code: 'INVALID_CONTEXT_ENVELOPE' });
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
function normalizeContextEnvelope(value) {
|
|
354
|
+
if (value == null) return null;
|
|
355
|
+
if (!value || typeof value !== 'object' || Array.isArray(value)) {
|
|
356
|
+
throw invalidContextEnvelope('contextEnvelope must be an object');
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
const unknownKeys = Object.keys(value).filter((key) => !CONTEXT_ENVELOPE_KEYS.includes(key));
|
|
360
|
+
if (unknownKeys.length > 0) {
|
|
361
|
+
throw invalidContextEnvelope(
|
|
362
|
+
`contextEnvelope contains unsupported blocks: ${unknownKeys.join(', ')}`,
|
|
363
|
+
);
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
const missingKeys = CONTEXT_ENVELOPE_KEYS.filter((key) => !Object.hasOwn(value, key));
|
|
367
|
+
if (missingKeys.length > 0) {
|
|
368
|
+
throw invalidContextEnvelope(
|
|
369
|
+
`contextEnvelope is missing required blocks: ${missingKeys.join(', ')}`,
|
|
370
|
+
);
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
const envelope = {
|
|
374
|
+
version: CONTEXT_ENVELOPE_VERSION,
|
|
375
|
+
};
|
|
376
|
+
for (const key of CONTEXT_ENVELOPE_KEYS) {
|
|
377
|
+
const items = key === 'goal' ? [value[key]] : value[key];
|
|
378
|
+
if (!Array.isArray(items)
|
|
379
|
+
|| items.length === 0
|
|
380
|
+
|| items.some((item) => (
|
|
381
|
+
typeof item !== 'string'
|
|
382
|
+
|| !item.trim()
|
|
383
|
+
))) {
|
|
384
|
+
throw invalidContextEnvelope(`contextEnvelope.${key} has invalid content`);
|
|
385
|
+
}
|
|
386
|
+
const normalized = items.map((item) => item.trim());
|
|
387
|
+
envelope[key] = key === 'goal' ? normalized[0] : normalized;
|
|
388
|
+
}
|
|
389
|
+
return envelope;
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
function measureContextEnvelopeChars(contextEnvelope) {
|
|
393
|
+
return contextEnvelope ? JSON.stringify(contextEnvelope).length : 0;
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
function getFreshness(observedAt, maxAgeSeconds, currentTimeMs) {
|
|
397
|
+
if (!observedAt) return 'unknown';
|
|
398
|
+
const observedAtMs = new Date(observedAt).getTime();
|
|
399
|
+
if (!Number.isFinite(observedAtMs)) return 'invalid';
|
|
400
|
+
if (observedAtMs > currentTimeMs + 300_000) return 'future';
|
|
401
|
+
if (!(Number.isFinite(maxAgeSeconds) && maxAgeSeconds > 0)) return 'unknown';
|
|
402
|
+
return currentTimeMs - observedAtMs <= maxAgeSeconds * 1000 ? 'fresh' : 'stale';
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
function buildItemProvenance(doc, currentTimeMs = Date.now()) {
|
|
406
|
+
const metadata = doc && typeof doc.metadata === 'object' ? doc.metadata : {};
|
|
407
|
+
const observedAtRaw = metadata.sourceUpdatedAt || doc.createdAt || null;
|
|
408
|
+
const observedAtMs = observedAtRaw ? new Date(observedAtRaw).getTime() : NaN;
|
|
409
|
+
const parsedMaxAge = Number(metadata.maxAgeSeconds);
|
|
410
|
+
const maxAgeSeconds = Number.isFinite(parsedMaxAge) && parsedMaxAge > 0 ? parsedMaxAge : null;
|
|
411
|
+
|
|
412
|
+
return {
|
|
413
|
+
source: doc.source || 'unknown',
|
|
414
|
+
sourceUrl: typeof metadata.sourceUrl === 'string' && metadata.sourceUrl.trim()
|
|
415
|
+
? metadata.sourceUrl.trim()
|
|
416
|
+
: null,
|
|
417
|
+
observedAt: Number.isFinite(observedAtMs) ? new Date(observedAtMs).toISOString() : null,
|
|
418
|
+
maxAgeSeconds,
|
|
419
|
+
freshness: getFreshness(observedAtRaw, maxAgeSeconds, currentTimeMs),
|
|
420
|
+
};
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
function refreshItemProvenance(provenance, currentTimeMs = Date.now()) {
|
|
424
|
+
if (!provenance) return provenance;
|
|
425
|
+
const freshness = getFreshness(provenance.observedAt, Number(provenance.maxAgeSeconds), currentTimeMs);
|
|
426
|
+
return { ...provenance, freshness };
|
|
427
|
+
}
|
|
428
|
+
|
|
346
429
|
function findExistingContextObject({ namespace, title, content, tags = [], source }) {
|
|
347
430
|
ensureContextFs();
|
|
348
431
|
|
|
@@ -365,9 +448,7 @@ function findExistingContextObject({ namespace, title, content, tags = [], sourc
|
|
|
365
448
|
filePath,
|
|
366
449
|
document: doc,
|
|
367
450
|
};
|
|
368
|
-
} catch {
|
|
369
|
-
// Ignore malformed entries while searching for exact duplicates.
|
|
370
|
-
}
|
|
451
|
+
} catch { /* ignore */ }
|
|
371
452
|
}
|
|
372
453
|
|
|
373
454
|
return null;
|
|
@@ -502,9 +583,7 @@ function loadCandidates(namespaces) {
|
|
|
502
583
|
...payload,
|
|
503
584
|
namespace,
|
|
504
585
|
});
|
|
505
|
-
} catch {
|
|
506
|
-
// ignore malformed files
|
|
507
|
-
}
|
|
586
|
+
} catch { /* ignore */ }
|
|
508
587
|
});
|
|
509
588
|
});
|
|
510
589
|
|
|
@@ -580,6 +659,7 @@ function selectFlatContextItems(candidates, maxItems, maxChars) {
|
|
|
580
659
|
namespace: item.doc.namespace,
|
|
581
660
|
title: item.doc.title,
|
|
582
661
|
structuredContext: buildStructuredContext(item.doc),
|
|
662
|
+
provenance: buildItemProvenance(item.doc),
|
|
583
663
|
tags: item.doc.tags || [],
|
|
584
664
|
score: item.score,
|
|
585
665
|
});
|
|
@@ -687,6 +767,7 @@ function selectSummarizeThenExpand(candidates, maxItems, maxChars) {
|
|
|
687
767
|
namespace: item.doc.namespace,
|
|
688
768
|
title: item.doc.title,
|
|
689
769
|
structuredContext: buildSummaryContext(item.doc),
|
|
770
|
+
provenance: buildItemProvenance(item.doc),
|
|
690
771
|
tags: item.doc.tags || [],
|
|
691
772
|
score: item.score,
|
|
692
773
|
tier: 'summary',
|
|
@@ -888,31 +969,33 @@ function constructContextPack({
|
|
|
888
969
|
namespaces = [],
|
|
889
970
|
strategy = null,
|
|
890
971
|
summarizeThenExpand = false,
|
|
972
|
+
contextEnvelope = null,
|
|
891
973
|
} = {}) {
|
|
892
974
|
const normalizedNamespaces = normalizeNamespaces(namespaces);
|
|
975
|
+
const normalizedContextEnvelope = normalizeContextEnvelope(contextEnvelope);
|
|
976
|
+
const contextEnvelopeChars = measureContextEnvelopeChars(normalizedContextEnvelope);
|
|
977
|
+
if (contextEnvelopeChars >= maxChars) {
|
|
978
|
+
const error = new Error(
|
|
979
|
+
`contextEnvelope requires ${contextEnvelopeChars} characters but maxChars is ${maxChars}`,
|
|
980
|
+
);
|
|
981
|
+
error.code = 'CONTEXT_BUDGET_EXCEEDED';
|
|
982
|
+
throw error;
|
|
983
|
+
}
|
|
984
|
+
const retrievalMaxChars = maxChars - contextEnvelopeChars;
|
|
893
985
|
const tokens = tokenizeQuery(query);
|
|
894
986
|
const sourceHash = getSourceHash(normalizedNamespaces);
|
|
895
987
|
|
|
896
|
-
// Resolve the effective strategy. Explicit `strategy` wins; otherwise
|
|
897
|
-
// `summarizeThenExpand: true` flips the flag. Default remains auto
|
|
898
|
-
// (flat | hierarchical) so callers that don't opt in keep their cached
|
|
899
|
-
// packs addressable.
|
|
900
988
|
const effectiveStrategy = strategy
|
|
901
989
|
|| (summarizeThenExpand ? 'summarize-then-expand' : null);
|
|
990
|
+
const hierarchicalRetrievalEnabled = shouldUseHierarchicalRetrieval(normalizedNamespaces);
|
|
991
|
+
const retrievalStrategy = effectiveStrategy === 'summarize-then-expand'
|
|
992
|
+
? 'summarize-then-expand'
|
|
993
|
+
: (hierarchicalRetrievalEnabled ? 'hierarchical' : 'flat');
|
|
902
994
|
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
// and invalidate every entry on disk.
|
|
908
|
-
const cacheHit = effectiveStrategy === 'summarize-then-expand'
|
|
909
|
-
? null
|
|
910
|
-
: findSemanticCacheHit({
|
|
911
|
-
query,
|
|
912
|
-
namespaces: normalizedNamespaces,
|
|
913
|
-
maxItems,
|
|
914
|
-
maxChars,
|
|
915
|
-
});
|
|
995
|
+
const cacheHit = findSemanticCacheHit({
|
|
996
|
+
query, namespaces: normalizedNamespaces, maxItems, maxChars,
|
|
997
|
+
strategy: retrievalStrategy, contextEnvelope: normalizedContextEnvelope,
|
|
998
|
+
});
|
|
916
999
|
|
|
917
1000
|
if (cacheHit) {
|
|
918
1001
|
const packId = `pack_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`;
|
|
@@ -922,6 +1005,12 @@ function constructContextPack({
|
|
|
922
1005
|
packId,
|
|
923
1006
|
query,
|
|
924
1007
|
createdAt: nowIso(),
|
|
1008
|
+
items: Array.isArray(cachedPack.items)
|
|
1009
|
+
? cachedPack.items.map((item) => ({
|
|
1010
|
+
...item,
|
|
1011
|
+
provenance: refreshItemProvenance(item.provenance),
|
|
1012
|
+
}))
|
|
1013
|
+
: cachedPack.items,
|
|
925
1014
|
cache: {
|
|
926
1015
|
hit: true,
|
|
927
1016
|
similarity: Number(cacheHit.score.toFixed(4)),
|
|
@@ -947,31 +1036,22 @@ function constructContextPack({
|
|
|
947
1036
|
.map((doc) => ({ doc, score: scoreDocument(doc, tokens) }))
|
|
948
1037
|
.sort((a, b) => b.score - a.score);
|
|
949
1038
|
|
|
950
|
-
const hierarchicalRetrievalEnabled = shouldUseHierarchicalRetrieval(normalizedNamespaces);
|
|
951
1039
|
let selection;
|
|
952
1040
|
if (effectiveStrategy === 'summarize-then-expand') {
|
|
953
|
-
|
|
954
|
-
// summarize-then-expand selector assumes a flat ranked list where each
|
|
955
|
-
// item is a single episode, and mixing it with theme-based hierarchical
|
|
956
|
-
// retrieval would double-compress the top-of-list.
|
|
957
|
-
selection = selectSummarizeThenExpand(candidates, maxItems, maxChars);
|
|
1041
|
+
selection = selectSummarizeThenExpand(candidates, maxItems, retrievalMaxChars);
|
|
958
1042
|
} else if (hierarchicalRetrievalEnabled) {
|
|
959
1043
|
selection = retrieveHierarchicalDocuments({
|
|
960
1044
|
documents: candidates.map((candidate) => candidate.doc),
|
|
961
1045
|
query,
|
|
962
1046
|
maxItems,
|
|
963
|
-
maxChars,
|
|
1047
|
+
maxChars: retrievalMaxChars,
|
|
964
1048
|
scorer: scoreDocument,
|
|
965
1049
|
measureDocument: measureDocumentChars,
|
|
966
1050
|
});
|
|
967
1051
|
} else {
|
|
968
|
-
selection = selectFlatContextItems(candidates, maxItems,
|
|
1052
|
+
selection = selectFlatContextItems(candidates, maxItems, retrievalMaxChars);
|
|
969
1053
|
}
|
|
970
1054
|
|
|
971
|
-
// The flat + hierarchical paths emit raw docs; summarize-then-expand emits
|
|
972
|
-
// fully-shaped items that already carry structuredContext and a `tier`
|
|
973
|
-
// marker. Detect the shape so we don't double-canonicalize STE items
|
|
974
|
-
// (which would re-expand every summary into full content).
|
|
975
1055
|
const selected = selection.items.map((item) => {
|
|
976
1056
|
if (item && item.structuredContext) {
|
|
977
1057
|
return {
|
|
@@ -979,6 +1059,7 @@ function constructContextPack({
|
|
|
979
1059
|
namespace: item.namespace,
|
|
980
1060
|
title: item.title,
|
|
981
1061
|
structuredContext: item.structuredContext,
|
|
1062
|
+
provenance: item.provenance || buildItemProvenance(item),
|
|
982
1063
|
tags: item.tags || [],
|
|
983
1064
|
score: typeof item.score === 'number' ? item.score : scoreDocument(item, tokens),
|
|
984
1065
|
...(item.tier ? { tier: item.tier } : {}),
|
|
@@ -989,11 +1070,12 @@ function constructContextPack({
|
|
|
989
1070
|
namespace: item.namespace,
|
|
990
1071
|
title: item.title,
|
|
991
1072
|
structuredContext: buildStructuredContext(item),
|
|
1073
|
+
provenance: buildItemProvenance(item),
|
|
992
1074
|
tags: item.tags || [],
|
|
993
1075
|
score: scoreDocument(item, tokens),
|
|
994
1076
|
};
|
|
995
1077
|
});
|
|
996
|
-
const usedChars = selection.usedChars;
|
|
1078
|
+
const usedChars = selection.usedChars + contextEnvelopeChars;
|
|
997
1079
|
const skippedByMaxChars = selection.skippedByMaxChars;
|
|
998
1080
|
|
|
999
1081
|
const visibility = {
|
|
@@ -1014,6 +1096,8 @@ function constructContextPack({
|
|
|
1014
1096
|
maxItems,
|
|
1015
1097
|
maxChars,
|
|
1016
1098
|
usedChars,
|
|
1099
|
+
contextEnvelope: normalizedContextEnvelope,
|
|
1100
|
+
contextEnvelopeChars,
|
|
1017
1101
|
namespaces: normalizedNamespaces,
|
|
1018
1102
|
createdAt: nowIso(),
|
|
1019
1103
|
items: selected,
|
|
@@ -1026,29 +1110,27 @@ function constructContextPack({
|
|
|
1026
1110
|
};
|
|
1027
1111
|
|
|
1028
1112
|
appendJsonl(contextFsPath(NAMESPACES.provenance, 'packs.jsonl'), pack);
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
tokens,
|
|
1042
|
-
sourceHash,
|
|
1043
|
-
pack,
|
|
1044
|
-
});
|
|
1045
|
-
}
|
|
1113
|
+
appendSemanticCacheEntry({
|
|
1114
|
+
id: `cache_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`,
|
|
1115
|
+
timestamp: nowIso(),
|
|
1116
|
+
key: buildSemanticCacheKey({
|
|
1117
|
+
namespaces: normalizedNamespaces, maxItems, maxChars,
|
|
1118
|
+
strategy: retrievalStrategy, contextEnvelope: normalizedContextEnvelope,
|
|
1119
|
+
}),
|
|
1120
|
+
query,
|
|
1121
|
+
tokens,
|
|
1122
|
+
sourceHash,
|
|
1123
|
+
pack,
|
|
1124
|
+
});
|
|
1046
1125
|
recordProvenance({
|
|
1047
1126
|
type: 'context_pack_constructed',
|
|
1048
1127
|
packId,
|
|
1049
1128
|
query,
|
|
1050
1129
|
itemCount: selected.length,
|
|
1051
1130
|
usedChars,
|
|
1131
|
+
contextEnvelopeVersion: normalizedContextEnvelope
|
|
1132
|
+
? normalizedContextEnvelope.version
|
|
1133
|
+
: null,
|
|
1052
1134
|
sourceHash,
|
|
1053
1135
|
retrievalStrategy: selection.retrieval.strategy,
|
|
1054
1136
|
});
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Shared helpers for dashboard size / heap failures (prod feedback logs).
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
function isDashboardDataLimitError(err) {
|
|
8
|
+
const message = String(err && err.message ? err.message : err || '');
|
|
9
|
+
return /string longer than|Cannot create a string|ENOMEM|JavaScript heap|out of memory/i.test(message);
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
function formatDashboardLimitDetail(err, { phase = 'assembly' } = {}) {
|
|
13
|
+
const cause = err && err.message ? err.message : 'string/heap limit';
|
|
14
|
+
if (phase === 'stringify') {
|
|
15
|
+
return 'Dashboard JSON exceeded the runtime string limit. '
|
|
16
|
+
+ 'Use a bounded feedback window or rotate oversized logs. '
|
|
17
|
+
+ `Cause: ${cause}`;
|
|
18
|
+
}
|
|
19
|
+
return 'Feedback/memory logs exceeded the safe in-memory limit for dashboard assembly. '
|
|
20
|
+
+ 'Logs are now tail-capped; if this persists, rotate oversized JSONL under the feedback dir. '
|
|
21
|
+
+ `Cause: ${cause}`;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
module.exports = {
|
|
25
|
+
isDashboardDataLimitError,
|
|
26
|
+
formatDashboardLimitDetail,
|
|
27
|
+
};
|