mirror of
https://github.com/PR0M3TH3AN/SeedPass.git
synced 2026-10-27 07:52:03 +00:00
Merge pull request #943 from PR0M3TH3AN/agents/daily/const-refactor-agent-6148832155416611801
[constants] extract memory service numeric literals to canonical modules
This commit is contained in:
23 files changed
+216
-23
No files matched your search
@@ -1,3 +1,6 @@
|
||||
### 1. [2026-02-27] (scheduler, daily, retrieve)
|
||||
|
||||
Memory retrieval seed for daily :: Required startup + artifacts + memory + issue capture
|
||||
### 1. [2026-02-28] (scheduler, daily, retrieve)
|
||||
|
||||
# Memory Update (2026-02-25)
|
||||
|
||||
@@ -513,6 +513,12 @@
|
||||
}
|
||||
],
|
||||
[
|
||||
"094aab2a-4a25-4322-a198-1638752acc77",
|
||||
{
|
||||
"schema_version": 1,
|
||||
"id": "094aab2a-4a25-4322-a198-1638752acc77",
|
||||
"agent_id": "const-refactor-agent",
|
||||
"session_id": "session-mm5d7amf",
|
||||
"c60afd2d-1325-4096-849a-77e11f2b5e39",
|
||||
{
|
||||
"schema_version": 1,
|
||||
@@ -547,6 +553,8 @@
|
||||
],
|
||||
"importance": 0.4,
|
||||
"embedding_id": null,
|
||||
"created_at": 1772225327752,
|
||||
"last_seen": 1772225327764,
|
||||
"created_at": 1772221041979,
|
||||
"last_seen": 1772221041993,
|
||||
"created_at": 1772218140227,
|
||||
@@ -560,6 +568,12 @@
|
||||
}
|
||||
],
|
||||
[
|
||||
"cef905d0-7a66-459c-8937-41310afc934f",
|
||||
{
|
||||
"schema_version": 1,
|
||||
"id": "cef905d0-7a66-459c-8937-41310afc934f",
|
||||
"agent_id": "const-refactor-agent",
|
||||
"session_id": "session-mm5dpefy",
|
||||
"9c49ca58-c6e5-4751-a3de-ab48bf7a4da1",
|
||||
{
|
||||
"schema_version": 1,
|
||||
@@ -592,6 +606,8 @@
|
||||
],
|
||||
"importance": 0.8,
|
||||
"embedding_id": null,
|
||||
"created_at": 1772226172512,
|
||||
"last_seen": 1772226172512,
|
||||
"created_at": 1772222021666,
|
||||
"last_seen": 1772222021666,
|
||||
"created_at": 1772218432277,
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
{
|
||||
"cadence": "daily",
|
||||
"operation": "retrieve",
|
||||
"runId": "session-mm5d7amf",
|
||||
"servicePath": "src/services/memory/index.js#getRelevantMemories",
|
||||
"inputs": {
|
||||
"agentId": "const-refactor-agent",
|
||||
"promptPath": "torch/src/prompts/daily/const-refactor-agent.md",
|
||||
"promptIntent": "Required startup + artifacts + memory + issue capture",
|
||||
"query": "scheduler | daily | agent | const-refactor-agent | intent | Required startup + artifacts + memory + issue capture",
|
||||
"events": 1
|
||||
},
|
||||
"outputs": {
|
||||
"ingestedCount": 1,
|
||||
"retrievedCount": 1
|
||||
},
|
||||
"status": "ok"
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
MEMORY_RETRIEVED
|
||||
@@ -0,0 +1,20 @@
|
||||
{
|
||||
"cadence": "daily",
|
||||
"operation": "store",
|
||||
"runId": "session-mm5dpefy",
|
||||
"servicePath": "src/services/memory/index.js#ingestEvents",
|
||||
"inputs": {
|
||||
"agentId": "const-refactor-agent",
|
||||
"promptPath": "torch/src/prompts/daily/const-refactor-agent.md",
|
||||
"promptIntent": "Required startup + artifacts + memory + issue capture",
|
||||
"events": 1,
|
||||
"sourceFile": "memory-update.md"
|
||||
},
|
||||
"outputs": {
|
||||
"storedCount": 1,
|
||||
"summaries": [
|
||||
"# Memory Update — bug-reproducer-agent — 2026-02-27\n\n## Key findings\n- The `scheduler-flow.md` script execution failed due to a missing runner (`codex`).\n- The automated `bug-reproducer-agent` prompt execution failed.\n- Fallback manual investigation identified one active issue: …"
|
||||
]
|
||||
},
|
||||
"status": "ok"
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
MEMORY_STORED
|
||||
@@ -0,0 +1,58 @@
|
||||
[
|
||||
{
|
||||
"value": 1000,
|
||||
"semantic": "one second in ms",
|
||||
"occurrences": [
|
||||
{"file": "torch/src/services/memory/index.js", "line": 45, "context": "const MIN_SAVE_INTERVAL_MS = 1000;"},
|
||||
{"file": "torch/src/services/memory/pruner.js", "line": 3, "context": "const DAY_MS = 24 * 60 * 60 * 1000;"},
|
||||
{"file": "torch/src/services/memory/retriever.js", "line": 8, "context": "const DEFAULT_RECENCY_HALF_LIFE_MS = 1000 * 60 * 60 * 24 * 7;"},
|
||||
{"file": "torch/src/services/memory/formatter.js", "line": 3, "context": "const DEFAULT_TOKEN_BUDGET = 1000;"}
|
||||
]
|
||||
},
|
||||
{
|
||||
"value": 60000,
|
||||
"semantic": "one minute in ms (or 60_000)",
|
||||
"occurrences": [
|
||||
{"file": "torch/src/services/memory/index.js", "line": 548, "context": "windowMs / 60_000"},
|
||||
{"file": "torch/src/services/memory/ingestor.js", "line": 6, "context": "const WINDOW_BUCKET_MS = 60_000;"},
|
||||
{"file": "torch/src/services/memory/cache.js", "line": 153, "context": "setRuntimeEvent(scope, event, ttlMs = 60_000) {"},
|
||||
{"file": "torch/src/services/memory/cache.js", "line": 157, "context": "const safeTtlMs = Number.isFinite(ttlMs) && ttlMs > 0 ? ttlMs : 60_000;"},
|
||||
{"file": "torch/src/services/memory/scheduler.js", "line": 2, "context": "const MINUTE_MS = 60_000;"}
|
||||
]
|
||||
},
|
||||
{
|
||||
"value": "24 * 60 * 60 * 1000",
|
||||
"semantic": "one day in ms",
|
||||
"occurrences": [
|
||||
{"file": "torch/src/services/memory/pruner.js", "line": 3, "context": "const DAY_MS = 24 * 60 * 60 * 1000;"},
|
||||
{"file": "torch/src/services/memory/index.js", "line": 329, "context": "const retentionMs = options.retentionMs ?? (1000 * 60 * 60 * 24 * 30);"},
|
||||
{"file": "torch/src/services/memory/index.js", "line": 495, "context": "const retentionMs = options.retentionMs ?? (1000 * 60 * 60 * 24 * 30);"}
|
||||
]
|
||||
},
|
||||
{
|
||||
"value": 280,
|
||||
"semantic": "max summary chars length",
|
||||
"occurrences": [
|
||||
{"file": "torch/src/services/memory/pruner.js", "line": 116, "context": ".slice(0, 280)"},
|
||||
{"file": "torch/src/services/memory/summarizer.js", "line": 116, "context": "const maxSummaryLength = options.maxSummaryLength ?? 280;"},
|
||||
{"file": "torch/src/services/memory/ingestor.js", "line": 92, "context": "function compactContextExcerpt(text, maxChars = 280) {"}
|
||||
]
|
||||
},
|
||||
{
|
||||
"value": 0.25,
|
||||
"semantic": "default importance score",
|
||||
"occurrences": [
|
||||
{"file": "torch/src/services/memory/summarizer.js", "line": 64, "context": "Math.min(1, Math.max(0, rawImportance)) : 0.25;"},
|
||||
{"file": "torch/src/services/memory/summarizer.js", "line": 72, "context": "return { summary: bounded, importance: 0.25 };"},
|
||||
{"file": "torch/src/services/memory/retriever.js", "line": 3, "context": "w_imp: 0.25,"}
|
||||
]
|
||||
},
|
||||
{
|
||||
"value": 0.35,
|
||||
"semantic": "low importance / semantic overlap threshold",
|
||||
"occurrences": [
|
||||
{"file": "torch/src/services/memory/summarizer.js", "line": 89, "context": "return overlap / summaryTokens.length >= 0.35;"},
|
||||
{"file": "torch/src/services/memory/pruner.js", "line": 184, "context": "lowImportanceThreshold: options.lowImportanceThreshold ?? 0.35,"}
|
||||
]
|
||||
}
|
||||
]
|
||||
@@ -0,0 +1,37 @@
|
||||
torch/src/services/memory/index.js:45:const MIN_SAVE_INTERVAL_MS = 1000;
|
||||
torch/src/services/memory/index.js:158:const ESTIMATED_INDEX_BYTES_PER_RECORD = 512;
|
||||
torch/src/services/memory/index.js:164: if (typeof value === 'string' && value.length > 300) {
|
||||
torch/src/services/memory/index.js:165: safe[key] = `${value.slice(0, 300)}…`;
|
||||
torch/src/services/memory/index.js:225: if (samples.length > 10_000) {
|
||||
torch/src/services/memory/index.js:226: samples.splice(0, samples.length - 10_000);
|
||||
torch/src/services/memory/index.js:324: * const result = await runPruneCycle({ retentionMs: 30 * 24 * 60 * 60 * 1000 });
|
||||
torch/src/services/memory/index.js:329: const retentionMs = options.retentionMs ?? (1000 * 60 * 60 * 24 * 30);
|
||||
torch/src/services/memory/index.js:491: * const preview = await triggerPruneDryRun({ retentionMs: 7 * 24 * 60 * 60 * 1000 });
|
||||
torch/src/services/memory/index.js:495: const retentionMs = options.retentionMs ?? (1000 * 60 * 60 * 24 * 30);
|
||||
torch/src/services/memory/index.js:530: * const stats = await memoryStats({ windowMs: 60 * 60 * 1000 });
|
||||
torch/src/services/memory/index.js:535: const windowMs = Number.isFinite(options.windowMs) ? Math.max(1, Number(options.windowMs)) : (60 * 60 * 1000);
|
||||
torch/src/services/memory/index.js:548: const ingestThroughputPerMinute = ingestedInWindow / Math.max(1, (windowMs / 60_000));
|
||||
torch/src/services/memory/pruner.js:3:const DAY_MS = 24 * 60 * 60 * 1000;
|
||||
torch/src/services/memory/pruner.js:116: const fallbackSummary = group.map((item) => item.summary || item.content).filter(Boolean).join(' ').slice(0, 280);
|
||||
torch/src/services/memory/pruner.js:184: lowImportanceThreshold: options.lowImportanceThreshold ?? 0.35,
|
||||
torch/src/services/memory/pruner.js:185: deleteImportanceThreshold: options.deleteImportanceThreshold ?? 0.12,
|
||||
torch/src/services/memory/summarizer.js:64: : 0.25;
|
||||
torch/src/services/memory/summarizer.js:72: return { summary: bounded, importance: 0.25 };
|
||||
torch/src/services/memory/summarizer.js:89: return overlap / summaryTokens.length >= 0.35;
|
||||
torch/src/services/memory/summarizer.js:116: const maxSummaryLength = options.maxSummaryLength ?? 280;
|
||||
torch/src/services/memory/ingestor.js:6:const WINDOW_BUCKET_MS = 60_000;
|
||||
torch/src/services/memory/ingestor.js:37: : 300;
|
||||
torch/src/services/memory/ingestor.js:92:function compactContextExcerpt(text, maxChars = 280) {
|
||||
torch/src/services/memory/retriever.js:2: w_sim: 0.6,
|
||||
torch/src/services/memory/retriever.js:3: w_imp: 0.25,
|
||||
torch/src/services/memory/retriever.js:4: w_rec: 0.15,
|
||||
torch/src/services/memory/retriever.js:5: pinBoost: 0.15,
|
||||
torch/src/services/memory/retriever.js:8:const DEFAULT_RECENCY_HALF_LIFE_MS = 1000 * 60 * 60 * 24 * 7;
|
||||
torch/src/services/memory/formatter.js:3:const DEFAULT_TOKEN_BUDGET = 1000;
|
||||
torch/src/services/memory/cache.js:2:const DEFAULT_MAX_EVENTS_PER_NAMESPACE = 200;
|
||||
torch/src/services/memory/cache.js:3:const DEFAULT_MAX_TOTAL_EVENTS = 5000;
|
||||
torch/src/services/memory/cache.js:153: setRuntimeEvent(scope, event, ttlMs = 60_000) {
|
||||
torch/src/services/memory/cache.js:157: const safeTtlMs = Number.isFinite(ttlMs) && ttlMs > 0 ? ttlMs : 60_000;
|
||||
torch/src/services/memory/scheduler.js:2:const MINUTE_MS = 60_000;
|
||||
torch/src/services/memory/scheduler.js:3:const HOUR_MS = 60 * MINUTE_MS;
|
||||
torch/src/services/memory/scheduler.js:4:const DAY_MS = 24 * HOUR_MS;
|
||||
@@ -0,0 +1,2 @@
|
||||
Fri Feb 27 20:49:17 UTC 2026
|
||||
Exploring duplicated constants in js/
|
||||
@@ -0,0 +1,7 @@
|
||||
## Decisions
|
||||
|
||||
- **Domain-specific constants vs Global**: The constants were found specifically within `torch/src/services/memory/`. Therefore, I created `torch/src/services/memory/constants/` rather than a global `src/constants.js`.
|
||||
- **Time constants**: Created `time.js` for `SECOND_MS`, `MINUTE_MS`, `HOUR_MS`, `DAY_MS`, `WEEK_MS`, `MONTH_MS`.
|
||||
- **Text constants**: Created `text.js` for `MAX_SUMMARY_LENGTH`.
|
||||
- **Scoring constants**: Created `scoring.js` for `DEFAULT_IMPORTANCE_SCORE` and `LOW_IMPORTANCE_THRESHOLD`.
|
||||
- Replaced literals in `index.js`, `pruner.js`, `retriever.js`, `ingestor.js`, `summarizer.js`, `cache.js`, `scheduler.js`.
|
||||
@@ -0,0 +1 @@
|
||||
Ran `npm run --prefix torch lint` and verified that there are no linter errors.
|
||||
@@ -0,0 +1,10 @@
|
||||
## Constants Refactoring TODOs
|
||||
|
||||
1. `1000` (second in ms): Replaced with `SECOND_MS`
|
||||
2. `60000` (minute in ms): Replaced with `MINUTE_MS`
|
||||
3. `24 * 60 * 60 * 1000` (day in ms): Replaced with `DAY_MS`
|
||||
4. `280` (max summary length): Replaced with `MAX_SUMMARY_LENGTH`
|
||||
5. `0.25` (default importance): Replaced with `DEFAULT_IMPORTANCE_SCORE`
|
||||
6. `0.35` (low importance threshold): Replaced with `LOW_IMPORTANCE_THRESHOLD`
|
||||
|
||||
Status: All complete. Constants extracted to `torch/src/services/memory/constants/`.
|
||||
@@ -1,3 +1,5 @@
|
||||
import { MINUTE_MS } from './constants/time.js';
|
||||
|
||||
const DEFAULT_MAX_NAMESPACES = 128;
|
||||
const DEFAULT_MAX_EVENTS_PER_NAMESPACE = 200;
|
||||
const DEFAULT_MAX_TOTAL_EVENTS = 5000;
|
||||
@@ -150,11 +152,11 @@ export function createMemoryCache(options = {}) {
|
||||
runtimeNamespaces.clear();
|
||||
totalRuntimeEvents = 0;
|
||||
},
|
||||
setRuntimeEvent(scope, event, ttlMs = 60_000) {
|
||||
setRuntimeEvent(scope, event, ttlMs = MINUTE_MS) {
|
||||
const now = Date.now();
|
||||
removeExpired(now);
|
||||
|
||||
const safeTtlMs = Number.isFinite(ttlMs) && ttlMs > 0 ? ttlMs : 60_000;
|
||||
const safeTtlMs = Number.isFinite(ttlMs) && ttlMs > 0 ? ttlMs : MINUTE_MS;
|
||||
const expiresAt = now + safeTtlMs;
|
||||
const namespaceKey = getNamespaceKey(scope);
|
||||
const bucket = runtimeNamespaces.get(namespaceKey) ?? { events: [] };
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
export const DEFAULT_IMPORTANCE_SCORE = 0.25;
|
||||
export const LOW_IMPORTANCE_THRESHOLD = 0.35;
|
||||
@@ -0,0 +1 @@
|
||||
export const MAX_SUMMARY_LENGTH = 280;
|
||||
@@ -0,0 +1,6 @@
|
||||
export const SECOND_MS = 1000;
|
||||
export const MINUTE_MS = 60 * SECOND_MS;
|
||||
export const HOUR_MS = 60 * MINUTE_MS;
|
||||
export const DAY_MS = 24 * HOUR_MS;
|
||||
export const WEEK_MS = 7 * DAY_MS;
|
||||
export const MONTH_MS = 30 * DAY_MS;
|
||||
@@ -42,7 +42,9 @@ let currentSavePromise = null;
|
||||
let pendingSavePromise = null;
|
||||
let pendingSaveResolve = null;
|
||||
let lastSaveTime = 0;
|
||||
const MIN_SAVE_INTERVAL_MS = 1000;
|
||||
import { SECOND_MS, MONTH_MS, MINUTE_MS } from './constants/time.js';
|
||||
|
||||
const MIN_SAVE_INTERVAL_MS = SECOND_MS;
|
||||
|
||||
async function performSave(store) {
|
||||
try {
|
||||
@@ -326,7 +328,7 @@ export async function getRelevantMemories(params) {
|
||||
export async function runPruneCycle(options = {}) {
|
||||
const repository = options.repository ?? memoryRepository;
|
||||
const telemetry = buildTelemetryEmitter(options);
|
||||
const retentionMs = options.retentionMs ?? (1000 * 60 * 60 * 24 * 30);
|
||||
const retentionMs = options.retentionMs ?? MONTH_MS;
|
||||
const pruneMode = options.pruneMode ?? getMemoryPruneMode(options.env);
|
||||
const dbCandidates = await listPruneCandidates(repository, {
|
||||
retentionMs,
|
||||
@@ -492,7 +494,7 @@ export async function inspectMemory(id, options = {}) {
|
||||
*/
|
||||
export async function triggerPruneDryRun(options = {}) {
|
||||
const repository = options.repository ?? memoryRepository;
|
||||
const retentionMs = options.retentionMs ?? (1000 * 60 * 60 * 24 * 30);
|
||||
const retentionMs = options.retentionMs ?? MONTH_MS;
|
||||
const dbCandidates = await listPruneCandidates(repository, {
|
||||
retentionMs,
|
||||
now: options.now,
|
||||
@@ -532,7 +534,7 @@ export async function triggerPruneDryRun(options = {}) {
|
||||
export async function memoryStats(options = {}) {
|
||||
const repository = options.repository ?? memoryRepository;
|
||||
const now = options.now ?? Date.now();
|
||||
const windowMs = Number.isFinite(options.windowMs) ? Math.max(1, Number(options.windowMs)) : (60 * 60 * 1000);
|
||||
const windowMs = Number.isFinite(options.windowMs) ? Math.max(1, Number(options.windowMs)) : (60 * MINUTE_MS);
|
||||
const memories = await listMemories({}, { repository });
|
||||
|
||||
const countsByType = memories.reduce((acc, memory) => {
|
||||
@@ -545,7 +547,7 @@ export async function memoryStats(options = {}) {
|
||||
const archivedRate = archivedCount / Math.max(1, memories.length);
|
||||
|
||||
const ingestedInWindow = memoryStatsState.ingested.filter((timestamp) => timestamp >= (now - windowMs)).length;
|
||||
const ingestThroughputPerMinute = ingestedInWindow / Math.max(1, (windowMs / 60_000));
|
||||
const ingestThroughputPerMinute = ingestedInWindow / Math.max(1, (windowMs / MINUTE_MS));
|
||||
|
||||
return {
|
||||
countsByType,
|
||||
|
||||
@@ -2,8 +2,10 @@ import { createHash, randomUUID } from 'node:crypto';
|
||||
import { createMemoryRecord, normalizeEvent, validateMemoryItem } from './schema.js';
|
||||
import { embedText, getDefaultEmbedderAdapter } from './embedder.js';
|
||||
import { summarizeEvents } from './summarizer.js';
|
||||
import { MINUTE_MS } from './constants/time.js';
|
||||
import { MAX_SUMMARY_LENGTH } from './constants/text.js';
|
||||
|
||||
const WINDOW_BUCKET_MS = 60_000;
|
||||
const WINDOW_BUCKET_MS = MINUTE_MS;
|
||||
const MAX_DEDUPE_KEYS = 2000;
|
||||
const dedupeWindow = new Map();
|
||||
|
||||
@@ -89,7 +91,7 @@ async function rememberWindowFingerprint(repository, dedupeKey, payload) {
|
||||
}
|
||||
|
||||
|
||||
function compactContextExcerpt(text, maxChars = 280) {
|
||||
function compactContextExcerpt(text, maxChars = MAX_SUMMARY_LENGTH) {
|
||||
if (typeof text !== 'string' || text.length === 0) return '';
|
||||
const compact = text.replace(/\s+/g, ' ').trim();
|
||||
if (compact.length <= maxChars) return compact;
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { loadMemoryPromptTemplates } from './summarizer.js';
|
||||
|
||||
const DAY_MS = 24 * 60 * 60 * 1000;
|
||||
import { DAY_MS } from './constants/time.js';
|
||||
import { MAX_SUMMARY_LENGTH } from './constants/text.js';
|
||||
import { LOW_IMPORTANCE_THRESHOLD } from './constants/scoring.js';
|
||||
|
||||
/**
|
||||
* @typedef {'keep' | 'archive' | 'delete'} LifecycleAction
|
||||
@@ -113,7 +114,7 @@ function groupNearDuplicates(memories, options) {
|
||||
*/
|
||||
async function condenseGroup(group, generateSummary, condenseTemplate) {
|
||||
const [primary, ...rest] = group;
|
||||
const fallbackSummary = group.map((item) => item.summary || item.content).filter(Boolean).join(' ').slice(0, 280);
|
||||
const fallbackSummary = group.map((item) => item.summary || item.content).filter(Boolean).join(' ').slice(0, MAX_SUMMARY_LENGTH);
|
||||
const fallback = {
|
||||
summary: fallbackSummary || primary.summary,
|
||||
importance: Math.max(...group.map((item) => item.importance)),
|
||||
@@ -181,7 +182,7 @@ export async function createLifecyclePlan(memories, options) {
|
||||
const policy = {
|
||||
now,
|
||||
retentionMs: options.retentionMs,
|
||||
lowImportanceThreshold: options.lowImportanceThreshold ?? 0.35,
|
||||
lowImportanceThreshold: options.lowImportanceThreshold ?? LOW_IMPORTANCE_THRESHOLD,
|
||||
deleteImportanceThreshold: options.deleteImportanceThreshold ?? 0.12,
|
||||
recentUsageMs: options.recentUsageMs ?? Math.max(Math.floor(options.retentionMs / 2), DAY_MS),
|
||||
duplicateWindowMs: options.duplicateWindowMs ?? (7 * DAY_MS),
|
||||
|
||||
@@ -1,11 +1,14 @@
|
||||
import { WEEK_MS } from './constants/time.js';
|
||||
import { DEFAULT_IMPORTANCE_SCORE } from './constants/scoring.js';
|
||||
|
||||
const DEFAULT_WEIGHTS = {
|
||||
w_sim: 0.6,
|
||||
w_imp: 0.25,
|
||||
w_imp: DEFAULT_IMPORTANCE_SCORE,
|
||||
w_rec: 0.15,
|
||||
pinBoost: 0.15,
|
||||
};
|
||||
|
||||
const DEFAULT_RECENCY_HALF_LIFE_MS = 1000 * 60 * 60 * 24 * 7;
|
||||
const DEFAULT_RECENCY_HALF_LIFE_MS = WEEK_MS;
|
||||
|
||||
function cosineSimilarity(left = [], right = []) {
|
||||
const size = Math.max(left.length, right.length);
|
||||
|
||||
@@ -1,8 +1,5 @@
|
||||
import { getMemoryPruneMode, isMemoryEnabled, isMemoryIngestEnabled } from './feature-flags.js';
|
||||
const MINUTE_MS = 60_000;
|
||||
const HOUR_MS = 60 * MINUTE_MS;
|
||||
const DAY_MS = 24 * HOUR_MS;
|
||||
const WEEK_MS = 7 * DAY_MS;
|
||||
import { MINUTE_MS, HOUR_MS, DAY_MS, WEEK_MS } from './constants/time.js';
|
||||
|
||||
const JOBS = {
|
||||
ingestRecentRuntimeEvents: {
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
import { readFileSync } from 'node:fs';
|
||||
import path from 'node:path';
|
||||
import { fileURLToPath } from 'node:url';
|
||||
import { MAX_SUMMARY_LENGTH } from './constants/text.js';
|
||||
import { DEFAULT_IMPORTANCE_SCORE, LOW_IMPORTANCE_THRESHOLD } from './constants/scoring.js';
|
||||
|
||||
const __filename = fileURLToPath(import.meta.url);
|
||||
const __dirname = path.dirname(__filename);
|
||||
@@ -61,7 +63,7 @@ function parseSummaryPayload(rawResponse) {
|
||||
const rawImportance = Number(parsed.importance);
|
||||
const importance = Number.isFinite(rawImportance)
|
||||
? Math.min(1, Math.max(0, rawImportance))
|
||||
: 0.25;
|
||||
: DEFAULT_IMPORTANCE_SCORE;
|
||||
|
||||
return { summary, importance };
|
||||
}
|
||||
@@ -69,7 +71,7 @@ function parseSummaryPayload(rawResponse) {
|
||||
function deterministicFallback(events, maxSummaryLength) {
|
||||
const joined = events.map((event) => redactObviousPii(event.content)).join(' ').trim();
|
||||
const bounded = joined.length > maxSummaryLength ? `${joined.slice(0, maxSummaryLength - 1)}…` : joined;
|
||||
return { summary: bounded, importance: 0.25 };
|
||||
return { summary: bounded, importance: DEFAULT_IMPORTANCE_SCORE };
|
||||
}
|
||||
|
||||
function isLikelyFactual(summary, sourceText) {
|
||||
@@ -86,7 +88,7 @@ function isLikelyFactual(summary, sourceText) {
|
||||
|
||||
if (!summaryTokens.length) return true;
|
||||
const overlap = summaryTokens.filter((token) => sourceTokens.has(token)).length;
|
||||
return overlap / summaryTokens.length >= 0.35;
|
||||
return overlap / summaryTokens.length >= LOW_IMPORTANCE_THRESHOLD;
|
||||
}
|
||||
|
||||
function sanitizeResult(parsed, sourceText, maxSummaryLength, fallback) {
|
||||
@@ -113,7 +115,7 @@ function sanitizeResult(parsed, sourceText, maxSummaryLength, fallback) {
|
||||
* @returns {Promise<{ summary: string, importance: number }>}
|
||||
*/
|
||||
export async function summarizeEvents(events, options = {}) {
|
||||
const maxSummaryLength = options.maxSummaryLength ?? 280;
|
||||
const maxSummaryLength = options.maxSummaryLength ?? MAX_SUMMARY_LENGTH;
|
||||
const fallback = deterministicFallback(events, maxSummaryLength);
|
||||
if (!fallback.summary) return fallback;
|
||||
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
completed
|
||||
Reference in new issue
Block a user