opencode-swarm 7.35.0 → 7.37.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/agents/agent-output-schema.d.ts +9 -1
- package/dist/cli/index.js +801 -27
- package/dist/index.js +4080 -2349
- package/dist/memory/curator-decision-helpers.d.ts +14 -0
- package/dist/memory/gateway.d.ts +5 -1
- package/dist/memory/index.d.ts +2 -2
- package/dist/memory/injector.d.ts +1 -1
- package/dist/memory/local-jsonl-provider.d.ts +4 -1
- package/dist/memory/provider.d.ts +2 -1
- package/dist/memory/run-log.d.ts +1 -1
- package/dist/memory/schema.d.ts +5 -1
- package/dist/memory/sqlite-provider.d.ts +25 -1
- package/dist/memory/types.d.ts +74 -0
- package/dist/sandbox/capability-probe.d.ts +55 -0
- package/dist/sandbox/executor.d.ts +51 -0
- package/dist/sandbox/executors/bubblewrap.d.ts +1 -0
- package/dist/sandbox/executors/macos.d.ts +1 -0
- package/dist/sandbox/executors/windows.d.ts +1 -0
- package/dist/sandbox/linux/bubblewrap-executor.d.ts +79 -0
- package/dist/sandbox/linux/edge-cases.d.ts +89 -0
- package/dist/sandbox/macos/edge-cases.d.ts +89 -0
- package/dist/sandbox/macos/sandbox-exec-executor.d.ts +68 -0
- package/dist/sandbox/scope-resolver.d.ts +32 -0
- package/dist/sandbox/win32/edge-cases.d.ts +90 -0
- package/dist/sandbox/win32/restricted-token-executor.d.ts +94 -0
- package/package.json +1 -1
package/dist/cli/index.js
CHANGED
|
@@ -34,7 +34,7 @@ var package_default;
|
|
|
34
34
|
var init_package = __esm(() => {
|
|
35
35
|
package_default = {
|
|
36
36
|
name: "opencode-swarm",
|
|
37
|
-
version: "7.
|
|
37
|
+
version: "7.37.0",
|
|
38
38
|
description: "Architect-centric agentic swarm plugin for OpenCode - hub-and-spoke orchestration with SME consultation, code generation, and QA review",
|
|
39
39
|
main: "dist/index.js",
|
|
40
40
|
types: "dist/index.d.ts",
|
|
@@ -21402,6 +21402,12 @@ var init_shell_write_detect = __esm(() => {
|
|
|
21402
21402
|
]);
|
|
21403
21403
|
});
|
|
21404
21404
|
|
|
21405
|
+
// src/sandbox/executor.ts
|
|
21406
|
+
var init_executor = () => {};
|
|
21407
|
+
|
|
21408
|
+
// src/sandbox/scope-resolver.ts
|
|
21409
|
+
var init_scope_resolver = () => {};
|
|
21410
|
+
|
|
21405
21411
|
// src/hooks/conflict-resolution.ts
|
|
21406
21412
|
var init_conflict_resolution = __esm(() => {
|
|
21407
21413
|
init_state();
|
|
@@ -21477,6 +21483,8 @@ var init_guardrails = __esm(() => {
|
|
|
21477
21483
|
init_telemetry();
|
|
21478
21484
|
init_utils();
|
|
21479
21485
|
init_shell_write_detect();
|
|
21486
|
+
init_executor();
|
|
21487
|
+
init_scope_resolver();
|
|
21480
21488
|
init_bun_compat();
|
|
21481
21489
|
init_logger();
|
|
21482
21490
|
init_conflict_resolution();
|
|
@@ -45465,7 +45473,7 @@ function validateMemoryRecordRules(record3, options) {
|
|
|
45465
45473
|
function validateMemoryProposal(proposal) {
|
|
45466
45474
|
return MemoryProposalSchema.parse(proposal);
|
|
45467
45475
|
}
|
|
45468
|
-
var MemoryScopeTypeSchema, MemoryScopeRefSchema, MemoryKindSchema, MemorySourceSchema, MemoryRecordSchema, MemoryProposalSchema;
|
|
45476
|
+
var MemoryScopeTypeSchema, MemoryScopeRefSchema, MemoryKindSchema, MemorySourceSchema, MemoryRecordSchema, MemoryProposalSchema, NewMemoryRecordSchema, MemoryPatchSchema, ProposalIdSchema, MemoryIdSchema, CuratorDecisionReasonSchema, CuratorMemoryDecisionSchema;
|
|
45469
45477
|
var init_schema2 = __esm(() => {
|
|
45470
45478
|
init_zod();
|
|
45471
45479
|
init_config3();
|
|
@@ -45572,6 +45580,234 @@ var init_schema2 = __esm(() => {
|
|
|
45572
45580
|
createdAt: exports_external.string().datetime(),
|
|
45573
45581
|
metadata: exports_external.record(exports_external.string(), exports_external.unknown())
|
|
45574
45582
|
}).strict();
|
|
45583
|
+
NewMemoryRecordSchema = exports_external.object({
|
|
45584
|
+
scope: MemoryScopeRefSchema.optional(),
|
|
45585
|
+
kind: MemoryKindSchema,
|
|
45586
|
+
text: exports_external.string().min(1).max(2000),
|
|
45587
|
+
tags: exports_external.array(exports_external.string().min(1).max(64)).max(32).optional(),
|
|
45588
|
+
confidence: exports_external.number().min(0).max(1).optional(),
|
|
45589
|
+
stability: exports_external.enum(["ephemeral", "session", "durable"]).optional(),
|
|
45590
|
+
source: MemorySourceSchema.optional(),
|
|
45591
|
+
expiresAt: exports_external.string().datetime().optional(),
|
|
45592
|
+
metadata: exports_external.record(exports_external.string(), exports_external.unknown()).optional()
|
|
45593
|
+
}).strict();
|
|
45594
|
+
MemoryPatchSchema = exports_external.object({
|
|
45595
|
+
scope: MemoryScopeRefSchema.optional(),
|
|
45596
|
+
kind: MemoryKindSchema.optional(),
|
|
45597
|
+
text: exports_external.string().min(1).max(2000).optional(),
|
|
45598
|
+
tags: exports_external.array(exports_external.string().min(1).max(64)).max(32).optional(),
|
|
45599
|
+
confidence: exports_external.number().min(0).max(1).optional(),
|
|
45600
|
+
stability: exports_external.enum(["ephemeral", "session", "durable"]).optional(),
|
|
45601
|
+
source: MemorySourceSchema.optional(),
|
|
45602
|
+
expiresAt: exports_external.string().datetime().optional(),
|
|
45603
|
+
metadata: exports_external.record(exports_external.string(), exports_external.unknown()).optional()
|
|
45604
|
+
}).strict().refine((patch) => Object.keys(patch).length > 0, {
|
|
45605
|
+
message: "memory patch must not be empty"
|
|
45606
|
+
});
|
|
45607
|
+
ProposalIdSchema = exports_external.string().regex(/^prop_[a-f0-9]{16}$/);
|
|
45608
|
+
MemoryIdSchema = exports_external.string().regex(/^mem_[a-f0-9]{16}$/);
|
|
45609
|
+
CuratorDecisionReasonSchema = exports_external.string().min(1).max(2000);
|
|
45610
|
+
CuratorMemoryDecisionSchema = exports_external.discriminatedUnion("action", [
|
|
45611
|
+
exports_external.object({
|
|
45612
|
+
action: exports_external.literal("add"),
|
|
45613
|
+
proposalId: ProposalIdSchema,
|
|
45614
|
+
memory: NewMemoryRecordSchema
|
|
45615
|
+
}).strict(),
|
|
45616
|
+
exports_external.object({
|
|
45617
|
+
action: exports_external.literal("update"),
|
|
45618
|
+
proposalId: ProposalIdSchema,
|
|
45619
|
+
targetMemoryId: MemoryIdSchema,
|
|
45620
|
+
patch: MemoryPatchSchema,
|
|
45621
|
+
reason: CuratorDecisionReasonSchema
|
|
45622
|
+
}).strict(),
|
|
45623
|
+
exports_external.object({
|
|
45624
|
+
action: exports_external.literal("supersede"),
|
|
45625
|
+
proposalId: ProposalIdSchema,
|
|
45626
|
+
oldMemoryId: MemoryIdSchema,
|
|
45627
|
+
replacement: NewMemoryRecordSchema,
|
|
45628
|
+
reason: CuratorDecisionReasonSchema
|
|
45629
|
+
}).strict(),
|
|
45630
|
+
exports_external.object({
|
|
45631
|
+
action: exports_external.literal("reject"),
|
|
45632
|
+
proposalId: ProposalIdSchema,
|
|
45633
|
+
reason: CuratorDecisionReasonSchema
|
|
45634
|
+
}).strict(),
|
|
45635
|
+
exports_external.object({
|
|
45636
|
+
action: exports_external.literal("noop"),
|
|
45637
|
+
proposalId: ProposalIdSchema,
|
|
45638
|
+
reason: CuratorDecisionReasonSchema
|
|
45639
|
+
}).strict()
|
|
45640
|
+
]);
|
|
45641
|
+
});
|
|
45642
|
+
|
|
45643
|
+
// src/memory/curator-decision-helpers.ts
|
|
45644
|
+
function validateDecisionMatchesProposal(decision, proposal) {
|
|
45645
|
+
if (decision.action === "add" && proposal.operation !== "add" || decision.action === "update" && proposal.operation !== "update" || decision.action === "supersede" && proposal.operation !== "supersede") {
|
|
45646
|
+
throw new MemoryValidationError(`curator ${decision.action} decision does not match ${proposal.operation} proposal`);
|
|
45647
|
+
}
|
|
45648
|
+
if (decision.action === "update" && proposal.targetMemoryId && proposal.targetMemoryId !== decision.targetMemoryId) {
|
|
45649
|
+
throw new MemoryValidationError("curator update decision target does not match proposal target");
|
|
45650
|
+
}
|
|
45651
|
+
if (decision.action === "supersede" && proposal.targetMemoryId && proposal.targetMemoryId !== decision.oldMemoryId) {
|
|
45652
|
+
throw new MemoryValidationError("curator supersede decision target does not match proposal target");
|
|
45653
|
+
}
|
|
45654
|
+
}
|
|
45655
|
+
function applyPatchToMemory(existing, patch, updatedAt) {
|
|
45656
|
+
const base = {
|
|
45657
|
+
scope: patch.scope ?? existing.scope,
|
|
45658
|
+
kind: patch.kind ?? existing.kind,
|
|
45659
|
+
text: patch.text === undefined ? existing.text : normalizeMemoryText(patch.text)
|
|
45660
|
+
};
|
|
45661
|
+
const tags = patch.tags === undefined ? existing.tags : normalizeTags(patch.tags);
|
|
45662
|
+
return {
|
|
45663
|
+
...existing,
|
|
45664
|
+
...patch,
|
|
45665
|
+
...base,
|
|
45666
|
+
id: createMemoryId(base),
|
|
45667
|
+
tags,
|
|
45668
|
+
updatedAt,
|
|
45669
|
+
contentHash: computeMemoryContentHash(base),
|
|
45670
|
+
metadata: patch.metadata === undefined ? existing.metadata : { ...existing.metadata, ...patch.metadata }
|
|
45671
|
+
};
|
|
45672
|
+
}
|
|
45673
|
+
function markProposalReviewed(proposal, decision, status, reviewedAt, ids) {
|
|
45674
|
+
const reason = curatorDecisionReason(decision);
|
|
45675
|
+
return validateMemoryProposal({
|
|
45676
|
+
...proposal,
|
|
45677
|
+
status,
|
|
45678
|
+
reviewer: "curator_agent",
|
|
45679
|
+
reviewedAt,
|
|
45680
|
+
rejectionReason: decision.action === "reject" ? reason : undefined,
|
|
45681
|
+
metadata: {
|
|
45682
|
+
...proposal.metadata,
|
|
45683
|
+
curatorDecision: {
|
|
45684
|
+
action: decision.action,
|
|
45685
|
+
reason,
|
|
45686
|
+
...ids,
|
|
45687
|
+
appliedAt: reviewedAt
|
|
45688
|
+
}
|
|
45689
|
+
}
|
|
45690
|
+
});
|
|
45691
|
+
}
|
|
45692
|
+
function curatorDecisionReason(decision) {
|
|
45693
|
+
switch (decision.action) {
|
|
45694
|
+
case "add":
|
|
45695
|
+
return;
|
|
45696
|
+
case "update":
|
|
45697
|
+
case "supersede":
|
|
45698
|
+
case "reject":
|
|
45699
|
+
case "noop":
|
|
45700
|
+
return decision.reason;
|
|
45701
|
+
}
|
|
45702
|
+
}
|
|
45703
|
+
function buildCuratorDecisionEvent(change, proposal) {
|
|
45704
|
+
return {
|
|
45705
|
+
...change,
|
|
45706
|
+
proposalOperation: proposal.operation
|
|
45707
|
+
};
|
|
45708
|
+
}
|
|
45709
|
+
function normalizeTags(tags) {
|
|
45710
|
+
return Array.from(new Set(tags.map((tag) => tag.toLowerCase().replace(/[^\w-]/g, "-").replace(/-+/g, "-").replace(/^-|-$/g, "")).filter(Boolean))).slice(0, 32);
|
|
45711
|
+
}
|
|
45712
|
+
var init_curator_decision_helpers = __esm(() => {
|
|
45713
|
+
init_errors6();
|
|
45714
|
+
init_schema2();
|
|
45715
|
+
});
|
|
45716
|
+
|
|
45717
|
+
// src/memory/role-profiles.ts
|
|
45718
|
+
function resolveMemoryRecallProfile(agentRole) {
|
|
45719
|
+
const role = normalizeMemoryAgentRole(agentRole);
|
|
45720
|
+
return MEMORY_RECALL_PROFILES[role] ?? MEMORY_RECALL_PROFILES.coder;
|
|
45721
|
+
}
|
|
45722
|
+
function normalizeMemoryAgentRole(agentRole) {
|
|
45723
|
+
const base = stripKnownSwarmPrefix(agentRole ?? "architect");
|
|
45724
|
+
if (base === "reviewer" || base === "test_engineer")
|
|
45725
|
+
return "qa";
|
|
45726
|
+
if (base === "critic" || base === "critic_sounding_board" || base === "critic_drift_verifier" || base === "critic_hallucination_verifier") {
|
|
45727
|
+
return "security";
|
|
45728
|
+
}
|
|
45729
|
+
if (base === "curator_init" || base === "curator_phase")
|
|
45730
|
+
return "curator";
|
|
45731
|
+
if (base === "docs")
|
|
45732
|
+
return "sme";
|
|
45733
|
+
if (base === "architect" || base === "sme" || base === "coder" || base === "security" || base === "curator") {
|
|
45734
|
+
return base;
|
|
45735
|
+
}
|
|
45736
|
+
return "coder";
|
|
45737
|
+
}
|
|
45738
|
+
var MEMORY_RECALL_PROFILES;
|
|
45739
|
+
var init_role_profiles = __esm(() => {
|
|
45740
|
+
init_schema();
|
|
45741
|
+
MEMORY_RECALL_PROFILES = {
|
|
45742
|
+
architect: {
|
|
45743
|
+
kinds: [
|
|
45744
|
+
"project_fact",
|
|
45745
|
+
"architecture_decision",
|
|
45746
|
+
"repo_convention",
|
|
45747
|
+
"failure_pattern",
|
|
45748
|
+
"security_note"
|
|
45749
|
+
],
|
|
45750
|
+
maxItems: 10,
|
|
45751
|
+
tokenBudget: 1600
|
|
45752
|
+
},
|
|
45753
|
+
sme: {
|
|
45754
|
+
kinds: [
|
|
45755
|
+
"api_finding",
|
|
45756
|
+
"code_pattern",
|
|
45757
|
+
"repo_convention",
|
|
45758
|
+
"failure_pattern",
|
|
45759
|
+
"evidence"
|
|
45760
|
+
],
|
|
45761
|
+
maxItems: 8,
|
|
45762
|
+
tokenBudget: 1200
|
|
45763
|
+
},
|
|
45764
|
+
coder: {
|
|
45765
|
+
kinds: [
|
|
45766
|
+
"architecture_decision",
|
|
45767
|
+
"repo_convention",
|
|
45768
|
+
"code_pattern",
|
|
45769
|
+
"test_pattern",
|
|
45770
|
+
"failure_pattern"
|
|
45771
|
+
],
|
|
45772
|
+
maxItems: 8,
|
|
45773
|
+
tokenBudget: 1200
|
|
45774
|
+
},
|
|
45775
|
+
qa: {
|
|
45776
|
+
kinds: [
|
|
45777
|
+
"test_pattern",
|
|
45778
|
+
"failure_pattern",
|
|
45779
|
+
"repo_convention",
|
|
45780
|
+
"security_note"
|
|
45781
|
+
],
|
|
45782
|
+
maxItems: 8,
|
|
45783
|
+
tokenBudget: 1200
|
|
45784
|
+
},
|
|
45785
|
+
security: {
|
|
45786
|
+
kinds: [
|
|
45787
|
+
"security_note",
|
|
45788
|
+
"architecture_decision",
|
|
45789
|
+
"repo_convention",
|
|
45790
|
+
"evidence"
|
|
45791
|
+
],
|
|
45792
|
+
maxItems: 8,
|
|
45793
|
+
tokenBudget: 1200
|
|
45794
|
+
},
|
|
45795
|
+
curator: {
|
|
45796
|
+
kinds: [
|
|
45797
|
+
"project_fact",
|
|
45798
|
+
"architecture_decision",
|
|
45799
|
+
"repo_convention",
|
|
45800
|
+
"api_finding",
|
|
45801
|
+
"code_pattern",
|
|
45802
|
+
"test_pattern",
|
|
45803
|
+
"failure_pattern",
|
|
45804
|
+
"security_note",
|
|
45805
|
+
"evidence"
|
|
45806
|
+
],
|
|
45807
|
+
maxItems: 20,
|
|
45808
|
+
tokenBudget: 3000
|
|
45809
|
+
}
|
|
45810
|
+
};
|
|
45575
45811
|
});
|
|
45576
45812
|
|
|
45577
45813
|
// src/memory/scoring.ts
|
|
@@ -45627,13 +45863,16 @@ function kindProfileBoost(kind, request) {
|
|
|
45627
45863
|
return 0.5;
|
|
45628
45864
|
return request.kinds.includes(kind) ? 1 : 0;
|
|
45629
45865
|
}
|
|
45866
|
+
function roleProfileBoost(kind, context) {
|
|
45867
|
+
return context.roleProfileKinds?.has(kind) ? 1 : 0;
|
|
45868
|
+
}
|
|
45630
45869
|
function sameScope(a, b) {
|
|
45631
45870
|
return stableScopeKey(a) === stableScopeKey(b);
|
|
45632
45871
|
}
|
|
45633
45872
|
function scopeAllowed(recordScope, allowedScopes) {
|
|
45634
45873
|
return allowedScopes.some((scope) => sameScope(recordScope, scope));
|
|
45635
45874
|
}
|
|
45636
|
-
function scoreMemoryRecordDetailed(record3, request) {
|
|
45875
|
+
function scoreMemoryRecordDetailed(record3, request, context) {
|
|
45637
45876
|
if (!request.includeExpired && isExpired(record3)) {
|
|
45638
45877
|
return { item: null, skipReason: "filtered" };
|
|
45639
45878
|
}
|
|
@@ -45648,7 +45887,7 @@ function scoreMemoryRecordDetailed(record3, request) {
|
|
|
45648
45887
|
if (request.kinds && !request.kinds.includes(record3.kind)) {
|
|
45649
45888
|
return { item: null, skipReason: "filtered" };
|
|
45650
45889
|
}
|
|
45651
|
-
const queryTokens = request.mode === "injection" &&
|
|
45890
|
+
const queryTokens = request.mode === "injection" && context.taskTokens ? context.taskTokens : context.queryTokens;
|
|
45652
45891
|
const textTokens = tokenize(record3.text);
|
|
45653
45892
|
const tagTokens = tokenize(record3.tags.join(" "));
|
|
45654
45893
|
const fileTokens = tokenize([
|
|
@@ -45661,24 +45900,31 @@ function scoreMemoryRecordDetailed(record3, request) {
|
|
|
45661
45900
|
])
|
|
45662
45901
|
].filter((value) => typeof value === "string").join(" "));
|
|
45663
45902
|
const symbolTokens = tokenize(collectMetadataStrings(record3.metadata, ["symbol", "symbols"]).join(" "));
|
|
45664
|
-
const
|
|
45903
|
+
const kindTokens = tokenize(normalizeKindText(record3.kind));
|
|
45904
|
+
const sourceRefTokens = tokenize(record3.source.ref ?? "");
|
|
45905
|
+
const taskSearchTokens = unionTokens(textTokens, tagTokens, fileTokens, symbolTokens, kindTokens, sourceRefTokens);
|
|
45906
|
+
const taskTermOverlap = context.taskTokens ? overlap(context.taskTokens, taskSearchTokens) : 0;
|
|
45907
|
+
const kindQueryOverlap = overlap(queryTokens, kindTokens);
|
|
45665
45908
|
const textOverlap = overlap(queryTokens, textTokens);
|
|
45666
45909
|
const tagOverlap = overlap(queryTokens, tagTokens);
|
|
45667
45910
|
const fileOverlap = overlap(queryTokens, fileTokens);
|
|
45668
45911
|
const symbolOverlap = overlap(queryTokens, symbolTokens);
|
|
45669
45912
|
const kindMatch = request.kinds?.includes(record3.kind) ?? false;
|
|
45670
45913
|
const scopeMatch = scopeAllowed(record3.scope, request.scopes);
|
|
45914
|
+
const roleBoost = roleProfileBoost(record3.kind, context);
|
|
45671
45915
|
const hasQuerySignal = textOverlap > 0 || tagOverlap > 0 || fileOverlap > 0 || symbolOverlap > 0 || kindQueryOverlap > 0;
|
|
45672
45916
|
if (request.mode === "injection" && request.requireQuerySignal !== false && !hasQuerySignal) {
|
|
45673
45917
|
return { item: null, skipReason: "no_signal" };
|
|
45674
45918
|
}
|
|
45675
|
-
const score = textOverlap * 0.
|
|
45919
|
+
const score = textOverlap * 0.38 + tagOverlap * 0.16 + fileOverlap * 0.12 + symbolOverlap * 0.08 + taskTermOverlap * 0.08 + scopeSpecificityBoost(record3.scope) * 0.12 + kindProfileBoost(record3.kind, request) * 0.06 + roleBoost * 0.05 + record3.confidence * 0.08;
|
|
45676
45920
|
const reasonParts = [
|
|
45677
45921
|
textOverlap > 0 ? `text_overlap=${textOverlap.toFixed(2)}` : null,
|
|
45678
45922
|
tagOverlap > 0 ? `tag_overlap=${tagOverlap.toFixed(2)}` : null,
|
|
45679
45923
|
fileOverlap > 0 ? `file_overlap=${fileOverlap.toFixed(2)}` : null,
|
|
45680
45924
|
symbolOverlap > 0 ? `symbol_overlap=${symbolOverlap.toFixed(2)}` : null,
|
|
45925
|
+
taskTermOverlap > 0 ? `task_terms=${taskTermOverlap.toFixed(2)}` : null,
|
|
45681
45926
|
kindQueryOverlap > 0 ? `kind_query=${kindQueryOverlap.toFixed(2)}` : null,
|
|
45927
|
+
roleBoost > 0 ? "role_profile" : null,
|
|
45682
45928
|
`scope=${record3.scope.type}`,
|
|
45683
45929
|
`confidence=${record3.confidence.toFixed(2)}`
|
|
45684
45930
|
].filter(Boolean);
|
|
@@ -45700,6 +45946,7 @@ function scoreMemoryRecordDetailed(record3, request) {
|
|
|
45700
45946
|
}
|
|
45701
45947
|
function scoreMemoryRecordsWithDiagnostics(records, request) {
|
|
45702
45948
|
const minScore = request.minScore ?? 0;
|
|
45949
|
+
const context = createScoringContext(request);
|
|
45703
45950
|
const diagnostics = {
|
|
45704
45951
|
candidateCount: records.length,
|
|
45705
45952
|
preScoredFilteredCount: 0,
|
|
@@ -45710,7 +45957,7 @@ function scoreMemoryRecordsWithDiagnostics(records, request) {
|
|
|
45710
45957
|
};
|
|
45711
45958
|
const items = [];
|
|
45712
45959
|
for (const record3 of records) {
|
|
45713
|
-
const result = scoreMemoryRecordDetailed(record3, request);
|
|
45960
|
+
const result = scoreMemoryRecordDetailed(record3, request, context);
|
|
45714
45961
|
if (!result.item) {
|
|
45715
45962
|
if (result.skipReason === "filtered")
|
|
45716
45963
|
diagnostics.preScoredFilteredCount++;
|
|
@@ -45729,7 +45976,24 @@ function scoreMemoryRecordsWithDiagnostics(records, request) {
|
|
|
45729
45976
|
diagnostics.returnedCount = items.length;
|
|
45730
45977
|
return { items, diagnostics };
|
|
45731
45978
|
}
|
|
45979
|
+
function createScoringContext(request) {
|
|
45980
|
+
const taskTokens = request.task ? tokenize(request.task) : undefined;
|
|
45981
|
+
return {
|
|
45982
|
+
taskTokens,
|
|
45983
|
+
queryTokens: tokenize(request.query),
|
|
45984
|
+
roleProfileKinds: request.agentRole ? new Set(resolveMemoryRecallProfile(request.agentRole).kinds) : undefined
|
|
45985
|
+
};
|
|
45986
|
+
}
|
|
45987
|
+
function unionTokens(...sets) {
|
|
45988
|
+
const union3 = new Set;
|
|
45989
|
+
for (const set3 of sets) {
|
|
45990
|
+
for (const token of set3)
|
|
45991
|
+
union3.add(token);
|
|
45992
|
+
}
|
|
45993
|
+
return union3;
|
|
45994
|
+
}
|
|
45732
45995
|
var init_scoring = __esm(() => {
|
|
45996
|
+
init_role_profiles();
|
|
45733
45997
|
init_schema2();
|
|
45734
45998
|
});
|
|
45735
45999
|
|
|
@@ -45887,21 +46151,126 @@ class LocalJsonlMemoryProvider {
|
|
|
45887
46151
|
proposals.sort((a, b) => b.createdAt.localeCompare(a.createdAt));
|
|
45888
46152
|
return proposals.slice(0, filter.limit ?? proposals.length);
|
|
45889
46153
|
}
|
|
46154
|
+
async applyCuratorDecision(decision) {
|
|
46155
|
+
await this.initialize();
|
|
46156
|
+
const appliedAt = new Date().toISOString();
|
|
46157
|
+
const proposal = this.proposals.get(decision.proposalId);
|
|
46158
|
+
if (!proposal) {
|
|
46159
|
+
throw new MemoryValidationError("memory proposal was not found");
|
|
46160
|
+
}
|
|
46161
|
+
if (proposal.status !== "pending") {
|
|
46162
|
+
throw new MemoryValidationError("memory proposal is not pending");
|
|
46163
|
+
}
|
|
46164
|
+
validateDecisionMatchesProposal(decision, proposal);
|
|
46165
|
+
let memoryId;
|
|
46166
|
+
let targetMemoryId;
|
|
46167
|
+
let oldMemoryId;
|
|
46168
|
+
let replacementMemoryId;
|
|
46169
|
+
if (decision.action === "add") {
|
|
46170
|
+
const memory = this.validateDecisionMemory({
|
|
46171
|
+
...decision.memory,
|
|
46172
|
+
updatedAt: appliedAt
|
|
46173
|
+
});
|
|
46174
|
+
this.memories.set(memory.id, memory);
|
|
46175
|
+
await appendJsonl(this.pathFor("memories"), memory);
|
|
46176
|
+
memoryId = memory.id;
|
|
46177
|
+
} else if (decision.action === "update") {
|
|
46178
|
+
const existing = this.activeMemory(decision.targetMemoryId);
|
|
46179
|
+
const updated = this.validateDecisionMemory(applyPatchToMemory(existing, decision.patch, appliedAt));
|
|
46180
|
+
if (updated.id !== existing.id) {
|
|
46181
|
+
const tombstone = this.validateDecisionMemory({
|
|
46182
|
+
...existing,
|
|
46183
|
+
updatedAt: appliedAt,
|
|
46184
|
+
metadata: {
|
|
46185
|
+
...existing.metadata,
|
|
46186
|
+
deleted: true,
|
|
46187
|
+
deleteReason: decision.reason,
|
|
46188
|
+
updateReplacementId: updated.id
|
|
46189
|
+
}
|
|
46190
|
+
});
|
|
46191
|
+
this.memories.set(tombstone.id, tombstone);
|
|
46192
|
+
await appendJsonl(this.pathFor("memories"), tombstone);
|
|
46193
|
+
}
|
|
46194
|
+
this.memories.set(updated.id, updated);
|
|
46195
|
+
await appendJsonl(this.pathFor("memories"), updated);
|
|
46196
|
+
memoryId = updated.id;
|
|
46197
|
+
targetMemoryId = existing.id;
|
|
46198
|
+
} else if (decision.action === "supersede") {
|
|
46199
|
+
const oldMemory = this.activeMemory(decision.oldMemoryId);
|
|
46200
|
+
const replacement = this.validateDecisionMemory({
|
|
46201
|
+
...decision.replacement,
|
|
46202
|
+
updatedAt: appliedAt,
|
|
46203
|
+
supersedes: Array.from(new Set([...decision.replacement.supersedes ?? [], oldMemory.id]))
|
|
46204
|
+
});
|
|
46205
|
+
const superseded = this.validateDecisionMemory({
|
|
46206
|
+
...oldMemory,
|
|
46207
|
+
updatedAt: appliedAt,
|
|
46208
|
+
supersededBy: replacement.id,
|
|
46209
|
+
metadata: {
|
|
46210
|
+
...oldMemory.metadata,
|
|
46211
|
+
supersedeReason: decision.reason
|
|
46212
|
+
}
|
|
46213
|
+
});
|
|
46214
|
+
this.memories.set(superseded.id, superseded);
|
|
46215
|
+
this.memories.set(replacement.id, replacement);
|
|
46216
|
+
await appendJsonl(this.pathFor("memories"), superseded);
|
|
46217
|
+
await appendJsonl(this.pathFor("memories"), replacement);
|
|
46218
|
+
oldMemoryId = oldMemory.id;
|
|
46219
|
+
replacementMemoryId = replacement.id;
|
|
46220
|
+
memoryId = replacement.id;
|
|
46221
|
+
}
|
|
46222
|
+
const proposalStatus = decision.action === "reject" ? "rejected" : "applied";
|
|
46223
|
+
const reviewedProposal = markProposalReviewed(proposal, decision, proposalStatus, appliedAt, { memoryId, targetMemoryId, oldMemoryId, replacementMemoryId });
|
|
46224
|
+
this.proposals.set(reviewedProposal.id, reviewedProposal);
|
|
46225
|
+
await appendJsonl(this.pathFor("proposals"), reviewedProposal);
|
|
46226
|
+
const change = {
|
|
46227
|
+
action: decision.action,
|
|
46228
|
+
proposalId: decision.proposalId,
|
|
46229
|
+
proposalStatus,
|
|
46230
|
+
appliedAt,
|
|
46231
|
+
memoryId,
|
|
46232
|
+
targetMemoryId,
|
|
46233
|
+
oldMemoryId,
|
|
46234
|
+
replacementMemoryId,
|
|
46235
|
+
reason: curatorDecisionReason(decision)
|
|
46236
|
+
};
|
|
46237
|
+
await this.audit("curator_decision", decision.proposalId, change.reason, buildCuratorDecisionEvent(change, proposal));
|
|
46238
|
+
return change;
|
|
46239
|
+
}
|
|
45890
46240
|
async compact() {
|
|
45891
46241
|
await this.initialize();
|
|
45892
46242
|
await writeJsonlAtomic(this.pathFor("memories"), Array.from(this.memories.values()));
|
|
45893
46243
|
await this.audit("compact", "memories");
|
|
45894
46244
|
}
|
|
45895
|
-
async audit(operation, targetId, reason) {
|
|
46245
|
+
async audit(operation, targetId, reason, eventJson) {
|
|
45896
46246
|
const event = {
|
|
45897
46247
|
id: randomUUID3(),
|
|
45898
46248
|
operation,
|
|
45899
46249
|
targetId,
|
|
45900
46250
|
reason,
|
|
46251
|
+
eventJson,
|
|
45901
46252
|
timestamp: new Date().toISOString()
|
|
45902
46253
|
};
|
|
45903
46254
|
await appendJsonl(this.pathFor("audit"), event);
|
|
45904
46255
|
}
|
|
46256
|
+
activeMemory(memoryId) {
|
|
46257
|
+
const memory = this.memories.get(memoryId);
|
|
46258
|
+
if (!memory) {
|
|
46259
|
+
throw new MemoryValidationError("target memory was not found");
|
|
46260
|
+
}
|
|
46261
|
+
if (memory.metadata.deleted === true) {
|
|
46262
|
+
throw new MemoryValidationError("target memory is deleted");
|
|
46263
|
+
}
|
|
46264
|
+
if (memory.supersededBy) {
|
|
46265
|
+
throw new MemoryValidationError("target memory is superseded");
|
|
46266
|
+
}
|
|
46267
|
+
return memory;
|
|
46268
|
+
}
|
|
46269
|
+
validateDecisionMemory(record3) {
|
|
46270
|
+
return validateMemoryRecordRules(record3, {
|
|
46271
|
+
rejectDurableSecrets: this.config.redaction.rejectDurableSecrets
|
|
46272
|
+
});
|
|
46273
|
+
}
|
|
45905
46274
|
}
|
|
45906
46275
|
function validateLoadedMemories(values, config3) {
|
|
45907
46276
|
const records = [];
|
|
@@ -45968,6 +46337,7 @@ async function writeJsonlAtomic(filePath, values) {
|
|
|
45968
46337
|
var init_local_jsonl_provider = __esm(() => {
|
|
45969
46338
|
init_utils2();
|
|
45970
46339
|
init_config3();
|
|
46340
|
+
init_curator_decision_helpers();
|
|
45971
46341
|
init_errors6();
|
|
45972
46342
|
init_schema2();
|
|
45973
46343
|
init_scoring();
|
|
@@ -46198,6 +46568,7 @@ class SQLiteMemoryProvider {
|
|
|
46198
46568
|
config;
|
|
46199
46569
|
initialized = false;
|
|
46200
46570
|
db = null;
|
|
46571
|
+
ftsAvailable = false;
|
|
46201
46572
|
memories = new Map;
|
|
46202
46573
|
proposals = new Map;
|
|
46203
46574
|
lastAutomaticJsonlMigration = null;
|
|
@@ -46245,6 +46616,7 @@ class SQLiteMemoryProvider {
|
|
|
46245
46616
|
this.db.run(`PRAGMA busy_timeout = ${busyTimeoutMs};`);
|
|
46246
46617
|
this.db.run("PRAGMA foreign_keys = ON;");
|
|
46247
46618
|
this.runMigrations();
|
|
46619
|
+
this.ftsAvailable = this.initializeFtsIndex();
|
|
46248
46620
|
this.lastAutomaticJsonlMigration = null;
|
|
46249
46621
|
await this.migrateLegacyJsonlIfNeeded();
|
|
46250
46622
|
const memoryLoad = this.loadMemories();
|
|
@@ -46286,6 +46658,7 @@ class SQLiteMemoryProvider {
|
|
|
46286
46658
|
if (this.config.hardDelete) {
|
|
46287
46659
|
this.memories.delete(id);
|
|
46288
46660
|
this.requireDb().run("DELETE FROM memory_items WHERE id = ?", [id]);
|
|
46661
|
+
this.deleteMemoryFts(id);
|
|
46289
46662
|
} else {
|
|
46290
46663
|
const tombstone = {
|
|
46291
46664
|
...existing,
|
|
@@ -46302,17 +46675,19 @@ class SQLiteMemoryProvider {
|
|
|
46302
46675
|
}
|
|
46303
46676
|
async recallWithDiagnostics(request) {
|
|
46304
46677
|
await this.initialize();
|
|
46305
|
-
const
|
|
46678
|
+
const scopedRecords = await this.list({
|
|
46306
46679
|
scopes: request.scopes,
|
|
46307
46680
|
kinds: request.kinds,
|
|
46308
46681
|
includeExpired: request.includeExpired
|
|
46309
46682
|
});
|
|
46310
|
-
const
|
|
46683
|
+
const candidates = this.selectRecallCandidates(request, scopedRecords);
|
|
46684
|
+
const result = scoreMemoryRecordsWithDiagnostics(candidates.records, request);
|
|
46685
|
+
const reranked = candidates.ftsOrder ? rerankWithFts(result.items, candidates.ftsOrder) : result.items;
|
|
46311
46686
|
return {
|
|
46312
|
-
items:
|
|
46687
|
+
items: reranked.slice(0, request.maxItems),
|
|
46313
46688
|
diagnostics: {
|
|
46314
46689
|
...result.diagnostics,
|
|
46315
|
-
returnedCount: Math.min(
|
|
46690
|
+
returnedCount: Math.min(reranked.length, request.maxItems)
|
|
46316
46691
|
}
|
|
46317
46692
|
};
|
|
46318
46693
|
}
|
|
@@ -46370,11 +46745,39 @@ class SQLiteMemoryProvider {
|
|
|
46370
46745
|
proposals.sort((a, b) => b.createdAt.localeCompare(a.createdAt));
|
|
46371
46746
|
return proposals.slice(0, filter.limit ?? proposals.length);
|
|
46372
46747
|
}
|
|
46748
|
+
async applyCuratorDecision(decision) {
|
|
46749
|
+
await this.initialize();
|
|
46750
|
+
const db = this.requireDb();
|
|
46751
|
+
const apply = db.transaction(() => {
|
|
46752
|
+
const appliedAt = new Date().toISOString();
|
|
46753
|
+
const proposal = this.readPendingProposal(decision.proposalId);
|
|
46754
|
+
validateDecisionMatchesProposal(decision, proposal);
|
|
46755
|
+
const result2 = this.applyDecisionToStorage(decision, proposal, appliedAt);
|
|
46756
|
+
this.writeProposal(result2.proposal);
|
|
46757
|
+
const eventId = randomUUID4();
|
|
46758
|
+
const eventJson = JSON.stringify(buildCuratorDecisionEvent(result2.change, proposal));
|
|
46759
|
+
this.insertEvent("curator_decision", decision.proposalId, result2.change.reason, eventJson, eventId);
|
|
46760
|
+
return {
|
|
46761
|
+
...result2,
|
|
46762
|
+
change: { ...result2.change, eventId }
|
|
46763
|
+
};
|
|
46764
|
+
});
|
|
46765
|
+
const result = apply();
|
|
46766
|
+
this.proposals.set(result.proposal.id, result.proposal);
|
|
46767
|
+
for (const id of result.removeMemoryIds) {
|
|
46768
|
+
this.memories.delete(id);
|
|
46769
|
+
}
|
|
46770
|
+
for (const memory of result.memories) {
|
|
46771
|
+
this.memories.set(memory.id, memory);
|
|
46772
|
+
}
|
|
46773
|
+
return result.change;
|
|
46774
|
+
}
|
|
46373
46775
|
close() {
|
|
46374
46776
|
if (!this.db)
|
|
46375
46777
|
return;
|
|
46376
46778
|
this.db.close();
|
|
46377
46779
|
this.db = null;
|
|
46780
|
+
this.ftsAvailable = false;
|
|
46378
46781
|
this.initialized = false;
|
|
46379
46782
|
this.lastAutomaticJsonlMigration = null;
|
|
46380
46783
|
}
|
|
@@ -46404,6 +46807,38 @@ class SQLiteMemoryProvider {
|
|
|
46404
46807
|
markMigration(version4, name) {
|
|
46405
46808
|
this.requireDb().run("INSERT OR IGNORE INTO schema_migrations (version, name) VALUES (?, ?)", [version4, name]);
|
|
46406
46809
|
}
|
|
46810
|
+
selectRecallCandidates(request, scopedRecords) {
|
|
46811
|
+
const ftsQuery = buildFtsQuery(request);
|
|
46812
|
+
if (!this.ftsAvailable || !ftsQuery) {
|
|
46813
|
+
return { records: scopedRecords, usedFts: false };
|
|
46814
|
+
}
|
|
46815
|
+
const scopedIds = new Set(scopedRecords.map((record3) => record3.id));
|
|
46816
|
+
if (scopedIds.size === 0) {
|
|
46817
|
+
return { records: [], usedFts: true, ftsOrder: new Map };
|
|
46818
|
+
}
|
|
46819
|
+
try {
|
|
46820
|
+
const rows = this.requireDb().query(`SELECT id, bm25(${FTS_TABLE_NAME}) AS rank
|
|
46821
|
+
FROM ${FTS_TABLE_NAME}
|
|
46822
|
+
WHERE ${FTS_TABLE_NAME} MATCH ?
|
|
46823
|
+
AND id IN (SELECT value FROM json_each(?))
|
|
46824
|
+
ORDER BY rank ASC
|
|
46825
|
+
LIMIT ?`).all(ftsQuery, JSON.stringify(Array.from(scopedIds)), Math.max(100, request.maxItems * 20));
|
|
46826
|
+
const ftsOrder = new Map;
|
|
46827
|
+
for (const row of rows) {
|
|
46828
|
+
if (!scopedIds.has(row.id))
|
|
46829
|
+
continue;
|
|
46830
|
+
ftsOrder.set(row.id, ftsOrder.size);
|
|
46831
|
+
}
|
|
46832
|
+
if (ftsOrder.size === 0 && (request.mode ?? "manual") === "manual") {
|
|
46833
|
+
return { records: scopedRecords, usedFts: false };
|
|
46834
|
+
}
|
|
46835
|
+
const records = scopedRecords.filter((record3) => ftsOrder.has(record3.id));
|
|
46836
|
+
return { records, usedFts: true, ftsOrder };
|
|
46837
|
+
} catch {
|
|
46838
|
+
this.ftsAvailable = false;
|
|
46839
|
+
return { records: scopedRecords, usedFts: false };
|
|
46840
|
+
}
|
|
46841
|
+
}
|
|
46407
46842
|
runMigrations() {
|
|
46408
46843
|
const db = this.requireDb();
|
|
46409
46844
|
db.run(`CREATE TABLE IF NOT EXISTS schema_migrations (
|
|
@@ -46429,16 +46864,82 @@ class SQLiteMemoryProvider {
|
|
|
46429
46864
|
apply();
|
|
46430
46865
|
}
|
|
46431
46866
|
}
|
|
46867
|
+
initializeFtsIndex() {
|
|
46868
|
+
const db = this.requireDb();
|
|
46869
|
+
try {
|
|
46870
|
+
if (!this.hasMigration(FTS_SCHEMA_MIGRATION_NAME)) {
|
|
46871
|
+
this.recreateFtsIndex();
|
|
46872
|
+
this.markMigration(FTS_SCHEMA_MIGRATION_VERSION, FTS_SCHEMA_MIGRATION_NAME);
|
|
46873
|
+
this.insertEvent("migration", String(FTS_SCHEMA_MIGRATION_VERSION), FTS_SCHEMA_MIGRATION_NAME);
|
|
46874
|
+
} else {
|
|
46875
|
+
db.run(`CREATE VIRTUAL TABLE IF NOT EXISTS ${FTS_TABLE_NAME} USING fts5(
|
|
46876
|
+
${ftsCreateColumnsSql()}
|
|
46877
|
+
)`);
|
|
46878
|
+
}
|
|
46879
|
+
this.ftsAvailable = true;
|
|
46880
|
+
const validMemoryCount = this.countValidMemoryRows();
|
|
46881
|
+
const ftsCount = db.query(`SELECT COUNT(*) AS count FROM ${FTS_TABLE_NAME}`).get()?.count ?? 0;
|
|
46882
|
+
if (validMemoryCount !== ftsCount) {
|
|
46883
|
+
this.rebuildFtsIndex();
|
|
46884
|
+
}
|
|
46885
|
+
return true;
|
|
46886
|
+
} catch {
|
|
46887
|
+
this.ftsAvailable = false;
|
|
46888
|
+
return false;
|
|
46889
|
+
}
|
|
46890
|
+
}
|
|
46891
|
+
recreateFtsIndex() {
|
|
46892
|
+
const db = this.requireDb();
|
|
46893
|
+
const recreate = db.transaction(() => {
|
|
46894
|
+
db.run(`DROP TABLE IF EXISTS ${FTS_TABLE_NAME}`);
|
|
46895
|
+
db.run(`CREATE VIRTUAL TABLE ${FTS_TABLE_NAME} USING fts5(
|
|
46896
|
+
${ftsCreateColumnsSql()}
|
|
46897
|
+
)`);
|
|
46898
|
+
});
|
|
46899
|
+
recreate();
|
|
46900
|
+
}
|
|
46901
|
+
rebuildFtsIndex() {
|
|
46902
|
+
const db = this.requireDb();
|
|
46903
|
+
const rebuild = db.transaction(() => {
|
|
46904
|
+
db.run(`DELETE FROM ${FTS_TABLE_NAME}`);
|
|
46905
|
+
for (const row of this.iterateMemoryRows()) {
|
|
46906
|
+
const record3 = this.parseMemoryRow(row);
|
|
46907
|
+
if (record3) {
|
|
46908
|
+
this.writeMemoryFts(record3);
|
|
46909
|
+
}
|
|
46910
|
+
}
|
|
46911
|
+
});
|
|
46912
|
+
rebuild();
|
|
46913
|
+
}
|
|
46914
|
+
countValidMemoryRows() {
|
|
46915
|
+
let count = 0;
|
|
46916
|
+
for (const row of this.iterateMemoryRows()) {
|
|
46917
|
+
if (this.parseMemoryRow(row))
|
|
46918
|
+
count++;
|
|
46919
|
+
}
|
|
46920
|
+
return count;
|
|
46921
|
+
}
|
|
46922
|
+
*iterateMemoryRows() {
|
|
46923
|
+
yield* this.requireDb().query("SELECT id, record_json FROM memory_items").iterate();
|
|
46924
|
+
}
|
|
46925
|
+
parseMemoryRow(row) {
|
|
46926
|
+
try {
|
|
46927
|
+
return validateMemoryRecordRules(JSON.parse(row.record_json), {
|
|
46928
|
+
rejectDurableSecrets: this.config.redaction.rejectDurableSecrets
|
|
46929
|
+
});
|
|
46930
|
+
} catch {
|
|
46931
|
+
return null;
|
|
46932
|
+
}
|
|
46933
|
+
}
|
|
46432
46934
|
loadMemories() {
|
|
46433
46935
|
const rows = this.requireDb().query("SELECT id, record_json FROM memory_items ORDER BY updated_at ASC").all();
|
|
46434
46936
|
const records = [];
|
|
46435
46937
|
let invalidCount = 0;
|
|
46436
46938
|
for (const row of rows) {
|
|
46437
|
-
|
|
46438
|
-
|
|
46439
|
-
|
|
46440
|
-
|
|
46441
|
-
} catch {
|
|
46939
|
+
const record3 = this.parseMemoryRow(row);
|
|
46940
|
+
if (record3) {
|
|
46941
|
+
records.push(record3);
|
|
46942
|
+
} else {
|
|
46442
46943
|
invalidCount++;
|
|
46443
46944
|
}
|
|
46444
46945
|
}
|
|
@@ -46483,6 +46984,29 @@ class SQLiteMemoryProvider {
|
|
|
46483
46984
|
record3.metadata.deleted === true ? 1 : 0,
|
|
46484
46985
|
JSON.stringify(record3)
|
|
46485
46986
|
]);
|
|
46987
|
+
this.writeMemoryFts(record3);
|
|
46988
|
+
}
|
|
46989
|
+
writeMemoryFts(record3) {
|
|
46990
|
+
if (!this.ftsAvailable)
|
|
46991
|
+
return;
|
|
46992
|
+
try {
|
|
46993
|
+
const db = this.requireDb();
|
|
46994
|
+
db.run(`DELETE FROM ${FTS_TABLE_NAME} WHERE id = ?`, [record3.id]);
|
|
46995
|
+
db.run(`INSERT INTO ${FTS_TABLE_NAME} (
|
|
46996
|
+
${FTS_INSERT_COLUMNS.join(", ")}
|
|
46997
|
+
) VALUES (${FTS_INSERT_COLUMNS.map(() => "?").join(", ")})`, [record3.id, ...ftsColumnValues(record3)]);
|
|
46998
|
+
} catch {
|
|
46999
|
+
this.ftsAvailable = false;
|
|
47000
|
+
}
|
|
47001
|
+
}
|
|
47002
|
+
deleteMemoryFts(id) {
|
|
47003
|
+
if (!this.ftsAvailable)
|
|
47004
|
+
return;
|
|
47005
|
+
try {
|
|
47006
|
+
this.requireDb().run(`DELETE FROM ${FTS_TABLE_NAME} WHERE id = ?`, [id]);
|
|
47007
|
+
} catch {
|
|
47008
|
+
this.ftsAvailable = false;
|
|
47009
|
+
}
|
|
46486
47010
|
}
|
|
46487
47011
|
writeProposal(proposal) {
|
|
46488
47012
|
this.requireDb().run(`INSERT OR REPLACE INTO memory_proposals (
|
|
@@ -46497,6 +47021,125 @@ class SQLiteMemoryProvider {
|
|
|
46497
47021
|
JSON.stringify(proposal)
|
|
46498
47022
|
]);
|
|
46499
47023
|
}
|
|
47024
|
+
applyDecisionToStorage(decision, proposal, appliedAt) {
|
|
47025
|
+
const memories = [];
|
|
47026
|
+
const removeMemoryIds = [];
|
|
47027
|
+
let memoryId;
|
|
47028
|
+
let targetMemoryId;
|
|
47029
|
+
let oldMemoryId;
|
|
47030
|
+
let replacementMemoryId;
|
|
47031
|
+
if (decision.action === "add") {
|
|
47032
|
+
const memory = this.validateDecisionMemory({
|
|
47033
|
+
...decision.memory,
|
|
47034
|
+
updatedAt: appliedAt
|
|
47035
|
+
});
|
|
47036
|
+
this.writeMemory(memory);
|
|
47037
|
+
memories.push(memory);
|
|
47038
|
+
memoryId = memory.id;
|
|
47039
|
+
} else if (decision.action === "update") {
|
|
47040
|
+
const existing = this.readActiveMemory(decision.targetMemoryId);
|
|
47041
|
+
const updated = this.validateDecisionMemory(applyPatchToMemory(existing, decision.patch, appliedAt));
|
|
47042
|
+
if (updated.id !== existing.id) {
|
|
47043
|
+
const tombstone = this.validateDecisionMemory({
|
|
47044
|
+
...existing,
|
|
47045
|
+
updatedAt: appliedAt,
|
|
47046
|
+
metadata: {
|
|
47047
|
+
...existing.metadata,
|
|
47048
|
+
deleted: true,
|
|
47049
|
+
deleteReason: decision.reason,
|
|
47050
|
+
updateReplacementId: updated.id
|
|
47051
|
+
}
|
|
47052
|
+
});
|
|
47053
|
+
this.writeMemory(tombstone);
|
|
47054
|
+
memories.push(tombstone);
|
|
47055
|
+
}
|
|
47056
|
+
this.writeMemory(updated);
|
|
47057
|
+
memories.push(updated);
|
|
47058
|
+
memoryId = updated.id;
|
|
47059
|
+
targetMemoryId = existing.id;
|
|
47060
|
+
} else if (decision.action === "supersede") {
|
|
47061
|
+
const oldMemory = this.readActiveMemory(decision.oldMemoryId);
|
|
47062
|
+
const replacement = this.validateDecisionMemory({
|
|
47063
|
+
...decision.replacement,
|
|
47064
|
+
updatedAt: appliedAt,
|
|
47065
|
+
supersedes: Array.from(new Set([...decision.replacement.supersedes ?? [], oldMemory.id]))
|
|
47066
|
+
});
|
|
47067
|
+
const superseded = this.validateDecisionMemory({
|
|
47068
|
+
...oldMemory,
|
|
47069
|
+
updatedAt: appliedAt,
|
|
47070
|
+
supersededBy: replacement.id,
|
|
47071
|
+
metadata: {
|
|
47072
|
+
...oldMemory.metadata,
|
|
47073
|
+
supersedeReason: decision.reason
|
|
47074
|
+
}
|
|
47075
|
+
});
|
|
47076
|
+
this.writeMemory(superseded);
|
|
47077
|
+
this.writeMemory(replacement);
|
|
47078
|
+
memories.push(superseded, replacement);
|
|
47079
|
+
oldMemoryId = oldMemory.id;
|
|
47080
|
+
replacementMemoryId = replacement.id;
|
|
47081
|
+
memoryId = replacement.id;
|
|
47082
|
+
}
|
|
47083
|
+
const proposalStatus = decision.action === "reject" ? "rejected" : "applied";
|
|
47084
|
+
const reviewedProposal = markProposalReviewed(proposal, decision, proposalStatus, appliedAt, {
|
|
47085
|
+
memoryId,
|
|
47086
|
+
targetMemoryId,
|
|
47087
|
+
oldMemoryId,
|
|
47088
|
+
replacementMemoryId
|
|
47089
|
+
});
|
|
47090
|
+
const change = {
|
|
47091
|
+
action: decision.action,
|
|
47092
|
+
proposalId: decision.proposalId,
|
|
47093
|
+
proposalStatus,
|
|
47094
|
+
appliedAt,
|
|
47095
|
+
memoryId,
|
|
47096
|
+
targetMemoryId,
|
|
47097
|
+
oldMemoryId,
|
|
47098
|
+
replacementMemoryId,
|
|
47099
|
+
reason: curatorDecisionReason(decision)
|
|
47100
|
+
};
|
|
47101
|
+
return {
|
|
47102
|
+
change,
|
|
47103
|
+
proposal: reviewedProposal,
|
|
47104
|
+
memories,
|
|
47105
|
+
removeMemoryIds
|
|
47106
|
+
};
|
|
47107
|
+
}
|
|
47108
|
+
readPendingProposal(proposalId) {
|
|
47109
|
+
const row = this.requireDb().query("SELECT id, proposal_json FROM memory_proposals WHERE id = ? LIMIT 1").get(proposalId);
|
|
47110
|
+
if (!row) {
|
|
47111
|
+
throw new MemoryValidationError("memory proposal was not found");
|
|
47112
|
+
}
|
|
47113
|
+
const proposal = validateMemoryProposal(JSON.parse(row.proposal_json));
|
|
47114
|
+
if (proposal.status !== "pending") {
|
|
47115
|
+
throw new MemoryValidationError("memory proposal is not pending");
|
|
47116
|
+
}
|
|
47117
|
+
if (proposal.proposedRecord) {
|
|
47118
|
+
validateMemoryRecordRules(proposal.proposedRecord, {
|
|
47119
|
+
rejectDurableSecrets: this.config.redaction.rejectDurableSecrets
|
|
47120
|
+
});
|
|
47121
|
+
}
|
|
47122
|
+
return proposal;
|
|
47123
|
+
}
|
|
47124
|
+
readActiveMemory(memoryId) {
|
|
47125
|
+
const row = this.requireDb().query("SELECT id, record_json FROM memory_items WHERE id = ? LIMIT 1").get(memoryId);
|
|
47126
|
+
if (!row) {
|
|
47127
|
+
throw new MemoryValidationError("target memory was not found");
|
|
47128
|
+
}
|
|
47129
|
+
const memory = this.validateDecisionMemory(JSON.parse(row.record_json));
|
|
47130
|
+
if (memory.metadata.deleted === true) {
|
|
47131
|
+
throw new MemoryValidationError("target memory is deleted");
|
|
47132
|
+
}
|
|
47133
|
+
if (memory.supersededBy) {
|
|
47134
|
+
throw new MemoryValidationError("target memory is superseded");
|
|
47135
|
+
}
|
|
47136
|
+
return memory;
|
|
47137
|
+
}
|
|
47138
|
+
validateDecisionMemory(record3) {
|
|
47139
|
+
return validateMemoryRecordRules(record3, {
|
|
47140
|
+
rejectDurableSecrets: this.config.redaction.rejectDurableSecrets
|
|
47141
|
+
});
|
|
47142
|
+
}
|
|
46500
47143
|
async migrateLegacyJsonlIfNeeded() {
|
|
46501
47144
|
if (this.hasMigration(LEGACY_JSONL_MIGRATION_NAME))
|
|
46502
47145
|
return;
|
|
@@ -46538,7 +47181,7 @@ class SQLiteMemoryProvider {
|
|
|
46538
47181
|
async event(operation, targetId, reason) {
|
|
46539
47182
|
this.insertEvent(operation, targetId, reason);
|
|
46540
47183
|
}
|
|
46541
|
-
insertEvent(operation, targetId, reason) {
|
|
47184
|
+
insertEvent(operation, targetId, reason, eventJson, id = randomUUID4()) {
|
|
46542
47185
|
this.requireDb().run(`INSERT INTO memory_events (
|
|
46543
47186
|
id,
|
|
46544
47187
|
operation,
|
|
@@ -46547,12 +47190,12 @@ class SQLiteMemoryProvider {
|
|
|
46547
47190
|
timestamp,
|
|
46548
47191
|
event_json
|
|
46549
47192
|
) VALUES (?, ?, ?, ?, ?, ?)`, [
|
|
46550
|
-
|
|
47193
|
+
id,
|
|
46551
47194
|
operation,
|
|
46552
47195
|
targetId,
|
|
46553
47196
|
reason ?? null,
|
|
46554
47197
|
new Date().toISOString(),
|
|
46555
|
-
reason ? JSON.stringify({ reason }) : null
|
|
47198
|
+
eventJson ?? (reason ? JSON.stringify({ reason }) : null)
|
|
46556
47199
|
]);
|
|
46557
47200
|
}
|
|
46558
47201
|
requireDb() {
|
|
@@ -46564,14 +47207,116 @@ class SQLiteMemoryProvider {
|
|
|
46564
47207
|
function splitSql(sql) {
|
|
46565
47208
|
return sql.split(";").map((statement) => statement.trim()).filter(Boolean);
|
|
46566
47209
|
}
|
|
46567
|
-
|
|
47210
|
+
function buildFtsQuery(request) {
|
|
47211
|
+
const text = request.mode === "injection" && request.task ? `${request.task}
|
|
47212
|
+
${request.query}` : `${request.query}
|
|
47213
|
+
${request.task ?? ""}`;
|
|
47214
|
+
const terms = Array.from(extractFtsTerms(text)).slice(0, 40);
|
|
47215
|
+
if (terms.length === 0)
|
|
47216
|
+
return null;
|
|
47217
|
+
return terms.map((term) => `"${term}"`).join(" OR ");
|
|
47218
|
+
}
|
|
47219
|
+
function extractFtsTerms(text) {
|
|
47220
|
+
const terms = new Set;
|
|
47221
|
+
for (const match of text.toLowerCase().matchAll(/[a-z0-9_]{2,}/g)) {
|
|
47222
|
+
const term = match[0];
|
|
47223
|
+
if (FTS_STOP_WORDS.has(term))
|
|
47224
|
+
continue;
|
|
47225
|
+
if (term.length < 3 && !/^\d+$/.test(term))
|
|
47226
|
+
continue;
|
|
47227
|
+
terms.add(term);
|
|
47228
|
+
}
|
|
47229
|
+
return terms;
|
|
47230
|
+
}
|
|
47231
|
+
function ftsCreateColumnsSql() {
|
|
47232
|
+
return [
|
|
47233
|
+
"id UNINDEXED",
|
|
47234
|
+
...FTS_INDEX_COLUMNS.map((column) => column.name)
|
|
47235
|
+
].join(`,
|
|
47236
|
+
`);
|
|
47237
|
+
}
|
|
47238
|
+
function ftsColumnValues(record3) {
|
|
47239
|
+
return FTS_INDEX_COLUMNS.map((column) => column.value(record3));
|
|
47240
|
+
}
|
|
47241
|
+
function collectMetadataSearchStrings(metadata, keys) {
|
|
47242
|
+
const values = [];
|
|
47243
|
+
for (const key of keys) {
|
|
47244
|
+
const value = metadata[key];
|
|
47245
|
+
if (typeof value === "string") {
|
|
47246
|
+
values.push(value);
|
|
47247
|
+
continue;
|
|
47248
|
+
}
|
|
47249
|
+
if (!Array.isArray(value))
|
|
47250
|
+
continue;
|
|
47251
|
+
for (const item of value) {
|
|
47252
|
+
if (typeof item === "string")
|
|
47253
|
+
values.push(item);
|
|
47254
|
+
}
|
|
47255
|
+
}
|
|
47256
|
+
return values;
|
|
47257
|
+
}
|
|
47258
|
+
function rerankWithFts(items, ftsOrder) {
|
|
47259
|
+
const denominator = Math.max(ftsOrder.size, 1);
|
|
47260
|
+
return items.map((item) => {
|
|
47261
|
+
const order = ftsOrder.get(item.record.id);
|
|
47262
|
+
if (order === undefined)
|
|
47263
|
+
return item;
|
|
47264
|
+
const ftsBoost = (denominator - order) / denominator * 0.08;
|
|
47265
|
+
return {
|
|
47266
|
+
...item,
|
|
47267
|
+
score: item.score + ftsBoost,
|
|
47268
|
+
reason: `${item.reason}, fts_rank=${order + 1}`
|
|
47269
|
+
};
|
|
47270
|
+
}).sort((a, b) => b.score - a.score || a.record.id.localeCompare(b.record.id));
|
|
47271
|
+
}
|
|
47272
|
+
var _DatabaseCtor2 = null, FTS_SCHEMA_MIGRATION_VERSION = 3, FTS_SCHEMA_MIGRATION_NAME = "create_memory_fts5_shadow_index", FTS_TABLE_NAME = "memory_items_fts", FTS_INDEX_COLUMNS, FTS_INSERT_COLUMNS, MIGRATIONS2, FTS_STOP_WORDS;
|
|
46568
47273
|
var init_sqlite_provider = __esm(() => {
|
|
46569
47274
|
init_utils2();
|
|
46570
47275
|
init_config3();
|
|
47276
|
+
init_curator_decision_helpers();
|
|
46571
47277
|
init_errors6();
|
|
46572
47278
|
init_jsonl_migration();
|
|
46573
47279
|
init_schema2();
|
|
46574
47280
|
init_scoring();
|
|
47281
|
+
FTS_INDEX_COLUMNS = [
|
|
47282
|
+
{
|
|
47283
|
+
name: "text",
|
|
47284
|
+
value: (record3) => record3.text
|
|
47285
|
+
},
|
|
47286
|
+
{
|
|
47287
|
+
name: "tags",
|
|
47288
|
+
value: (record3) => record3.tags.join(" ")
|
|
47289
|
+
},
|
|
47290
|
+
{
|
|
47291
|
+
name: "kind",
|
|
47292
|
+
value: (record3) => record3.kind.replace(/_/g, " ")
|
|
47293
|
+
},
|
|
47294
|
+
{
|
|
47295
|
+
name: "source_file_path",
|
|
47296
|
+
value: (record3) => record3.source.filePath ?? ""
|
|
47297
|
+
},
|
|
47298
|
+
{
|
|
47299
|
+
name: "source_ref",
|
|
47300
|
+
value: (record3) => record3.source.ref ?? ""
|
|
47301
|
+
},
|
|
47302
|
+
{
|
|
47303
|
+
name: "metadata_symbols",
|
|
47304
|
+
value: (record3) => collectMetadataSearchStrings(record3.metadata, ["symbol", "symbols"]).join(" ")
|
|
47305
|
+
},
|
|
47306
|
+
{
|
|
47307
|
+
name: "metadata_files",
|
|
47308
|
+
value: (record3) => collectMetadataSearchStrings(record3.metadata, [
|
|
47309
|
+
"file",
|
|
47310
|
+
"filePath",
|
|
47311
|
+
"files",
|
|
47312
|
+
"touchedFiles"
|
|
47313
|
+
]).join(" ")
|
|
47314
|
+
}
|
|
47315
|
+
];
|
|
47316
|
+
FTS_INSERT_COLUMNS = [
|
|
47317
|
+
"id",
|
|
47318
|
+
...FTS_INDEX_COLUMNS.map((column) => column.name)
|
|
47319
|
+
];
|
|
46575
47320
|
MIGRATIONS2 = [
|
|
46576
47321
|
{
|
|
46577
47322
|
version: 1,
|
|
@@ -46621,6 +47366,37 @@ var init_sqlite_provider = __esm(() => {
|
|
|
46621
47366
|
`
|
|
46622
47367
|
}
|
|
46623
47368
|
];
|
|
47369
|
+
FTS_STOP_WORDS = new Set([
|
|
47370
|
+
"a",
|
|
47371
|
+
"an",
|
|
47372
|
+
"and",
|
|
47373
|
+
"are",
|
|
47374
|
+
"as",
|
|
47375
|
+
"at",
|
|
47376
|
+
"be",
|
|
47377
|
+
"by",
|
|
47378
|
+
"for",
|
|
47379
|
+
"from",
|
|
47380
|
+
"goal",
|
|
47381
|
+
"how",
|
|
47382
|
+
"in",
|
|
47383
|
+
"into",
|
|
47384
|
+
"is",
|
|
47385
|
+
"it",
|
|
47386
|
+
"of",
|
|
47387
|
+
"on",
|
|
47388
|
+
"or",
|
|
47389
|
+
"role",
|
|
47390
|
+
"task",
|
|
47391
|
+
"that",
|
|
47392
|
+
"the",
|
|
47393
|
+
"this",
|
|
47394
|
+
"to",
|
|
47395
|
+
"user",
|
|
47396
|
+
"what",
|
|
47397
|
+
"when",
|
|
47398
|
+
"with"
|
|
47399
|
+
]);
|
|
46624
47400
|
});
|
|
46625
47401
|
|
|
46626
47402
|
// src/memory/gateway.ts
|
|
@@ -46643,7 +47419,7 @@ var init_gateway = __esm(() => {
|
|
|
46643
47419
|
});
|
|
46644
47420
|
|
|
46645
47421
|
// src/agents/agent-output-schema.ts
|
|
46646
|
-
var AgentMemoryProposalSchema, AgentOutputMemorySchema;
|
|
47422
|
+
var AgentMemoryProposalSchema, AgentOutputMemorySchema, CuratorOutputMemoryDecisionSchema;
|
|
46647
47423
|
var init_agent_output_schema = __esm(() => {
|
|
46648
47424
|
init_zod();
|
|
46649
47425
|
init_schema2();
|
|
@@ -46666,11 +47442,9 @@ var init_agent_output_schema = __esm(() => {
|
|
|
46666
47442
|
AgentOutputMemorySchema = exports_external.object({
|
|
46667
47443
|
memoryProposals: exports_external.array(AgentMemoryProposalSchema).max(20).optional()
|
|
46668
47444
|
}).passthrough();
|
|
46669
|
-
|
|
46670
|
-
|
|
46671
|
-
|
|
46672
|
-
var init_role_profiles = __esm(() => {
|
|
46673
|
-
init_schema();
|
|
47445
|
+
CuratorOutputMemoryDecisionSchema = exports_external.object({
|
|
47446
|
+
curatorMemoryDecisions: exports_external.array(CuratorMemoryDecisionSchema).max(20).optional()
|
|
47447
|
+
}).passthrough();
|
|
46674
47448
|
});
|
|
46675
47449
|
|
|
46676
47450
|
// src/memory/recall-planner.ts
|