@botbotgo/agent-harness 0.0.475 → 0.0.476
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 +3 -1234
- package/README.zh.md +3 -1191
- package/dist/acp.js +1 -1
- package/dist/api.js +1 -404
- package/dist/benchmark/checkpoint-resume-cost-benchmark.js +1 -55
- package/dist/benchmark/deepagent-local-model-benchmark.js +2 -35
- package/dist/benchmark/upstream-runtime-ab-benchmark.js +1 -179
- package/dist/cli/chat-interactive.js +25 -244
- package/dist/cli/chat-rendering.js +6 -100
- package/dist/cli/chat-stream.js +23 -512
- package/dist/cli/chat-ui.js +21 -199
- package/dist/cli/chat-workspace.js +2 -210
- package/dist/cli/main.js +21 -428
- package/dist/cli/managed-service-commands.js +9 -63
- package/dist/cli/managed-service.js +2 -137
- package/dist/cli/options-init-chat.js +1 -108
- package/dist/cli/options-runtime.js +1 -158
- package/dist/cli/options-serve.js +1 -282
- package/dist/cli/options.js +2 -19
- package/dist/cli/process-guards.js +1 -139
- package/dist/cli/request-tree.js +7 -296
- package/dist/cli/runtime-commands.js +12 -258
- package/dist/cli/runtime-output.js +16 -155
- package/dist/cli/server-commands.js +16 -270
- package/dist/cli/workspace.js +1 -67
- package/dist/cli.js +1 -7
- package/dist/client/acp.js +1 -1
- package/dist/client/in-process.js +1 -67
- package/dist/client/index.js +1 -2
- package/dist/client/types.js +0 -1
- package/dist/client.js +1 -1
- package/dist/contracts/core.js +1 -1
- package/dist/contracts/runtime-evaluation.js +0 -1
- package/dist/contracts/runtime-memory.js +0 -1
- package/dist/contracts/runtime-observability.js +0 -1
- package/dist/contracts/runtime-requests.js +0 -1
- package/dist/contracts/runtime-scheduling.js +0 -1
- package/dist/contracts/runtime.js +1 -27
- package/dist/contracts/types.js +1 -3
- package/dist/contracts/workspace.js +0 -1
- package/dist/flow/build-flow-graph.js +1 -50
- package/dist/flow/export-mermaid.js +2 -464
- package/dist/flow/export-sequence-mermaid.js +2 -325
- package/dist/flow/flow-graph-normalization.js +1 -214
- package/dist/flow/flow-graph-runtime.js +1 -107
- package/dist/flow/flow-graph-upstream.js +1 -494
- package/dist/flow/index.js +1 -3
- package/dist/flow/types.js +0 -1
- package/dist/index.js +1 -5
- package/dist/init-project.js +1 -1
- package/dist/knowledge/config.js +1 -32
- package/dist/knowledge/contracts.js +0 -1
- package/dist/knowledge/index.js +1 -2
- package/dist/knowledge/module.js +12 -909
- package/dist/knowledge/procedural/config.js +1 -125
- package/dist/knowledge/procedural/index.js +1 -2
- package/dist/knowledge/procedural/manager.js +9 -345
- package/dist/mcp.js +1 -2
- package/dist/package-version.d.ts +1 -1
- package/dist/package-version.js +1 -2
- package/dist/persistence/file-store.js +3 -758
- package/dist/persistence/sqlite-request-context-store.js +5 -54
- package/dist/persistence/sqlite-request-queue-store.js +10 -108
- package/dist/persistence/sqlite-runtime.js +1 -86
- package/dist/persistence/sqlite-store.js +62 -810
- package/dist/persistence/types.js +0 -1
- package/dist/projections/presentation.js +37 -206
- package/dist/projections/request-events.js +2 -502
- package/dist/projections/upstream-events.js +1 -201
- package/dist/protocol/a2a/http-discovery.js +1 -178
- package/dist/protocol/a2a/http-rpc.js +6 -622
- package/dist/protocol/a2a/http.js +1 -138
- package/dist/protocol/a2a/task-state.js +3 -317
- package/dist/protocol/acp/client.js +8 -294
- package/dist/protocol/acp/harness-client.js +1 -218
- package/dist/protocol/acp/http.js +5 -130
- package/dist/protocol/acp/server.js +1 -310
- package/dist/protocol/acp/stdio.js +2 -69
- package/dist/protocol/ag-ui/http.js +3 -378
- package/dist/protocol/mcp/server.js +1 -428
- package/dist/resource/backend/workspace-scoped-backend.js +1 -319
- package/dist/resource/isolation.js +1 -237
- package/dist/resource/mcp/tool-support.js +3 -296
- package/dist/resource/mcp-tool-support.js +1 -2
- package/dist/resource/providers/resource-provider.js +1 -215
- package/dist/resource/resource-impl.js +1 -3
- package/dist/resource/resource-types.js +0 -1
- package/dist/resource/resource.js +1 -1
- package/dist/resource/sources.js +1 -247
- package/dist/resource/tools/function-tool-resolver.js +2 -272
- package/dist/runtime/adapter/compat/deepagent-compat.js +1 -29
- package/dist/runtime/adapter/compat/openai-compatible.js +1 -55
- package/dist/runtime/adapter/direct-builtin-utility.js +2 -90
- package/dist/runtime/adapter/flow/execution-context.js +1 -71
- package/dist/runtime/adapter/flow/invocation-flow.js +8 -425
- package/dist/runtime/adapter/flow/invoke-runtime.js +1 -20
- package/dist/runtime/adapter/flow/stream-runtime.js +11 -1395
- package/dist/runtime/adapter/invocation-result.js +2 -473
- package/dist/runtime/adapter/local-tool-invocation.js +6 -638
- package/dist/runtime/adapter/middleware/context-hygiene.js +1 -83
- package/dist/runtime/adapter/middleware-assembly.js +5 -477
- package/dist/runtime/adapter/model/invocation-request.js +3 -183
- package/dist/runtime/adapter/model/message-assembly.js +1 -28
- package/dist/runtime/adapter/model/model-providers.js +23 -1115
- package/dist/runtime/adapter/model/prompted-json-tool-call-capture.js +1 -40
- package/dist/runtime/adapter/model/prompted-json-tool-policy.js +1 -22
- package/dist/runtime/adapter/resilience.js +1 -104
- package/dist/runtime/adapter/runtime-adapter-support.js +3 -141
- package/dist/runtime/adapter/runtime-shell.js +5 -166
- package/dist/runtime/adapter/stream-event-projection.js +2 -622
- package/dist/runtime/adapter/stream-text-consumption.js +1 -18
- package/dist/runtime/adapter/terminal-status.js +2 -67
- package/dist/runtime/adapter/tool/builtin-middleware-tools.js +6 -627
- package/dist/runtime/adapter/tool/declared-middleware.js +1 -154
- package/dist/runtime/adapter/tool/interrupt-policy.js +1 -34
- package/dist/runtime/adapter/tool/provider-tool.js +1 -25
- package/dist/runtime/adapter/tool/resolved-tool.js +1 -225
- package/dist/runtime/adapter/tool/tool-arguments.js +3 -486
- package/dist/runtime/adapter/tool/tool-hitl.js +1 -346
- package/dist/runtime/adapter/tool/tool-name-mapping.js +1 -128
- package/dist/runtime/adapter/tool/tool-output-artifacts.js +2 -88
- package/dist/runtime/adapter/tool/tool-replay.js +1 -37
- package/dist/runtime/adapter/tool-resolution.js +1 -86
- package/dist/runtime/adapter/upstream-configurable-keys.js +1 -2
- package/dist/runtime/agent-runtime-adapter.js +60 -2338
- package/dist/runtime/agent-runtime-assembly.js +7 -249
- package/dist/runtime/env/runtime-env.js +1 -62
- package/dist/runtime/harness/background-runtime.js +1 -8
- package/dist/runtime/harness/bindings.js +1 -58
- package/dist/runtime/harness/events/event-bus.js +1 -16
- package/dist/runtime/harness/events/event-sink.js +1 -61
- package/dist/runtime/harness/events/events.js +1 -80
- package/dist/runtime/harness/events/listener-runtime.js +1 -13
- package/dist/runtime/harness/events/runtime-event-operations.js +1 -9
- package/dist/runtime/harness/events/streaming.js +1 -100
- package/dist/runtime/harness/events/timeline.js +1 -52
- package/dist/runtime/harness/public-shapes.js +1 -186
- package/dist/runtime/harness/run/artifact-paths.js +1 -15
- package/dist/runtime/harness/run/governance.js +1 -295
- package/dist/runtime/harness/run/helpers.js +1 -71
- package/dist/runtime/harness/run/inspection.js +1 -409
- package/dist/runtime/harness/run/operator-overview.js +1 -80
- package/dist/runtime/harness/run/queue-diagnostics.js +1 -15
- package/dist/runtime/harness/run/recovery.js +1 -162
- package/dist/runtime/harness/run/resources.js +1 -60
- package/dist/runtime/harness/run/resume.js +1 -56
- package/dist/runtime/harness/run/routing.js +1 -48
- package/dist/runtime/harness/run/run-lifecycle.js +1 -66
- package/dist/runtime/harness/run/run-operations.js +1 -217
- package/dist/runtime/harness/run/run-queue.js +1 -43
- package/dist/runtime/harness/run/run-slot-acquisition.js +1 -157
- package/dist/runtime/harness/run/session-records.js +1 -97
- package/dist/runtime/harness/run/start-run.js +1 -120
- package/dist/runtime/harness/run/startup-runtime.js +1 -69
- package/dist/runtime/harness/run/stream-run.js +8 -1418
- package/dist/runtime/harness/run/surface-semantics.js +1 -79
- package/dist/runtime/harness/runtime-defaults.js +1 -39
- package/dist/runtime/harness/system/boundary-analysis.js +1 -234
- package/dist/runtime/harness/system/health-monitor.js +1 -258
- package/dist/runtime/harness/system/inventory.js +1 -129
- package/dist/runtime/harness/system/mem0-ingestion-sync.js +5 -345
- package/dist/runtime/harness/system/policy-engine.js +1 -175
- package/dist/runtime/harness/system/runtime-memory-candidates.js +4 -110
- package/dist/runtime/harness/system/runtime-memory-consolidation.js +1 -51
- package/dist/runtime/harness/system/runtime-memory-manager.js +10 -693
- package/dist/runtime/harness/system/runtime-memory-policy.js +1 -155
- package/dist/runtime/harness/system/runtime-memory-records.js +11 -577
- package/dist/runtime/harness/system/runtime-memory-sync.js +5 -206
- package/dist/runtime/harness/system/session-memory-sync.js +3 -113
- package/dist/runtime/harness/system/skill-requirements.js +1 -112
- package/dist/runtime/harness/system/store.js +9 -365
- package/dist/runtime/harness/tool-gateway/index.js +1 -2
- package/dist/runtime/harness/tool-gateway/policy.js +1 -45
- package/dist/runtime/harness/tool-gateway/validation.js +1 -176
- package/dist/runtime/harness/tool-schema.js +1 -3
- package/dist/runtime/harness.js +3 -1490
- package/dist/runtime/index.js +1 -3
- package/dist/runtime/layout/runtime-layout.js +1 -31
- package/dist/runtime/maintenance/checkpoint-maintenance.js +2 -178
- package/dist/runtime/maintenance/file-checkpoint-saver.js +1 -106
- package/dist/runtime/maintenance/runtime-record-maintenance.js +2 -169
- package/dist/runtime/maintenance/sqlite-checkpoint-saver.js +4 -289
- package/dist/runtime/parsing/output-content.js +10 -550
- package/dist/runtime/parsing/output-parsing.js +1 -4
- package/dist/runtime/parsing/output-recovery.js +3 -213
- package/dist/runtime/parsing/output-tool-args.js +7 -663
- package/dist/runtime/parsing/stream-event-parsing.js +3 -362
- package/dist/runtime/prompts/runtime-prompts.js +4 -73
- package/dist/runtime/scheduling/system-schedule-manager.js +11 -532
- package/dist/runtime/skills/skill-metadata.js +1 -197
- package/dist/runtime/startup-tracing.js +2 -37
- package/dist/runtime/support/compiled-binding.js +1 -290
- package/dist/runtime/support/embedding-models.js +1 -118
- package/dist/runtime/support/harness-support.js +5 -137
- package/dist/runtime/support/llamaindex.js +1 -108
- package/dist/runtime/support/runtime-adapter-options.js +1 -29
- package/dist/runtime/support/runtime-factories.js +1 -51
- package/dist/runtime/support/vector-stores.js +9 -270
- package/dist/scaffold/init-project.js +54 -233
- package/dist/tooling/extensions.js +1 -311
- package/dist/tooling/module-loader.js +1 -55
- package/dist/tools.js +1 -176
- package/dist/utils/agent-display.js +1 -18
- package/dist/utils/bundled-text.js +4 -39
- package/dist/utils/compiled-binding.js +1 -33
- package/dist/utils/fs.js +2 -45
- package/dist/utils/id.js +1 -9
- package/dist/utils/message-content.js +1 -30
- package/dist/utils/object.js +1 -6
- package/dist/workspace/agent-binding-compiler.js +3 -613
- package/dist/workspace/compile.js +1 -472
- package/dist/workspace/framework-contract-validation.js +2 -322
- package/dist/workspace/index.js +1 -1
- package/dist/workspace/object-loader-paths.js +1 -71
- package/dist/workspace/object-loader-readers.js +1 -187
- package/dist/workspace/object-loader.js +1 -754
- package/dist/workspace/resource-compilers.js +1 -374
- package/dist/workspace/support/agent-capabilities.js +1 -37
- package/dist/workspace/support/agent-execution-config.js +1 -44
- package/dist/workspace/support/discovery.js +1 -147
- package/dist/workspace/support/source-collectors.js +1 -30
- package/dist/workspace/support/source-protocols.js +2 -192
- package/dist/workspace/support/workspace-ref-utils.js +1 -362
- package/dist/workspace/tool-hydration.js +1 -280
- package/dist/workspace/validate.js +1 -99
- package/dist/workspace/yaml-object-reader.js +1 -285
- package/package.json +7 -3
|
@@ -1,577 +1,11 @@
|
|
|
1
|
-
import
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
function
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
return value.slice(0, 240);
|
|
13
|
-
}
|
|
14
|
-
function createFingerprint(input) {
|
|
15
|
-
return createHash("sha256").update(input).digest("hex");
|
|
16
|
-
}
|
|
17
|
-
function normalizeConfidence(value) {
|
|
18
|
-
if (typeof value !== "number" || Number.isNaN(value)) {
|
|
19
|
-
return 0.5;
|
|
20
|
-
}
|
|
21
|
-
return Math.min(1, Math.max(0, value));
|
|
22
|
-
}
|
|
23
|
-
function normalizeSourceRef(value) {
|
|
24
|
-
return typeof value === "string" && value.trim().length > 0 ? value.trim() : undefined;
|
|
25
|
-
}
|
|
26
|
-
function normalizeOperationalRule(rule) {
|
|
27
|
-
if (!rule) {
|
|
28
|
-
return undefined;
|
|
29
|
-
}
|
|
30
|
-
const trigger = typeof rule.trigger === "string" ? rule.trigger.trim() : "";
|
|
31
|
-
const action = typeof rule.action === "string" ? rule.action.trim() : "";
|
|
32
|
-
const target = typeof rule.target === "string" ? rule.target.trim() : "";
|
|
33
|
-
if (!trigger || !action || !target) {
|
|
34
|
-
return undefined;
|
|
35
|
-
}
|
|
36
|
-
return {
|
|
37
|
-
trigger,
|
|
38
|
-
action,
|
|
39
|
-
target,
|
|
40
|
-
...(rule.effect === "apply" || rule.effect === "invalidate" ? { effect: rule.effect } : {}),
|
|
41
|
-
};
|
|
42
|
-
}
|
|
43
|
-
function normalizeKnowledgeMutation(mutation) {
|
|
44
|
-
if (!mutation || typeof mutation !== "object") {
|
|
45
|
-
return undefined;
|
|
46
|
-
}
|
|
47
|
-
const identity = typeof mutation.identity === "string" ? mutation.identity.trim() : "";
|
|
48
|
-
if (!identity) {
|
|
49
|
-
return undefined;
|
|
50
|
-
}
|
|
51
|
-
const operation = mutation.operation === "update" || mutation.operation === "delete" ? mutation.operation : "create";
|
|
52
|
-
return { identity, operation };
|
|
53
|
-
}
|
|
54
|
-
function inferKnowledgeMutation(candidate) {
|
|
55
|
-
const explicit = normalizeKnowledgeMutation(candidate.knowledgeMutation);
|
|
56
|
-
if (explicit) {
|
|
57
|
-
return explicit;
|
|
58
|
-
}
|
|
59
|
-
const operationalRule = normalizeOperationalRule(candidate.operationalRule);
|
|
60
|
-
if (operationalRule) {
|
|
61
|
-
return {
|
|
62
|
-
identity: `rule:${createFingerprint([operationalRule.trigger, operationalRule.action, operationalRule.target].join("\n"))}`,
|
|
63
|
-
operation: operationalRule.effect === "invalidate" ? "delete" : "create",
|
|
64
|
-
};
|
|
65
|
-
}
|
|
66
|
-
return undefined;
|
|
67
|
-
}
|
|
68
|
-
function createCanonicalKey(candidate, kind, scope) {
|
|
69
|
-
const knowledgeMutation = normalizeKnowledgeMutation(candidate.knowledgeMutation);
|
|
70
|
-
if (knowledgeMutation) {
|
|
71
|
-
return `${kind}:${scope}:knowledge:${createFingerprint(knowledgeMutation.identity)}`;
|
|
72
|
-
}
|
|
73
|
-
const operationalRule = normalizeOperationalRule(candidate.operationalRule);
|
|
74
|
-
if (operationalRule) {
|
|
75
|
-
return `${kind}:${scope}:rule:${createFingerprint([operationalRule.trigger, operationalRule.action, operationalRule.target].join("\n"))}`;
|
|
76
|
-
}
|
|
77
|
-
const sourceRef = normalizeSourceRef(candidate.sourceRef);
|
|
78
|
-
if (sourceRef) {
|
|
79
|
-
return `${kind}:${scope}:source:${createFingerprint(sourceRef)}`;
|
|
80
|
-
}
|
|
81
|
-
const base = normalizeSummary(candidate).toLowerCase().replace(/\s+/g, " ").trim();
|
|
82
|
-
return `${kind}:${scope}:summary:${createFingerprint(base)}`;
|
|
83
|
-
}
|
|
84
|
-
function buildScopeNamespace(scope) {
|
|
85
|
-
return ["memories", "records", scope];
|
|
86
|
-
}
|
|
87
|
-
function buildCanonicalIndexNamespace(scope) {
|
|
88
|
-
return ["memories", "indexes", "canonical", scope];
|
|
89
|
-
}
|
|
90
|
-
function buildSourceRefIndexNamespace(scope) {
|
|
91
|
-
return ["memories", "indexes", "source-ref", scope];
|
|
92
|
-
}
|
|
93
|
-
function normalizeTextForCompare(value) {
|
|
94
|
-
return value.toLowerCase().replace(/\s+/g, " ").trim();
|
|
95
|
-
}
|
|
96
|
-
function tokenize(value) {
|
|
97
|
-
return new Set(value
|
|
98
|
-
.toLowerCase()
|
|
99
|
-
.split(/[^a-z0-9_]+/i)
|
|
100
|
-
.map((token) => token.trim())
|
|
101
|
-
.filter((token) => token.length > 2));
|
|
102
|
-
}
|
|
103
|
-
function jaccardSimilarity(left, right) {
|
|
104
|
-
const leftTokens = tokenize(left);
|
|
105
|
-
const rightTokens = tokenize(right);
|
|
106
|
-
if (leftTokens.size === 0 || rightTokens.size === 0) {
|
|
107
|
-
return 0;
|
|
108
|
-
}
|
|
109
|
-
let intersection = 0;
|
|
110
|
-
for (const token of leftTokens) {
|
|
111
|
-
if (rightTokens.has(token)) {
|
|
112
|
-
intersection += 1;
|
|
113
|
-
}
|
|
114
|
-
}
|
|
115
|
-
const union = new Set([...leftTokens, ...rightTokens]).size;
|
|
116
|
-
return union === 0 ? 0 : intersection / union;
|
|
117
|
-
}
|
|
118
|
-
function hasNegationSignal(value) {
|
|
119
|
-
const normalized = ` ${normalizeTextForCompare(value)} `;
|
|
120
|
-
return (normalized.includes(" not ") ||
|
|
121
|
-
normalized.includes(" no ") ||
|
|
122
|
-
normalized.includes(" never ") ||
|
|
123
|
-
normalized.includes(" without ") ||
|
|
124
|
-
normalized.includes(" do not ") ||
|
|
125
|
-
normalized.includes(" does not ") ||
|
|
126
|
-
normalized.includes(" did not "));
|
|
127
|
-
}
|
|
128
|
-
function mergeUniqueStrings(left, right) {
|
|
129
|
-
return Array.from(new Set([...left, ...right].filter((item) => item.trim().length > 0)));
|
|
130
|
-
}
|
|
131
|
-
function mergeRecordContent(left, right) {
|
|
132
|
-
const normalizedLeft = normalizeTextForCompare(left);
|
|
133
|
-
const normalizedRight = normalizeTextForCompare(right);
|
|
134
|
-
if (normalizedLeft === normalizedRight) {
|
|
135
|
-
return left;
|
|
136
|
-
}
|
|
137
|
-
if (normalizedLeft.includes(normalizedRight)) {
|
|
138
|
-
return left;
|
|
139
|
-
}
|
|
140
|
-
if (normalizedRight.includes(normalizedLeft)) {
|
|
141
|
-
return right;
|
|
142
|
-
}
|
|
143
|
-
return `${left.trim()}\n\n${right.trim()}`;
|
|
144
|
-
}
|
|
145
|
-
function createMemoryRecord(candidate, options) {
|
|
146
|
-
const kind = normalizeLangMemMemoryKind(candidate.kind);
|
|
147
|
-
const scope = normalizeScope(candidate.scope);
|
|
148
|
-
const canonicalKey = createCanonicalKey(candidate, kind, scope);
|
|
149
|
-
const id = createFingerprint([
|
|
150
|
-
canonicalKey,
|
|
151
|
-
candidate.content.trim(),
|
|
152
|
-
options.sessionId,
|
|
153
|
-
options.requestId,
|
|
154
|
-
options.agentId,
|
|
155
|
-
options.recordedAt,
|
|
156
|
-
].join("\n"));
|
|
157
|
-
const sourceRef = normalizeSourceRef(candidate.sourceRef);
|
|
158
|
-
const operationalRule = normalizeOperationalRule(candidate.operationalRule);
|
|
159
|
-
const knowledgeMutation = inferKnowledgeMutation(candidate);
|
|
160
|
-
return {
|
|
161
|
-
id,
|
|
162
|
-
canonicalKey,
|
|
163
|
-
kind,
|
|
164
|
-
scope,
|
|
165
|
-
content: candidate.content.trim(),
|
|
166
|
-
summary: normalizeSummary(candidate),
|
|
167
|
-
status: "active",
|
|
168
|
-
confidence: normalizeConfidence(candidate.confidence),
|
|
169
|
-
createdAt: options.recordedAt,
|
|
170
|
-
observedAt: candidate.observedAt ?? options.recordedAt,
|
|
171
|
-
lastConfirmedAt: options.recordedAt,
|
|
172
|
-
sourceType: candidate.sourceType?.trim() || "tool-output",
|
|
173
|
-
sourceRefs: sourceRef ? [sourceRef] : [],
|
|
174
|
-
tags: candidate.tags ?? [],
|
|
175
|
-
...(knowledgeMutation
|
|
176
|
-
? {
|
|
177
|
-
knowledgeIdentity: knowledgeMutation.identity,
|
|
178
|
-
knowledgeOperation: knowledgeMutation.operation,
|
|
179
|
-
}
|
|
180
|
-
: {}),
|
|
181
|
-
...(operationalRule ? { operationalRule } : {}),
|
|
182
|
-
provenance: {
|
|
183
|
-
sessionId: options.sessionId,
|
|
184
|
-
requestId: options.requestId,
|
|
185
|
-
agentId: options.agentId,
|
|
186
|
-
workspaceId: options.workspaceId,
|
|
187
|
-
userId: options.userId,
|
|
188
|
-
projectId: options.projectId,
|
|
189
|
-
...(candidate.provenance ?? {}),
|
|
190
|
-
},
|
|
191
|
-
revision: 1,
|
|
192
|
-
supersedes: [],
|
|
193
|
-
conflictsWith: [],
|
|
194
|
-
};
|
|
195
|
-
}
|
|
196
|
-
function isSameRecordContent(left, right) {
|
|
197
|
-
return normalizeTextForCompare(left.content) === normalizeTextForCompare(right.content);
|
|
198
|
-
}
|
|
199
|
-
function refreshRecord(existing, incoming, recordedAt) {
|
|
200
|
-
return {
|
|
201
|
-
...existing,
|
|
202
|
-
summary: incoming.summary.length > existing.summary.length ? incoming.summary : existing.summary,
|
|
203
|
-
confidence: Math.max(existing.confidence, incoming.confidence),
|
|
204
|
-
observedAt: incoming.observedAt,
|
|
205
|
-
lastConfirmedAt: recordedAt,
|
|
206
|
-
sourceRefs: mergeUniqueStrings(existing.sourceRefs, incoming.sourceRefs),
|
|
207
|
-
tags: mergeUniqueStrings(existing.tags, incoming.tags),
|
|
208
|
-
provenance: {
|
|
209
|
-
...existing.provenance,
|
|
210
|
-
refreshedFrom: incoming.provenance,
|
|
211
|
-
lastRefreshRequestId: incoming.provenance.requestId,
|
|
212
|
-
lastRefreshSessionId: incoming.provenance.sessionId,
|
|
213
|
-
},
|
|
214
|
-
revision: existing.revision + 1,
|
|
215
|
-
};
|
|
216
|
-
}
|
|
217
|
-
function mergeRecord(existing, incoming, recordedAt) {
|
|
218
|
-
return {
|
|
219
|
-
...existing,
|
|
220
|
-
content: mergeRecordContent(existing.content, incoming.content),
|
|
221
|
-
summary: incoming.summary.length >= existing.summary.length ? incoming.summary : existing.summary,
|
|
222
|
-
confidence: Math.max(existing.confidence, incoming.confidence),
|
|
223
|
-
observedAt: incoming.observedAt,
|
|
224
|
-
lastConfirmedAt: recordedAt,
|
|
225
|
-
sourceRefs: mergeUniqueStrings(existing.sourceRefs, incoming.sourceRefs),
|
|
226
|
-
tags: mergeUniqueStrings(existing.tags, incoming.tags),
|
|
227
|
-
provenance: {
|
|
228
|
-
...existing.provenance,
|
|
229
|
-
mergedFrom: incoming.provenance,
|
|
230
|
-
lastMergeRequestId: incoming.provenance.requestId,
|
|
231
|
-
lastMergeSessionId: incoming.provenance.sessionId,
|
|
232
|
-
},
|
|
233
|
-
revision: existing.revision + 1,
|
|
234
|
-
};
|
|
235
|
-
}
|
|
236
|
-
function markConflicted(record, conflictingRecordId, recordedAt) {
|
|
237
|
-
return {
|
|
238
|
-
...record,
|
|
239
|
-
status: "conflicted",
|
|
240
|
-
lastConfirmedAt: recordedAt,
|
|
241
|
-
conflictsWith: mergeUniqueStrings(record.conflictsWith, [conflictingRecordId]),
|
|
242
|
-
revision: record.revision + 1,
|
|
243
|
-
};
|
|
244
|
-
}
|
|
245
|
-
function createReviewRecord(existing, incoming, recordedAt) {
|
|
246
|
-
return {
|
|
247
|
-
...incoming,
|
|
248
|
-
status: "pending_review",
|
|
249
|
-
conflictsWith: mergeUniqueStrings(incoming.conflictsWith, [existing.id]),
|
|
250
|
-
lastConfirmedAt: recordedAt,
|
|
251
|
-
};
|
|
252
|
-
}
|
|
253
|
-
function archiveRecord(record, incomingRecordId, recordedAt) {
|
|
254
|
-
return {
|
|
255
|
-
...record,
|
|
256
|
-
status: "archived",
|
|
257
|
-
lastConfirmedAt: recordedAt,
|
|
258
|
-
supersedes: mergeUniqueStrings(record.supersedes, [incomingRecordId]),
|
|
259
|
-
revision: record.revision + 1,
|
|
260
|
-
};
|
|
261
|
-
}
|
|
262
|
-
async function listStoredRecords(store, scope) {
|
|
263
|
-
const scopes = scope ? [scope] : MEMORY_SCOPES;
|
|
264
|
-
const docs = await Promise.all(scopes.map((currentScope) => store.search(buildScopeNamespace(currentScope))));
|
|
265
|
-
return docs
|
|
266
|
-
.flat()
|
|
267
|
-
.map((entry) => entry.value)
|
|
268
|
-
.filter((record) => typeof record?.id === "string" && typeof record.content === "string");
|
|
269
|
-
}
|
|
270
|
-
function findMatchingRecord(existingRecords, incoming) {
|
|
271
|
-
const exact = existingRecords.find((record) => record.scope === incoming.scope && isSameRecordContent(record, incoming));
|
|
272
|
-
if (exact) {
|
|
273
|
-
return exact;
|
|
274
|
-
}
|
|
275
|
-
const sourceRefMatch = existingRecords.find((record) => record.scope === incoming.scope &&
|
|
276
|
-
incoming.sourceRefs.some((sourceRef) => record.sourceRefs.includes(sourceRef)));
|
|
277
|
-
if (sourceRefMatch) {
|
|
278
|
-
return sourceRefMatch;
|
|
279
|
-
}
|
|
280
|
-
return existingRecords.find((record) => record.scope === incoming.scope && record.canonicalKey === incoming.canonicalKey);
|
|
281
|
-
}
|
|
282
|
-
function evaluateDecision(existing, incoming, recordedAt) {
|
|
283
|
-
if (!existing) {
|
|
284
|
-
return {
|
|
285
|
-
decision: {
|
|
286
|
-
action: "store",
|
|
287
|
-
reason: "Stored as a new durable memory record.",
|
|
288
|
-
recordId: incoming.id,
|
|
289
|
-
kind: incoming.kind,
|
|
290
|
-
scope: incoming.scope,
|
|
291
|
-
confidence: incoming.confidence,
|
|
292
|
-
maintenance: "dedupe",
|
|
293
|
-
reviewRequired: false,
|
|
294
|
-
},
|
|
295
|
-
primaryRecord: incoming,
|
|
296
|
-
additionalRecords: [],
|
|
297
|
-
};
|
|
298
|
-
}
|
|
299
|
-
if (isSameRecordContent(existing, incoming)) {
|
|
300
|
-
const refreshed = refreshRecord(existing, incoming, recordedAt);
|
|
301
|
-
return {
|
|
302
|
-
decision: {
|
|
303
|
-
action: "refresh",
|
|
304
|
-
reason: "Refreshed an exact durable memory match.",
|
|
305
|
-
recordId: refreshed.id,
|
|
306
|
-
kind: refreshed.kind,
|
|
307
|
-
scope: refreshed.scope,
|
|
308
|
-
confidence: refreshed.confidence,
|
|
309
|
-
maintenance: "none",
|
|
310
|
-
reviewRequired: false,
|
|
311
|
-
},
|
|
312
|
-
primaryRecord: refreshed,
|
|
313
|
-
additionalRecords: [],
|
|
314
|
-
};
|
|
315
|
-
}
|
|
316
|
-
if (existing.canonicalKey === incoming.canonicalKey ||
|
|
317
|
-
incoming.sourceRefs.some((sourceRef) => existing.sourceRefs.includes(sourceRef))) {
|
|
318
|
-
if (existing.knowledgeIdentity && incoming.knowledgeIdentity && existing.knowledgeIdentity === incoming.knowledgeIdentity) {
|
|
319
|
-
const existingOperation = existing.knowledgeOperation ?? "create";
|
|
320
|
-
const incomingOperation = incoming.knowledgeOperation ?? "create";
|
|
321
|
-
if (existingOperation !== incomingOperation || !isSameRecordContent(existing, incoming)) {
|
|
322
|
-
const archivedExisting = archiveRecord(existing, incoming.id, recordedAt);
|
|
323
|
-
const activeIncoming = {
|
|
324
|
-
...incoming,
|
|
325
|
-
supersedes: mergeUniqueStrings(incoming.supersedes, [existing.id]),
|
|
326
|
-
};
|
|
327
|
-
return {
|
|
328
|
-
decision: {
|
|
329
|
-
action: "supersede",
|
|
330
|
-
reason: "Stored a newer knowledge mutation that supersedes the previous active state.",
|
|
331
|
-
recordId: activeIncoming.id,
|
|
332
|
-
kind: activeIncoming.kind,
|
|
333
|
-
scope: activeIncoming.scope,
|
|
334
|
-
confidence: activeIncoming.confidence,
|
|
335
|
-
maintenance: "merge",
|
|
336
|
-
reviewRequired: false,
|
|
337
|
-
},
|
|
338
|
-
primaryRecord: archivedExisting,
|
|
339
|
-
additionalRecords: [activeIncoming],
|
|
340
|
-
};
|
|
341
|
-
}
|
|
342
|
-
}
|
|
343
|
-
if (hasNegationSignal(existing.content) !== hasNegationSignal(incoming.content)) {
|
|
344
|
-
const conflictedExisting = markConflicted(existing, incoming.id, recordedAt);
|
|
345
|
-
const pendingReview = createReviewRecord(conflictedExisting, incoming, recordedAt);
|
|
346
|
-
return {
|
|
347
|
-
decision: {
|
|
348
|
-
action: "review",
|
|
349
|
-
reason: "Detected conflicting durable memory with the same canonical identity.",
|
|
350
|
-
recordId: pendingReview.id,
|
|
351
|
-
kind: pendingReview.kind,
|
|
352
|
-
scope: pendingReview.scope,
|
|
353
|
-
confidence: pendingReview.confidence,
|
|
354
|
-
maintenance: "review",
|
|
355
|
-
reviewRequired: true,
|
|
356
|
-
},
|
|
357
|
-
primaryRecord: conflictedExisting,
|
|
358
|
-
additionalRecords: [pendingReview],
|
|
359
|
-
};
|
|
360
|
-
}
|
|
361
|
-
const similarity = jaccardSimilarity(existing.summary, incoming.summary);
|
|
362
|
-
if (similarity >= 0.45) {
|
|
363
|
-
const merged = mergeRecord(existing, incoming, recordedAt);
|
|
364
|
-
return {
|
|
365
|
-
decision: {
|
|
366
|
-
action: "merge",
|
|
367
|
-
reason: "Merged a matching durable memory record with compatible additions.",
|
|
368
|
-
recordId: merged.id,
|
|
369
|
-
kind: merged.kind,
|
|
370
|
-
scope: merged.scope,
|
|
371
|
-
confidence: merged.confidence,
|
|
372
|
-
maintenance: "merge",
|
|
373
|
-
reviewRequired: false,
|
|
374
|
-
},
|
|
375
|
-
primaryRecord: merged,
|
|
376
|
-
additionalRecords: [],
|
|
377
|
-
};
|
|
378
|
-
}
|
|
379
|
-
const conflictedExisting = markConflicted(existing, incoming.id, recordedAt);
|
|
380
|
-
const pendingReview = createReviewRecord(conflictedExisting, incoming, recordedAt);
|
|
381
|
-
return {
|
|
382
|
-
decision: {
|
|
383
|
-
action: "review",
|
|
384
|
-
reason: "Detected conflicting durable memory with the same canonical identity.",
|
|
385
|
-
recordId: pendingReview.id,
|
|
386
|
-
kind: pendingReview.kind,
|
|
387
|
-
scope: pendingReview.scope,
|
|
388
|
-
confidence: pendingReview.confidence,
|
|
389
|
-
maintenance: "review",
|
|
390
|
-
reviewRequired: true,
|
|
391
|
-
},
|
|
392
|
-
primaryRecord: conflictedExisting,
|
|
393
|
-
additionalRecords: [pendingReview],
|
|
394
|
-
};
|
|
395
|
-
}
|
|
396
|
-
return {
|
|
397
|
-
decision: {
|
|
398
|
-
action: "store",
|
|
399
|
-
reason: "Stored as a new durable memory record.",
|
|
400
|
-
recordId: incoming.id,
|
|
401
|
-
kind: incoming.kind,
|
|
402
|
-
scope: incoming.scope,
|
|
403
|
-
confidence: incoming.confidence,
|
|
404
|
-
maintenance: "dedupe",
|
|
405
|
-
reviewRequired: false,
|
|
406
|
-
},
|
|
407
|
-
primaryRecord: incoming,
|
|
408
|
-
additionalRecords: [],
|
|
409
|
-
};
|
|
410
|
-
}
|
|
411
|
-
async function putRecordWithIndexes(store, record, updatedAt) {
|
|
412
|
-
const canonicalKeyId = createFingerprint(record.canonicalKey);
|
|
413
|
-
await store.put(buildScopeNamespace(record.scope), `${record.id}.json`, record);
|
|
414
|
-
await store.put(buildCanonicalIndexNamespace(record.scope), `${canonicalKeyId}-${record.id}.json`, {
|
|
415
|
-
canonicalKey: record.canonicalKey,
|
|
416
|
-
recordId: record.id,
|
|
417
|
-
scope: record.scope,
|
|
418
|
-
kind: record.kind,
|
|
419
|
-
updatedAt,
|
|
420
|
-
});
|
|
421
|
-
await Promise.all(record.sourceRefs.map((sourceRef) => {
|
|
422
|
-
const sourceRefId = createFingerprint(sourceRef);
|
|
423
|
-
return store.put(buildSourceRefIndexNamespace(record.scope), `${sourceRefId}-${record.id}.json`, {
|
|
424
|
-
sourceRef,
|
|
425
|
-
recordId: record.id,
|
|
426
|
-
scope: record.scope,
|
|
427
|
-
kind: record.kind,
|
|
428
|
-
updatedAt,
|
|
429
|
-
});
|
|
430
|
-
}));
|
|
431
|
-
}
|
|
432
|
-
export function renderMemoryRecordsMarkdown(title, records) {
|
|
433
|
-
const lines = [`# ${title}`, ""];
|
|
434
|
-
if (records.length === 0) {
|
|
435
|
-
lines.push("(none)", "");
|
|
436
|
-
return lines.join("\n");
|
|
437
|
-
}
|
|
438
|
-
for (const record of records) {
|
|
439
|
-
lines.push(`## ${record.summary}`);
|
|
440
|
-
lines.push(`- kind: ${record.kind}`);
|
|
441
|
-
lines.push(`- scope: ${record.scope}`);
|
|
442
|
-
lines.push(`- status: ${record.status}`);
|
|
443
|
-
lines.push(`- confidence: ${record.confidence.toFixed(2)}`);
|
|
444
|
-
if (record.knowledgeIdentity) {
|
|
445
|
-
lines.push(`- knowledge_identity: ${record.knowledgeIdentity}`);
|
|
446
|
-
lines.push(`- knowledge_operation: ${record.knowledgeOperation ?? "create"}`);
|
|
447
|
-
}
|
|
448
|
-
if (record.operationalRule) {
|
|
449
|
-
lines.push(`- operational_rule: ${record.operationalRule.trigger} -> ${record.operationalRule.action}(${record.operationalRule.target}) [${record.operationalRule.effect ?? "apply"}]`);
|
|
450
|
-
}
|
|
451
|
-
if (record.tags.length > 0) {
|
|
452
|
-
lines.push(`- tags: ${record.tags.join(", ")}`);
|
|
453
|
-
}
|
|
454
|
-
lines.push("");
|
|
455
|
-
lines.push(record.content);
|
|
456
|
-
lines.push("");
|
|
457
|
-
}
|
|
458
|
-
return lines.join("\n");
|
|
459
|
-
}
|
|
460
|
-
export async function rebuildStructuredMemoryProjections(store, namespace, title, scope, maxEntries) {
|
|
461
|
-
const records = (await listStoredRecords(store, scope))
|
|
462
|
-
.filter((record) => record.status === "active")
|
|
463
|
-
.sort((left, right) => left.lastConfirmedAt.localeCompare(right.lastConfirmedAt))
|
|
464
|
-
.slice(-maxEntries);
|
|
465
|
-
await store.put(namespace, "structured-memory.md", {
|
|
466
|
-
content: `${renderMemoryRecordsMarkdown(title, records)}\n`,
|
|
467
|
-
items: records,
|
|
468
|
-
});
|
|
469
|
-
const grouped = new Map();
|
|
470
|
-
for (const record of records) {
|
|
471
|
-
const current = grouped.get(record.kind) ?? [];
|
|
472
|
-
current.push(record);
|
|
473
|
-
grouped.set(record.kind, current);
|
|
474
|
-
}
|
|
475
|
-
await Promise.all(Array.from(grouped.entries()).map(([kind, items]) => store.put(namespace, `${kind}.md`, {
|
|
476
|
-
content: `${renderMemoryRecordsMarkdown(`${title} (${kind})`, items)}\n`,
|
|
477
|
-
items,
|
|
478
|
-
})));
|
|
479
|
-
}
|
|
480
|
-
export async function listMemoryRecordsForScopes(store, scopes) {
|
|
481
|
-
const all = await Promise.all(scopes.map((scope) => listStoredRecords(store, scope)));
|
|
482
|
-
return all.flat();
|
|
483
|
-
}
|
|
484
|
-
export async function getMemoryRecord(store, scope, recordId) {
|
|
485
|
-
const entry = await store.get(buildScopeNamespace(scope), `${recordId}.json`);
|
|
486
|
-
const record = entry?.value;
|
|
487
|
-
if (typeof record !== "object" || !record || Array.isArray(record)) {
|
|
488
|
-
return null;
|
|
489
|
-
}
|
|
490
|
-
const candidate = record;
|
|
491
|
-
return typeof candidate.id === "string" && typeof candidate.content === "string" ? candidate : null;
|
|
492
|
-
}
|
|
493
|
-
export async function findMemoryRecordById(store, recordId) {
|
|
494
|
-
for (const scope of MEMORY_SCOPES) {
|
|
495
|
-
const record = await getMemoryRecord(store, scope, recordId);
|
|
496
|
-
if (record) {
|
|
497
|
-
return record;
|
|
498
|
-
}
|
|
499
|
-
}
|
|
500
|
-
return null;
|
|
501
|
-
}
|
|
502
|
-
async function deleteRecordIndexes(store, record) {
|
|
503
|
-
const [canonicalEntries, sourceRefEntries] = await Promise.all([
|
|
504
|
-
store.search(buildCanonicalIndexNamespace(record.scope)),
|
|
505
|
-
store.search(buildSourceRefIndexNamespace(record.scope)),
|
|
506
|
-
]);
|
|
507
|
-
await Promise.all([
|
|
508
|
-
...canonicalEntries
|
|
509
|
-
.filter((entry) => entry.value?.recordId === record.id)
|
|
510
|
-
.map((entry) => store.delete(entry.namespace, entry.key)),
|
|
511
|
-
...sourceRefEntries
|
|
512
|
-
.filter((entry) => entry.value?.recordId === record.id)
|
|
513
|
-
.map((entry) => store.delete(entry.namespace, entry.key)),
|
|
514
|
-
]);
|
|
515
|
-
}
|
|
516
|
-
export async function updateMemoryRecord(store, record, updatedAt) {
|
|
517
|
-
const existing = await getMemoryRecord(store, record.scope, record.id);
|
|
518
|
-
if (existing) {
|
|
519
|
-
await deleteRecordIndexes(store, existing);
|
|
520
|
-
}
|
|
521
|
-
await putRecordWithIndexes(store, record, updatedAt);
|
|
522
|
-
return record;
|
|
523
|
-
}
|
|
524
|
-
export async function removeMemoryRecord(store, scope, recordId) {
|
|
525
|
-
const existing = await getMemoryRecord(store, scope, recordId);
|
|
526
|
-
if (!existing) {
|
|
527
|
-
return null;
|
|
528
|
-
}
|
|
529
|
-
await deleteRecordIndexes(store, existing);
|
|
530
|
-
await store.delete(buildScopeNamespace(scope), `${recordId}.json`);
|
|
531
|
-
return existing;
|
|
532
|
-
}
|
|
533
|
-
export async function persistStructuredMemoryRecords(options) {
|
|
534
|
-
const sessionId = options.sessionId ?? options.legacySessionId;
|
|
535
|
-
const requestId = options.requestId ?? options.legacyRequestId;
|
|
536
|
-
if (!sessionId || !requestId) {
|
|
537
|
-
throw new Error("persistStructuredMemoryRecords requires sessionId/requestId");
|
|
538
|
-
}
|
|
539
|
-
const existingRecords = await listStoredRecords(options.store);
|
|
540
|
-
const persistedRecords = [];
|
|
541
|
-
const decisions = [];
|
|
542
|
-
for (const candidate of options.candidates) {
|
|
543
|
-
const incoming = createMemoryRecord(candidate, {
|
|
544
|
-
sessionId,
|
|
545
|
-
requestId,
|
|
546
|
-
agentId: options.agentId,
|
|
547
|
-
workspaceId: options.workspaceId,
|
|
548
|
-
userId: options.userId,
|
|
549
|
-
projectId: options.projectId,
|
|
550
|
-
recordedAt: options.recordedAt,
|
|
551
|
-
});
|
|
552
|
-
const existing = findMatchingRecord(existingRecords, incoming);
|
|
553
|
-
const evaluated = evaluateDecision(existing, incoming, options.recordedAt);
|
|
554
|
-
const recordsToWrite = [evaluated.primaryRecord, ...evaluated.additionalRecords];
|
|
555
|
-
for (const record of recordsToWrite) {
|
|
556
|
-
const priorRecord = existingRecords.find((item) => item.id === record.id);
|
|
557
|
-
if (priorRecord) {
|
|
558
|
-
await deleteRecordIndexes(options.store, priorRecord);
|
|
559
|
-
}
|
|
560
|
-
await putRecordWithIndexes(options.store, record, options.recordedAt);
|
|
561
|
-
const existingIndex = existingRecords.findIndex((item) => item.id === record.id);
|
|
562
|
-
if (existingIndex >= 0) {
|
|
563
|
-
existingRecords[existingIndex] = record;
|
|
564
|
-
}
|
|
565
|
-
else {
|
|
566
|
-
existingRecords.push(record);
|
|
567
|
-
}
|
|
568
|
-
}
|
|
569
|
-
await options.store.put(["memories", "decisions", sessionId, requestId], `${evaluated.decision.recordId ?? incoming.id}.json`, evaluated.decision);
|
|
570
|
-
decisions.push(evaluated.decision);
|
|
571
|
-
persistedRecords.push(...recordsToWrite);
|
|
572
|
-
}
|
|
573
|
-
return {
|
|
574
|
-
records: persistedRecords,
|
|
575
|
-
decisions,
|
|
576
|
-
};
|
|
577
|
-
}
|
|
1
|
+
import{createHash as N}from"node:crypto";import{normalizeLangMemMemoryKind as W}from"./runtime-memory-policy.js";const M=["session","agent","workspace","user","project"];function F(e){return e==="agent"||e==="workspace"||e==="user"||e==="project"?e:"session"}function S(e){return(e.summary?.trim()||e.content.trim().split(`
|
|
2
|
+
`)[0]||e.content.trim()).slice(0,240)}function u(e){return N("sha256").update(e).digest("hex")}function T(e){return typeof e!="number"||Number.isNaN(e)?.5:Math.min(1,Math.max(0,e))}function b(e){return typeof e=="string"&&e.trim().length>0?e.trim():void 0}function R(e){if(!e)return;const t=typeof e.trigger=="string"?e.trigger.trim():"",n=typeof e.action=="string"?e.action.trim():"",r=typeof e.target=="string"?e.target.trim():"";if(!(!t||!n||!r))return{trigger:t,action:n,target:r,...e.effect==="apply"||e.effect==="invalidate"?{effect:e.effect}:{}}}function j(e){if(!e||typeof e!="object")return;const t=typeof e.identity=="string"?e.identity.trim():"";if(!t)return;const n=e.operation==="update"||e.operation==="delete"?e.operation:"create";return{identity:t,operation:n}}function _(e){const t=j(e.knowledgeMutation);if(t)return t;const n=R(e.operationalRule);if(n)return{identity:`rule:${u([n.trigger,n.action,n.target].join(`
|
|
3
|
+
`))}`,operation:n.effect==="invalidate"?"delete":"create"}}function L(e,t,n){const r=j(e.knowledgeMutation);if(r)return`${t}:${n}:knowledge:${u(r.identity)}`;const o=R(e.operationalRule);if(o)return`${t}:${n}:rule:${u([o.trigger,o.action,o.target].join(`
|
|
4
|
+
`))}`;const s=b(e.sourceRef);if(s)return`${t}:${n}:source:${u(s)}`;const i=S(e).toLowerCase().replace(/\s+/g," ").trim();return`${t}:${n}:summary:${u(i)}`}function m(e){return["memories","records",e]}function q(e){return["memories","indexes","canonical",e]}function A(e){return["memories","indexes","source-ref",e]}function p(e){return e.toLowerCase().replace(/\s+/g," ").trim()}function C(e){return new Set(e.toLowerCase().split(/[^a-z0-9_]+/i).map(t=>t.trim()).filter(t=>t.length>2))}function D(e,t){const n=C(e),r=C(t);if(n.size===0||r.size===0)return 0;let o=0;for(const i of n)r.has(i)&&(o+=1);const s=new Set([...n,...r]).size;return s===0?0:o/s}function z(e){const t=` ${p(e)} `;return t.includes(" not ")||t.includes(" no ")||t.includes(" never ")||t.includes(" without ")||t.includes(" do not ")||t.includes(" does not ")||t.includes(" did not ")}function f(e,t){return Array.from(new Set([...e,...t].filter(n=>n.trim().length>0)))}function x(e,t){const n=p(e),r=p(t);return n===r||n.includes(r)?e:r.includes(n)?t:`${e.trim()}
|
|
5
|
+
|
|
6
|
+
${t.trim()}`}function B(e,t){const n=W(e.kind),r=F(e.scope),o=L(e,n,r),s=u([o,e.content.trim(),t.sessionId,t.requestId,t.agentId,t.recordedAt].join(`
|
|
7
|
+
`)),i=b(e.sourceRef),c=R(e.operationalRule),a=_(e);return{id:s,canonicalKey:o,kind:n,scope:r,content:e.content.trim(),summary:S(e),status:"active",confidence:T(e.confidence),createdAt:t.recordedAt,observedAt:e.observedAt??t.recordedAt,lastConfirmedAt:t.recordedAt,sourceType:e.sourceType?.trim()||"tool-output",sourceRefs:i?[i]:[],tags:e.tags??[],...a?{knowledgeIdentity:a.identity,knowledgeOperation:a.operation}:{},...c?{operationalRule:c}:{},provenance:{sessionId:t.sessionId,requestId:t.requestId,agentId:t.agentId,workspaceId:t.workspaceId,userId:t.userId,projectId:t.projectId,...e.provenance??{}},revision:1,supersedes:[],conflictsWith:[]}}function w(e,t){return p(e.content)===p(t.content)}function H(e,t,n){return{...e,summary:t.summary.length>e.summary.length?t.summary:e.summary,confidence:Math.max(e.confidence,t.confidence),observedAt:t.observedAt,lastConfirmedAt:n,sourceRefs:f(e.sourceRefs,t.sourceRefs),tags:f(e.tags,t.tags),provenance:{...e.provenance,refreshedFrom:t.provenance,lastRefreshRequestId:t.provenance.requestId,lastRefreshSessionId:t.provenance.sessionId},revision:e.revision+1}}function U(e,t,n){return{...e,content:x(e.content,t.content),summary:t.summary.length>=e.summary.length?t.summary:e.summary,confidence:Math.max(e.confidence,t.confidence),observedAt:t.observedAt,lastConfirmedAt:n,sourceRefs:f(e.sourceRefs,t.sourceRefs),tags:f(e.tags,t.tags),provenance:{...e.provenance,mergedFrom:t.provenance,lastMergeRequestId:t.provenance.requestId,lastMergeSessionId:t.provenance.sessionId},revision:e.revision+1}}function K(e,t,n){return{...e,status:"conflicted",lastConfirmedAt:n,conflictsWith:f(e.conflictsWith,[t]),revision:e.revision+1}}function O(e,t,n){return{...t,status:"pending_review",conflictsWith:f(t.conflictsWith,[e.id]),lastConfirmedAt:n}}function Y(e,t,n){return{...e,status:"archived",lastConfirmedAt:n,supersedes:f(e.supersedes,[t]),revision:e.revision+1}}async function h(e,t){const n=t?[t]:M;return(await Promise.all(n.map(o=>e.search(m(o))))).flat().map(o=>o.value).filter(o=>typeof o?.id=="string"&&typeof o.content=="string")}function G(e,t){const n=e.find(o=>o.scope===t.scope&&w(o,t));if(n)return n;const r=e.find(o=>o.scope===t.scope&&t.sourceRefs.some(s=>o.sourceRefs.includes(s)));return r||e.find(o=>o.scope===t.scope&&o.canonicalKey===t.canonicalKey)}function J(e,t,n){if(!e)return{decision:{action:"store",reason:"Stored as a new durable memory record.",recordId:t.id,kind:t.kind,scope:t.scope,confidence:t.confidence,maintenance:"dedupe",reviewRequired:!1},primaryRecord:t,additionalRecords:[]};if(w(e,t)){const r=H(e,t,n);return{decision:{action:"refresh",reason:"Refreshed an exact durable memory match.",recordId:r.id,kind:r.kind,scope:r.scope,confidence:r.confidence,maintenance:"none",reviewRequired:!1},primaryRecord:r,additionalRecords:[]}}if(e.canonicalKey===t.canonicalKey||t.sourceRefs.some(r=>e.sourceRefs.includes(r))){if(e.knowledgeIdentity&&t.knowledgeIdentity&&e.knowledgeIdentity===t.knowledgeIdentity){const i=e.knowledgeOperation??"create",c=t.knowledgeOperation??"create";if(i!==c||!w(e,t)){const a=Y(e,t.id,n),d={...t,supersedes:f(t.supersedes,[e.id])};return{decision:{action:"supersede",reason:"Stored a newer knowledge mutation that supersedes the previous active state.",recordId:d.id,kind:d.kind,scope:d.scope,confidence:d.confidence,maintenance:"merge",reviewRequired:!1},primaryRecord:a,additionalRecords:[d]}}}if(z(e.content)!==z(t.content)){const i=K(e,t.id,n),c=O(i,t,n);return{decision:{action:"review",reason:"Detected conflicting durable memory with the same canonical identity.",recordId:c.id,kind:c.kind,scope:c.scope,confidence:c.confidence,maintenance:"review",reviewRequired:!0},primaryRecord:i,additionalRecords:[c]}}if(D(e.summary,t.summary)>=.45){const i=U(e,t,n);return{decision:{action:"merge",reason:"Merged a matching durable memory record with compatible additions.",recordId:i.id,kind:i.kind,scope:i.scope,confidence:i.confidence,maintenance:"merge",reviewRequired:!1},primaryRecord:i,additionalRecords:[]}}const o=K(e,t.id,n),s=O(o,t,n);return{decision:{action:"review",reason:"Detected conflicting durable memory with the same canonical identity.",recordId:s.id,kind:s.kind,scope:s.scope,confidence:s.confidence,maintenance:"review",reviewRequired:!0},primaryRecord:o,additionalRecords:[s]}}return{decision:{action:"store",reason:"Stored as a new durable memory record.",recordId:t.id,kind:t.kind,scope:t.scope,confidence:t.confidence,maintenance:"dedupe",reviewRequired:!1},primaryRecord:t,additionalRecords:[]}}async function E(e,t,n){const r=u(t.canonicalKey);await e.put(m(t.scope),`${t.id}.json`,t),await e.put(q(t.scope),`${r}-${t.id}.json`,{canonicalKey:t.canonicalKey,recordId:t.id,scope:t.scope,kind:t.kind,updatedAt:n}),await Promise.all(t.sourceRefs.map(o=>{const s=u(o);return e.put(A(t.scope),`${s}-${t.id}.json`,{sourceRef:o,recordId:t.id,scope:t.scope,kind:t.kind,updatedAt:n})}))}function P(e,t){const n=[`# ${e}`,""];if(t.length===0)return n.push("(none)",""),n.join(`
|
|
8
|
+
`);for(const r of t)n.push(`## ${r.summary}`),n.push(`- kind: ${r.kind}`),n.push(`- scope: ${r.scope}`),n.push(`- status: ${r.status}`),n.push(`- confidence: ${r.confidence.toFixed(2)}`),r.knowledgeIdentity&&(n.push(`- knowledge_identity: ${r.knowledgeIdentity}`),n.push(`- knowledge_operation: ${r.knowledgeOperation??"create"}`)),r.operationalRule&&n.push(`- operational_rule: ${r.operationalRule.trigger} -> ${r.operationalRule.action}(${r.operationalRule.target}) [${r.operationalRule.effect??"apply"}]`),r.tags.length>0&&n.push(`- tags: ${r.tags.join(", ")}`),n.push(""),n.push(r.content),n.push("");return n.join(`
|
|
9
|
+
`)}async function X(e,t,n,r,o){const s=(await h(e,r)).filter(c=>c.status==="active").sort((c,a)=>c.lastConfirmedAt.localeCompare(a.lastConfirmedAt)).slice(-o);await e.put(t,"structured-memory.md",{content:`${P(n,s)}
|
|
10
|
+
`,items:s});const i=new Map;for(const c of s){const a=i.get(c.kind)??[];a.push(c),i.set(c.kind,a)}await Promise.all(Array.from(i.entries()).map(([c,a])=>e.put(t,`${c}.md`,{content:`${P(`${n} (${c})`,a)}
|
|
11
|
+
`,items:a})))}async function Z(e,t){return(await Promise.all(t.map(r=>h(e,r)))).flat()}async function I(e,t,n){const o=(await e.get(m(t),`${n}.json`))?.value;if(typeof o!="object"||!o||Array.isArray(o))return null;const s=o;return typeof s.id=="string"&&typeof s.content=="string"?s:null}async function ee(e,t){for(const n of M){const r=await I(e,n,t);if(r)return r}return null}async function v(e,t){const[n,r]=await Promise.all([e.search(q(t.scope)),e.search(A(t.scope))]);await Promise.all([...n.filter(o=>o.value?.recordId===t.id).map(o=>e.delete(o.namespace,o.key)),...r.filter(o=>o.value?.recordId===t.id).map(o=>e.delete(o.namespace,o.key))])}async function te(e,t,n){const r=await I(e,t.scope,t.id);return r&&await v(e,r),await E(e,t,n),t}async function ne(e,t,n){const r=await I(e,t,n);return r?(await v(e,r),await e.delete(m(t),`${n}.json`),r):null}async function re(e){const t=e.sessionId??e.legacySessionId,n=e.requestId??e.legacyRequestId;if(!t||!n)throw new Error("persistStructuredMemoryRecords requires sessionId/requestId");const r=await h(e.store),o=[],s=[];for(const i of e.candidates){const c=B(i,{sessionId:t,requestId:n,agentId:e.agentId,workspaceId:e.workspaceId,userId:e.userId,projectId:e.projectId,recordedAt:e.recordedAt}),a=G(r,c),d=J(a,c,e.recordedAt),k=[d.primaryRecord,...d.additionalRecords];for(const l of k){const $=r.find(y=>y.id===l.id);$&&await v(e.store,$),await E(e.store,l,e.recordedAt);const g=r.findIndex(y=>y.id===l.id);g>=0?r[g]=l:r.push(l)}await e.store.put(["memories","decisions",t,n],`${d.decision.recordId??c.id}.json`,d.decision),s.push(d.decision),o.push(...k)}return{records:o,decisions:s}}export{ee as findMemoryRecordById,I as getMemoryRecord,Z as listMemoryRecordsForScopes,re as persistStructuredMemoryRecords,X as rebuildStructuredMemoryProjections,ne as removeMemoryRecord,P as renderMemoryRecordsMarkdown,te as updateMemoryRecord};
|