@effect-agent/storage-memory 0.1.0-beta.39 → 0.1.0-beta.41
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/index.d.mts +18 -2
- package/dist/index.mjs +261 -50
- package/dist/index.mjs.map +1 -1
- package/package.json +4 -4
- package/src/index.ts +1 -0
- package/src/semantic-memory-index.ts +320 -0
package/dist/index.d.mts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
|
+
import { MemoryIndexError, SemanticMemoryIndex, SemanticMemoryProfile } from "@effect-agent/core";
|
|
1
2
|
import { ScheduleStore, SourcePartition, SubmissionLedger, SubscriptionError, SubscriptionStore, ThreadStore } from "@effect-agent/thread";
|
|
2
|
-
import { Crypto, Effect, Layer, Option } from "effect";
|
|
3
|
+
import { Crypto, Effect, Layer, Option, Schema } from "effect";
|
|
3
4
|
//#region src/memory-ledger.d.ts
|
|
4
5
|
/** Construction options for the in-memory reference SubmissionLedger. */
|
|
5
6
|
interface MemorySubmissionLedgerOptions {
|
|
@@ -33,5 +34,20 @@ declare const MemoryThreadStoreLive: Layer.Layer<ThreadStore, never, Crypto.Cryp
|
|
|
33
34
|
*/
|
|
34
35
|
declare const MemoryStorageLive: Layer.Layer<ThreadStore, never, Crypto.Crypto>;
|
|
35
36
|
//#endregion
|
|
36
|
-
|
|
37
|
+
//#region src/semantic-memory-index.d.ts
|
|
38
|
+
declare const InMemorySemanticIndexCapacity_base: Schema.Class<InMemorySemanticIndexCapacity, Schema.Struct<{
|
|
39
|
+
readonly maxSources: Schema.Int;
|
|
40
|
+
readonly maxChunks: Schema.Int;
|
|
41
|
+
readonly maxSourceBytes: Schema.optionalKey<Schema.Int>;
|
|
42
|
+
}>, {}>;
|
|
43
|
+
/**
|
|
44
|
+
* Hard per-Layer bounds for disposable semantic index state. maxChunks times profile dimensions
|
|
45
|
+
* must not exceed 16,777,216 vector components. maxSourceBytes bounds the aggregate UTF-8 JSON
|
|
46
|
+
* of retained source identities and defaults to 16 MiB; it is not a general heap limit.
|
|
47
|
+
*/
|
|
48
|
+
declare class InMemorySemanticIndexCapacity extends InMemorySemanticIndexCapacity_base {}
|
|
49
|
+
/** Scoped disposable semantic index. No persistent build or recovery state is retained. */
|
|
50
|
+
declare const inMemorySemanticIndexLayer: (profile: SemanticMemoryProfile, capacity: InMemorySemanticIndexCapacity) => Layer.Layer<SemanticMemoryIndex, MemoryIndexError>;
|
|
51
|
+
//#endregion
|
|
52
|
+
export { InMemorySemanticIndexCapacity, MemoryScheduleStoreLive, MemoryStorageLive, MemorySubmissionLedgerLive, MemorySubmissionLedgerOptions, MemoryThreadStoreLive, inMemorySemanticIndexLayer, memoryScheduleStoreLayer, memorySubmissionLedgerLayer, memorySubscriptionStoreLayer };
|
|
37
53
|
//# sourceMappingURL=index.d.mts.map
|
package/dist/index.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { AttemptId, ReceiptId, SubmissionId, ThreadId } from "@effect-agent/core";
|
|
1
|
+
import { AttemptId, MemoryIndexCandidate, MemoryIndexError, MemoryIndexQuery, MemoryIndexReplacement, MemoryIndexSearch, MemoryIndexSource, MemoryKey, ReceiptId, SemanticMemoryChunk, SemanticMemoryIndex, SemanticMemoryProfile, SubmissionId, ThreadId } from "@effect-agent/core";
|
|
2
2
|
import { AbortCommand, AbortIntent, AcceptedEvent, AdmissionAdmitted, AdmissionConflict, AdmissionIndeterminate, AdmissionNotAdmitted, AdmissionRequest, AdmissionResult, AppendConflict, AppendResult, ApprovalConflict, ApprovalDecisionCommand, ApprovalDecisionIntent, AttachChildToReservationRequest, BeginChildBudgetReleaseRequest, CanonicalRecordEnvelope, CanonicalSequence, CheckpointRejected, ChildAttachmentSnapshot, ChildBudgetReservationRequest, ChildBudgetReservationSnapshot, ChildReservationConflict, ChildSettledNotification, Claim, ClaimJoiningRequest, ClaimRequest, DEFAULT_OWNERSHIP_LEASE_DURATION, DeliveryChange, Digest, EMPTY_TAIL_DIGEST, FenceRejected, FencedAppendRequest, InputAppliedMarker, JoinSnapshot, JoinedToHost, JoiningClaim, LedgerCapabilities, LedgerError, LoadCheckpointRequest, MarkInputAppliedRequest, MarkJoinedRequest, MarkReadyRequest, MarkUnknownRequest, ObservationOffset, OwnershipLost, OwnershipRenewal, OwnershipSnapshot, OwnershipToken, PersistedJson, ProducerEpoch, QueueSequence, RecoverySnapshot, RecoverySnapshotRequest, ReleaseChildBudgetRequest, ReleaseOwnershipRequest, RenewOwnershipRequest, ReservedChildBudget, ReservedSettlement, RevertJoiningRequest, SaveCheckpointRequest, ScheduleCapacityError, ScheduleChange, ScheduleConflict, ScheduleDueCursor, ScheduleFailpoint, ScheduleKey, ScheduleNotFound, ScheduleOwner, SchedulePageRequest, ScheduleRecord, ScheduleStorageError, ScheduleStore, Settlement, SettlementConflict, SettlementFinalization, SettlementReservation, SettlementReservationSnapshot, SourcePartition, SubmissionLedger, SubmissionLookup, SubmissionLookupByKey, SubmissionSnapshot, SubscriptionDelivery, SubscriptionDeliveryKey, SubscriptionError, SubscriptionFailpoint, SubscriptionKey, SubscriptionLimits, SubscriptionName, SubscriptionRecord, SubscriptionScanCursors, SubscriptionStore, SuspendRequest, SuspensionSnapshot, ThreadExport, ThreadExportRequest, ThreadMaterialization, ThreadNotMaterialized, ThreadObservation, ThreadRead, ThreadStore, ThreadStoreError, ThreadTail, ThreadTailRequest, UnknownResolution, UnknownResolutionCommand, UnknownResolutionConflict, UnknownResolutionIntent, applyScheduleChange, applySubscriptionDeliveryChange, compareScheduleKeys, compareScheduleNames, defaultSchedulingLimits, digestCanonicalBatch, scheduleDeadline, scheduleKeyOf, scheduleKeyString, scheduleOwnerKey, scheduleUsesCapacity, settlementFailureFromRecord, subscriptionCanSelect, subscriptionDeliveryCanSelect, subscriptionDeliveryKeyString, subscriptionKeyString } from "@effect-agent/thread";
|
|
3
3
|
import { Clock, Crypto, DateTime, Duration, Effect, Encoding, Layer, Option, PubSub, Ref, Result, Schema, Stream } from "effect";
|
|
4
4
|
//#region src/memory-ledger.ts
|
|
@@ -1151,22 +1151,22 @@ const memoryScheduleStoreLayer = () => Layer.effect(ScheduleStore, makeScheduleS
|
|
|
1151
1151
|
const MemoryScheduleStoreLive = memoryScheduleStoreLayer();
|
|
1152
1152
|
//#endregion
|
|
1153
1153
|
//#region src/memory-subscription-store.ts
|
|
1154
|
-
const error = (reason, code) => SubscriptionError.make({
|
|
1154
|
+
const error$1 = (reason, code) => SubscriptionError.make({
|
|
1155
1155
|
reason,
|
|
1156
1156
|
code
|
|
1157
1157
|
});
|
|
1158
1158
|
const samePartition = (left, right) => left.tenantId === right.tenantId && left.address === right.address;
|
|
1159
|
-
const sameSource = (left, right) => left.name === right.name && left.version === right.version;
|
|
1159
|
+
const sameSource$1 = (left, right) => left.name === right.name && left.version === right.version;
|
|
1160
1160
|
const encode = (schema, value, code) => Result.try({
|
|
1161
1161
|
try: () => Schema.encodeSync(Schema.fromJsonString(schema))(value),
|
|
1162
|
-
catch: () => error("corrupt", code)
|
|
1162
|
+
catch: () => error$1("corrupt", code)
|
|
1163
1163
|
});
|
|
1164
1164
|
const decode = (schema, value, code) => Result.try({
|
|
1165
1165
|
try: () => Schema.decodeSync(Schema.fromJsonString(schema))(value),
|
|
1166
|
-
catch: () => error("corrupt", code)
|
|
1166
|
+
catch: () => error$1("corrupt", code)
|
|
1167
1167
|
});
|
|
1168
1168
|
const decodeEffect = (schema, value, code) => Effect.fromResult(decode(schema, value, code));
|
|
1169
|
-
const validate$1 = (schema, value, code) => Schema.decodeUnknownEffect(schema)(value).pipe(Effect.mapError(() => error("validation", code)));
|
|
1169
|
+
const validate$1 = (schema, value, code) => Schema.decodeUnknownEffect(schema)(value).pipe(Effect.mapError(() => error$1("validation", code)));
|
|
1170
1170
|
const jsonBytes = (value) => new TextEncoder().encode(JSON.stringify(value)).byteLength;
|
|
1171
1171
|
const sameDeliveryIdentity = (left, right) => subscriptionDeliveryKeyString(left.key) === subscriptionDeliveryKeyString(right.key) && left.deliveryId === right.deliveryId && left.source.name === right.source.name && left.source.version === right.source.version && left.threadId === right.threadId && left.admissionKey === right.admissionKey && left.subscriptionFingerprint === right.subscriptionFingerprint && left.eventDigest === right.eventDigest;
|
|
1172
1172
|
const candidateIndexKey = (record) => JSON.stringify([
|
|
@@ -1179,8 +1179,8 @@ const eventCandidateIndexKey = (event) => JSON.stringify([
|
|
|
1179
1179
|
event.source.version,
|
|
1180
1180
|
event.matchingKey
|
|
1181
1181
|
]);
|
|
1182
|
-
const sameEventIdentity = (left, right) => samePartition(left.partition, right.partition) && left.eventId === right.eventId && sameSource(left.source, right.source) && left.matchingKey === right.matchingKey && left.payloadDigest === right.payloadDigest;
|
|
1183
|
-
const deliveryBelongsTo = (delivery, record, event) => subscriptionKeyString(delivery.key.subscription) === subscriptionKeyString(record.key) && delivery.key.eventId === event.eventId && sameSource(delivery.source, event.source);
|
|
1182
|
+
const sameEventIdentity = (left, right) => samePartition(left.partition, right.partition) && left.eventId === right.eventId && sameSource$1(left.source, right.source) && left.matchingKey === right.matchingKey && left.payloadDigest === right.payloadDigest;
|
|
1183
|
+
const deliveryBelongsTo = (delivery, record, event) => subscriptionKeyString(delivery.key.subscription) === subscriptionKeyString(record.key) && delivery.key.eventId === event.eventId && sameSource$1(delivery.source, event.source);
|
|
1184
1184
|
const makeMemorySubscriptionStore = Effect.fn("makeMemorySubscriptionStore")(function* (ownedPartition) {
|
|
1185
1185
|
const partition = yield* validate$1(SourcePartition, ownedPartition, "partition");
|
|
1186
1186
|
const state = yield* Ref.make({
|
|
@@ -1201,7 +1201,7 @@ const makeMemorySubscriptionStore = Effect.fn("makeMemorySubscriptionStore")(fun
|
|
|
1201
1201
|
}
|
|
1202
1202
|
});
|
|
1203
1203
|
const failpoint = yield* SubscriptionFailpoint;
|
|
1204
|
-
const requirePartition = (value, code) => samePartition(value.partition, partition) ? Effect.succeed(value) : Effect.fail(error("validation", code));
|
|
1204
|
+
const requirePartition = (value, code) => samePartition(value.partition, partition) ? Effect.succeed(value) : Effect.fail(error$1("validation", code));
|
|
1205
1205
|
const requireKey = (key, code) => validate$1(SubscriptionKey, key, code).pipe(Effect.flatMap((decoded) => requirePartition(decoded, code)));
|
|
1206
1206
|
const register = Effect.fn("MemorySubscriptionStore.register")(function* (input, inputLimits) {
|
|
1207
1207
|
const record = yield* validate$1(SubscriptionRecord, input, "register-record");
|
|
@@ -1214,14 +1214,14 @@ const makeMemorySubscriptionStore = Effect.fn("makeMemorySubscriptionStore")(fun
|
|
|
1214
1214
|
if (existingText !== void 0) {
|
|
1215
1215
|
const existing = decode(SubscriptionRecord, existingText, "register-existing");
|
|
1216
1216
|
if (Result.isFailure(existing)) return [Result.fail(existing.failure), current];
|
|
1217
|
-
return existing.success.creationFingerprint === record.creationFingerprint ? [Result.succeed(existing.success), current] : [Result.fail(error("conflict", "registration-identity")), current];
|
|
1217
|
+
return existing.success.creationFingerprint === record.creationFingerprint ? [Result.succeed(existing.success), current] : [Result.fail(error$1("conflict", "registration-identity")), current];
|
|
1218
1218
|
}
|
|
1219
|
-
if (jsonBytes(record.configuration.context) > limits.maxContextBytes) return [Result.fail(error("capacity", "context-bytes")), current];
|
|
1220
|
-
if (jsonBytes(record.configuration.parameters) > limits.maxPayloadBytes) return [Result.fail(error("capacity", "parameters-bytes")), current];
|
|
1221
|
-
if (record.configuration.expiresAtMillis - record.createdAtMillis > limits.maxLifetimeMillis) return [Result.fail(error("capacity", "lifetime")), current];
|
|
1222
|
-
if (current.registrations.size >= limits.maxRegistrations) return [Result.fail(error("capacity", "registrations")), current];
|
|
1219
|
+
if (jsonBytes(record.configuration.context) > limits.maxContextBytes) return [Result.fail(error$1("capacity", "context-bytes")), current];
|
|
1220
|
+
if (jsonBytes(record.configuration.parameters) > limits.maxPayloadBytes) return [Result.fail(error$1("capacity", "parameters-bytes")), current];
|
|
1221
|
+
if (record.configuration.expiresAtMillis - record.createdAtMillis > limits.maxLifetimeMillis) return [Result.fail(error$1("capacity", "lifetime")), current];
|
|
1222
|
+
if (current.registrations.size >= limits.maxRegistrations) return [Result.fail(error$1("capacity", "registrations")), current];
|
|
1223
1223
|
const ownerCount = current.ownerRegistrationCounts.get(record.key.ownerId) ?? 0;
|
|
1224
|
-
if (ownerCount >= limits.maxRegistrationsPerOwner) return [Result.fail(error("capacity", "owner-registrations")), current];
|
|
1224
|
+
if (ownerCount >= limits.maxRegistrationsPerOwner) return [Result.fail(error$1("capacity", "owner-registrations")), current];
|
|
1225
1225
|
const assigned = {
|
|
1226
1226
|
...record,
|
|
1227
1227
|
ordinal: current.sequence + 1
|
|
@@ -1260,13 +1260,13 @@ const makeMemorySubscriptionStore = Effect.fn("makeMemorySubscriptionStore")(fun
|
|
|
1260
1260
|
return text === void 0 ? null : yield* decodeEffect(SubscriptionRecord, text, "get-record");
|
|
1261
1261
|
});
|
|
1262
1262
|
const list = Effect.fn("MemorySubscriptionStore.list")(function* (ownerId, after, limit) {
|
|
1263
|
-
if (!Number.isSafeInteger(after) || after < 0 || !Number.isSafeInteger(limit) || limit <= 0) return yield* error("validation", "list-page");
|
|
1263
|
+
if (!Number.isSafeInteger(after) || after < 0 || !Number.isSafeInteger(limit) || limit <= 0) return yield* error$1("validation", "list-page");
|
|
1264
1264
|
const current = yield* Ref.get(state);
|
|
1265
1265
|
const records = [];
|
|
1266
1266
|
for (const [storageKey, indexed] of current.registrationIndex) {
|
|
1267
1267
|
if (indexed.key.ownerId !== ownerId || indexed.ordinal <= after) continue;
|
|
1268
1268
|
const text = current.registrations.get(storageKey);
|
|
1269
|
-
if (text === void 0) return yield* error("corrupt", "list-index");
|
|
1269
|
+
if (text === void 0) return yield* error$1("corrupt", "list-index");
|
|
1270
1270
|
records.push(yield* decodeEffect(SubscriptionRecord, text, "list-record"));
|
|
1271
1271
|
}
|
|
1272
1272
|
records.sort((a, b) => a.ordinal - b.ordinal);
|
|
@@ -1278,7 +1278,7 @@ const makeMemorySubscriptionStore = Effect.fn("makeMemorySubscriptionStore")(fun
|
|
|
1278
1278
|
const result = yield* Effect.uninterruptible(Ref.modify(state, (current) => {
|
|
1279
1279
|
const storageKey = subscriptionKeyString(key);
|
|
1280
1280
|
const text = current.registrations.get(storageKey);
|
|
1281
|
-
if (text === void 0) return [Result.fail(error("not-found", "subscription")), current];
|
|
1281
|
+
if (text === void 0) return [Result.fail(error$1("not-found", "subscription")), current];
|
|
1282
1282
|
const decoded = decode(SubscriptionRecord, text, "cancel-record");
|
|
1283
1283
|
if (Result.isFailure(decoded)) return [decoded, current];
|
|
1284
1284
|
if (decoded.success.state === "cancelled") return [Result.succeed(decoded.success), current];
|
|
@@ -1293,7 +1293,7 @@ const makeMemorySubscriptionStore = Effect.fn("makeMemorySubscriptionStore")(fun
|
|
|
1293
1293
|
registrations.set(storageKey, encoded.success);
|
|
1294
1294
|
const registrationIndex = new Map(current.registrationIndex);
|
|
1295
1295
|
const indexed = registrationIndex.get(storageKey);
|
|
1296
|
-
if (indexed === void 0) return [Result.fail(error("corrupt", "cancel-index")), current];
|
|
1296
|
+
if (indexed === void 0) return [Result.fail(error$1("corrupt", "cancel-index")), current];
|
|
1297
1297
|
registrationIndex.set(storageKey, {
|
|
1298
1298
|
...indexed,
|
|
1299
1299
|
state: "cancelled",
|
|
@@ -1318,10 +1318,10 @@ const makeMemorySubscriptionStore = Effect.fn("makeMemorySubscriptionStore")(fun
|
|
|
1318
1318
|
if (existingText !== void 0) {
|
|
1319
1319
|
const existing = decode(AcceptedEvent, existingText, "accept-existing");
|
|
1320
1320
|
if (Result.isFailure(existing)) return [Result.fail(existing.failure), current];
|
|
1321
|
-
return sameEventIdentity(existing.success, event) ? [Result.succeed(existing.success), current] : [Result.fail(error("conflict", "event-identity")), current];
|
|
1321
|
+
return sameEventIdentity(existing.success, event) ? [Result.succeed(existing.success), current] : [Result.fail(error$1("conflict", "event-identity")), current];
|
|
1322
1322
|
}
|
|
1323
|
-
if (jsonBytes(event.payload) > limits.maxPayloadBytes) return [Result.fail(error("capacity", "payload-bytes")), current];
|
|
1324
|
-
if (current.events.size >= limits.maxEvents) return [Result.fail(error("capacity", "events")), current];
|
|
1323
|
+
if (jsonBytes(event.payload) > limits.maxPayloadBytes) return [Result.fail(error$1("capacity", "payload-bytes")), current];
|
|
1324
|
+
if (current.events.size >= limits.maxEvents) return [Result.fail(error$1("capacity", "events")), current];
|
|
1325
1325
|
const accepted = {
|
|
1326
1326
|
...event,
|
|
1327
1327
|
cutoff: current.sequence + 1,
|
|
@@ -1362,15 +1362,15 @@ const makeMemorySubscriptionStore = Effect.fn("makeMemorySubscriptionStore")(fun
|
|
|
1362
1362
|
const accepted = yield* validate$1(AcceptedEvent, input, "candidates-event");
|
|
1363
1363
|
yield* requirePartition(accepted, "candidates-partition");
|
|
1364
1364
|
const stored = yield* event(accepted.eventId);
|
|
1365
|
-
if (stored === null || !sameEventIdentity(stored, accepted)) return yield* error(stored === null ? "not-found" : "conflict", "event");
|
|
1365
|
+
if (stored === null || !sameEventIdentity(stored, accepted)) return yield* error$1(stored === null ? "not-found" : "conflict", "event");
|
|
1366
1366
|
const current = yield* Ref.get(state);
|
|
1367
1367
|
const records = [];
|
|
1368
1368
|
for (const storageKey of current.candidateIndex.get(eventCandidateIndexKey(stored)) ?? []) {
|
|
1369
1369
|
const indexed = current.registrationIndex.get(storageKey);
|
|
1370
|
-
if (indexed === void 0) return yield* error("corrupt", "candidate-index");
|
|
1370
|
+
if (indexed === void 0) return yield* error$1("corrupt", "candidate-index");
|
|
1371
1371
|
if (indexed.ordinal <= stored.cursor || indexed.ordinal > stored.cutoff) continue;
|
|
1372
1372
|
const text = current.registrations.get(storageKey);
|
|
1373
|
-
if (text === void 0) return yield* error("corrupt", "candidate-record");
|
|
1373
|
+
if (text === void 0) return yield* error$1("corrupt", "candidate-record");
|
|
1374
1374
|
records.push(yield* decodeEffect(SubscriptionRecord, text, "candidate-record"));
|
|
1375
1375
|
}
|
|
1376
1376
|
records.sort((a, b) => a.ordinal - b.ordinal);
|
|
@@ -1385,13 +1385,13 @@ const makeMemorySubscriptionStore = Effect.fn("makeMemorySubscriptionStore")(fun
|
|
|
1385
1385
|
const effectiveNowMillis = Math.max(nowMillis, yield* Clock.currentTimeMillis);
|
|
1386
1386
|
yield* Effect.uninterruptible(Ref.modify(state, (current) => {
|
|
1387
1387
|
const eventText = current.events.get(suppliedEvent.eventId);
|
|
1388
|
-
if (eventText === void 0) return [Result.fail(error("not-found", "event")), current];
|
|
1388
|
+
if (eventText === void 0) return [Result.fail(error$1("not-found", "event")), current];
|
|
1389
1389
|
const decodedEvent = decode(AcceptedEvent, eventText, "select-event-record");
|
|
1390
1390
|
if (Result.isFailure(decodedEvent)) return [Result.fail(decodedEvent.failure), current];
|
|
1391
1391
|
const accepted = decodedEvent.success;
|
|
1392
|
-
if (!sameEventIdentity(accepted, suppliedEvent) || suppliedEvent.cursor !== accepted.cursor) return [Result.fail(error("conflict", "event-cursor")), current];
|
|
1393
|
-
if (accepted.routingComplete) return [complete && cursor === accepted.cursor ? Result.void : Result.fail(error("conflict", "routing-complete")), current];
|
|
1394
|
-
if (!Number.isSafeInteger(cursor) || cursor < accepted.cursor || cursor > accepted.cutoff) return [Result.fail(error("validation", "cursor")), current];
|
|
1392
|
+
if (!sameEventIdentity(accepted, suppliedEvent) || suppliedEvent.cursor !== accepted.cursor) return [Result.fail(error$1("conflict", "event-cursor")), current];
|
|
1393
|
+
if (accepted.routingComplete) return [complete && cursor === accepted.cursor ? Result.void : Result.fail(error$1("conflict", "routing-complete")), current];
|
|
1394
|
+
if (!Number.isSafeInteger(cursor) || cursor < accepted.cursor || cursor > accepted.cutoff) return [Result.fail(error$1("validation", "cursor")), current];
|
|
1395
1395
|
const additions = [];
|
|
1396
1396
|
const updates = [];
|
|
1397
1397
|
const additionIndex = [];
|
|
@@ -1399,17 +1399,17 @@ const makeMemorySubscriptionStore = Effect.fn("makeMemorySubscriptionStore")(fun
|
|
|
1399
1399
|
const owners = new Map(current.ownerDeliveryCounts);
|
|
1400
1400
|
for (const delivery of deliveries) {
|
|
1401
1401
|
const recordText = current.registrations.get(subscriptionKeyString(delivery.key.subscription));
|
|
1402
|
-
if (recordText === void 0) return [Result.fail(error("not-found", "subscription")), current];
|
|
1402
|
+
if (recordText === void 0) return [Result.fail(error$1("not-found", "subscription")), current];
|
|
1403
1403
|
const record = decode(SubscriptionRecord, recordText, "select-registration");
|
|
1404
1404
|
if (Result.isFailure(record)) return [Result.fail(record.failure), current];
|
|
1405
|
-
if (!deliveryBelongsTo(delivery, record.success, accepted) || !subscriptionDeliveryCanSelect(delivery, record.success, accepted) || record.success.ordinal <= accepted.cursor || record.success.ordinal > cursor) return [Result.fail(error("conflict", "selection")), current];
|
|
1405
|
+
if (!deliveryBelongsTo(delivery, record.success, accepted) || !subscriptionDeliveryCanSelect(delivery, record.success, accepted) || record.success.ordinal <= accepted.cursor || record.success.ordinal > cursor) return [Result.fail(error$1("conflict", "selection")), current];
|
|
1406
1406
|
if (!subscriptionCanSelect(record.success, accepted, effectiveNowMillis, false)) continue;
|
|
1407
1407
|
const deliveryKey = subscriptionDeliveryKeyString(delivery.key);
|
|
1408
1408
|
const existingText = current.deliveries.get(deliveryKey);
|
|
1409
1409
|
if (existingText !== void 0) {
|
|
1410
1410
|
const existing = decode(SubscriptionDelivery, existingText, "select-existing");
|
|
1411
1411
|
if (Result.isFailure(existing)) return [Result.fail(existing.failure), current];
|
|
1412
|
-
if (!sameDeliveryIdentity(existing.success, delivery)) return [Result.fail(error("conflict", "delivery-identity")), current];
|
|
1412
|
+
if (!sameDeliveryIdentity(existing.success, delivery)) return [Result.fail(error$1("conflict", "delivery-identity")), current];
|
|
1413
1413
|
continue;
|
|
1414
1414
|
}
|
|
1415
1415
|
const encodedDelivery = encode(SubscriptionDelivery, delivery, "select-delivery-encode");
|
|
@@ -1426,7 +1426,7 @@ const makeMemorySubscriptionStore = Effect.fn("makeMemorySubscriptionStore")(fun
|
|
|
1426
1426
|
]);
|
|
1427
1427
|
const ownerId = record.success.key.ownerId;
|
|
1428
1428
|
owners.set(ownerId, (owners.get(ownerId) ?? 0) + 1);
|
|
1429
|
-
if ((owners.get(ownerId) ?? 0) > limits.maxDeliveriesPerOwner) return [Result.fail(error("capacity", "owner-deliveries")), current];
|
|
1429
|
+
if ((owners.get(ownerId) ?? 0) > limits.maxDeliveriesPerOwner) return [Result.fail(error$1("capacity", "owner-deliveries")), current];
|
|
1430
1430
|
if (record.success.configuration.mode === "once") {
|
|
1431
1431
|
const consumed = {
|
|
1432
1432
|
...record.success,
|
|
@@ -1438,7 +1438,7 @@ const makeMemorySubscriptionStore = Effect.fn("makeMemorySubscriptionStore")(fun
|
|
|
1438
1438
|
const consumedKey = subscriptionKeyString(consumed.key);
|
|
1439
1439
|
updates.push([consumedKey, encodedRecord.success]);
|
|
1440
1440
|
const indexed = current.registrationIndex.get(consumedKey);
|
|
1441
|
-
if (indexed === void 0) return [Result.fail(error("corrupt", "selection-index")), current];
|
|
1441
|
+
if (indexed === void 0) return [Result.fail(error$1("corrupt", "selection-index")), current];
|
|
1442
1442
|
registrationUpdates.push([consumedKey, {
|
|
1443
1443
|
...indexed,
|
|
1444
1444
|
state: "consumed",
|
|
@@ -1446,7 +1446,7 @@ const makeMemorySubscriptionStore = Effect.fn("makeMemorySubscriptionStore")(fun
|
|
|
1446
1446
|
}]);
|
|
1447
1447
|
}
|
|
1448
1448
|
}
|
|
1449
|
-
if (current.deliveries.size + additions.length > limits.maxDeliveries) return [Result.fail(error("capacity", "deliveries")), current];
|
|
1449
|
+
if (current.deliveries.size + additions.length > limits.maxDeliveries) return [Result.fail(error$1("capacity", "deliveries")), current];
|
|
1450
1450
|
const registrations = new Map(current.registrations);
|
|
1451
1451
|
for (const [key, value] of updates) registrations.set(key, value);
|
|
1452
1452
|
const nextDeliveries = new Map(current.deliveries);
|
|
@@ -1493,23 +1493,23 @@ const makeMemorySubscriptionStore = Effect.fn("makeMemorySubscriptionStore")(fun
|
|
|
1493
1493
|
yield* Effect.uninterruptible(Ref.modify(state, (current) => {
|
|
1494
1494
|
const eventText = current.events.get(suppliedEvent.eventId);
|
|
1495
1495
|
const recordText = current.registrations.get(subscriptionKeyString(delivery.key.subscription));
|
|
1496
|
-
if (eventText === void 0 || recordText === void 0) return [Result.fail(error("not-found", eventText === void 0 ? "event" : "subscription")), current];
|
|
1496
|
+
if (eventText === void 0 || recordText === void 0) return [Result.fail(error$1("not-found", eventText === void 0 ? "event" : "subscription")), current];
|
|
1497
1497
|
const accepted = decode(AcceptedEvent, eventText, "catch-up-event-record");
|
|
1498
1498
|
if (Result.isFailure(accepted)) return [Result.fail(accepted.failure), current];
|
|
1499
1499
|
const record = decode(SubscriptionRecord, recordText, "catch-up-registration");
|
|
1500
1500
|
if (Result.isFailure(record)) return [Result.fail(record.failure), current];
|
|
1501
|
-
if (!sameEventIdentity(accepted.success, suppliedEvent) || !deliveryBelongsTo(delivery, record.success, accepted.success) || !subscriptionDeliveryCanSelect(delivery, record.success, accepted.success) || record.success.configuration.mode !== "once") return [Result.fail(error("conflict", "catch-up-identity")), current];
|
|
1501
|
+
if (!sameEventIdentity(accepted.success, suppliedEvent) || !deliveryBelongsTo(delivery, record.success, accepted.success) || !subscriptionDeliveryCanSelect(delivery, record.success, accepted.success) || record.success.configuration.mode !== "once") return [Result.fail(error$1("conflict", "catch-up-identity")), current];
|
|
1502
1502
|
const key = subscriptionDeliveryKeyString(delivery.key);
|
|
1503
1503
|
const existingText = current.deliveries.get(key);
|
|
1504
1504
|
if (existingText !== void 0) {
|
|
1505
1505
|
const existing = decode(SubscriptionDelivery, existingText, "catch-up-existing");
|
|
1506
1506
|
if (Result.isFailure(existing)) return [Result.fail(existing.failure), current];
|
|
1507
|
-
return sameDeliveryIdentity(existing.success, delivery) ? [Result.void, current] : [Result.fail(error("conflict", "delivery-identity")), current];
|
|
1507
|
+
return sameDeliveryIdentity(existing.success, delivery) ? [Result.void, current] : [Result.fail(error$1("conflict", "delivery-identity")), current];
|
|
1508
1508
|
}
|
|
1509
|
-
if (!subscriptionCanSelect(record.success, accepted.success, effectiveNowMillis, true)) return [Result.fail(error("conflict", "catch-up-eligibility")), current];
|
|
1510
|
-
if (current.deliveries.size >= limits.maxDeliveries) return [Result.fail(error("capacity", "deliveries")), current];
|
|
1509
|
+
if (!subscriptionCanSelect(record.success, accepted.success, effectiveNowMillis, true)) return [Result.fail(error$1("conflict", "catch-up-eligibility")), current];
|
|
1510
|
+
if (current.deliveries.size >= limits.maxDeliveries) return [Result.fail(error$1("capacity", "deliveries")), current];
|
|
1511
1511
|
const ownerCount = current.ownerDeliveryCounts.get(record.success.key.ownerId) ?? 0;
|
|
1512
|
-
if (ownerCount >= limits.maxDeliveriesPerOwner) return [Result.fail(error("capacity", "owner-deliveries")), current];
|
|
1512
|
+
if (ownerCount >= limits.maxDeliveriesPerOwner) return [Result.fail(error$1("capacity", "owner-deliveries")), current];
|
|
1513
1513
|
const encodedDelivery = encode(SubscriptionDelivery, delivery, "catch-up-delivery-encode");
|
|
1514
1514
|
if (Result.isFailure(encodedDelivery)) return [Result.fail(encodedDelivery.failure), current];
|
|
1515
1515
|
const consumed = {
|
|
@@ -1526,7 +1526,7 @@ const makeMemorySubscriptionStore = Effect.fn("makeMemorySubscriptionStore")(fun
|
|
|
1526
1526
|
registrations.set(consumedKey, encodedRecord.success);
|
|
1527
1527
|
const registrationIndex = new Map(current.registrationIndex);
|
|
1528
1528
|
const indexed = registrationIndex.get(consumedKey);
|
|
1529
|
-
if (indexed === void 0) return [Result.fail(error("corrupt", "catch-up-index")), current];
|
|
1529
|
+
if (indexed === void 0) return [Result.fail(error$1("corrupt", "catch-up-index")), current];
|
|
1530
1530
|
registrationIndex.set(consumedKey, {
|
|
1531
1531
|
...indexed,
|
|
1532
1532
|
state: "consumed",
|
|
@@ -1556,7 +1556,7 @@ const makeMemorySubscriptionStore = Effect.fn("makeMemorySubscriptionStore")(fun
|
|
|
1556
1556
|
yield* failpoint.hit("subscription:defer-event:before");
|
|
1557
1557
|
yield* Effect.uninterruptible(Ref.modify(state, (current) => {
|
|
1558
1558
|
const text = current.events.get(eventId);
|
|
1559
|
-
if (text === void 0) return [Result.fail(error("not-found", "event")), current];
|
|
1559
|
+
if (text === void 0) return [Result.fail(error$1("not-found", "event")), current];
|
|
1560
1560
|
const accepted = decode(AcceptedEvent, text, "defer-event-record");
|
|
1561
1561
|
if (Result.isFailure(accepted)) return [Result.fail(accepted.failure), current];
|
|
1562
1562
|
const updated = {
|
|
@@ -1570,7 +1570,7 @@ const makeMemorySubscriptionStore = Effect.fn("makeMemorySubscriptionStore")(fun
|
|
|
1570
1570
|
events.set(eventId, encoded.success);
|
|
1571
1571
|
const eventIndex = new Map(current.eventIndex);
|
|
1572
1572
|
const indexed = eventIndex.get(eventId);
|
|
1573
|
-
if (indexed === void 0) return [Result.fail(error("corrupt", "defer-event-index")), current];
|
|
1573
|
+
if (indexed === void 0) return [Result.fail(error$1("corrupt", "defer-event-index")), current];
|
|
1574
1574
|
eventIndex.set(eventId, {
|
|
1575
1575
|
...indexed,
|
|
1576
1576
|
nextAttemptAtMillis
|
|
@@ -1619,11 +1619,11 @@ const makeMemorySubscriptionStore = Effect.fn("makeMemorySubscriptionStore")(fun
|
|
|
1619
1619
|
const result = yield* Effect.uninterruptible(Ref.modify(state, (current) => {
|
|
1620
1620
|
const storageKey = subscriptionDeliveryKeyString(key);
|
|
1621
1621
|
const text = current.deliveries.get(storageKey);
|
|
1622
|
-
if (text === void 0) return [Result.fail(error("not-found", "delivery")), current];
|
|
1622
|
+
if (text === void 0) return [Result.fail(error$1("not-found", "delivery")), current];
|
|
1623
1623
|
const decoded = decode(SubscriptionDelivery, text, "change-delivery-record");
|
|
1624
1624
|
if (Result.isFailure(decoded)) return [decoded, current];
|
|
1625
1625
|
const registrationText = current.registrations.get(subscriptionKeyString(key.subscription));
|
|
1626
|
-
if (registrationText === void 0) return [Result.fail(error("corrupt", "delivery-registration")), current];
|
|
1626
|
+
if (registrationText === void 0) return [Result.fail(error$1("corrupt", "delivery-registration")), current];
|
|
1627
1627
|
const registration = decode(SubscriptionRecord, registrationText, "delivery-registration");
|
|
1628
1628
|
if (Result.isFailure(registration)) return [Result.fail(registration.failure), current];
|
|
1629
1629
|
const transition = applySubscriptionDeliveryChange(decoded.success, registration.success, deliveryId, effectiveChange);
|
|
@@ -1636,7 +1636,7 @@ const makeMemorySubscriptionStore = Effect.fn("makeMemorySubscriptionStore")(fun
|
|
|
1636
1636
|
deliveries.set(storageKey, encoded.success);
|
|
1637
1637
|
const deliveryIndex = new Map(current.deliveryIndex);
|
|
1638
1638
|
const indexed = deliveryIndex.get(storageKey);
|
|
1639
|
-
if (indexed === void 0) return [Result.fail(error("corrupt", "delivery-index")), current];
|
|
1639
|
+
if (indexed === void 0) return [Result.fail(error$1("corrupt", "delivery-index")), current];
|
|
1640
1640
|
deliveryIndex.set(storageKey, {
|
|
1641
1641
|
...indexed,
|
|
1642
1642
|
state: updated.state,
|
|
@@ -1666,7 +1666,7 @@ const makeMemorySubscriptionStore = Effect.fn("makeMemorySubscriptionStore")(fun
|
|
|
1666
1666
|
yield* Effect.uninterruptible(Ref.modify(state, (current) => {
|
|
1667
1667
|
const storageKey = subscriptionKeyString(key);
|
|
1668
1668
|
const text = current.registrations.get(storageKey);
|
|
1669
|
-
if (text === void 0) return [Result.fail(error("not-found", "subscription")), current];
|
|
1669
|
+
if (text === void 0) return [Result.fail(error$1("not-found", "subscription")), current];
|
|
1670
1670
|
const record = decode(SubscriptionRecord, text, "defer-recovery-record");
|
|
1671
1671
|
if (Result.isFailure(record)) return [Result.fail(record.failure), current];
|
|
1672
1672
|
const updated = {
|
|
@@ -1679,7 +1679,7 @@ const makeMemorySubscriptionStore = Effect.fn("makeMemorySubscriptionStore")(fun
|
|
|
1679
1679
|
registrations.set(storageKey, encoded.success);
|
|
1680
1680
|
const registrationIndex = new Map(current.registrationIndex);
|
|
1681
1681
|
const indexed = registrationIndex.get(storageKey);
|
|
1682
|
-
if (indexed === void 0) return [Result.fail(error("corrupt", "recovery-index")), current];
|
|
1682
|
+
if (indexed === void 0) return [Result.fail(error$1("corrupt", "recovery-index")), current];
|
|
1683
1683
|
registrationIndex.set(storageKey, {
|
|
1684
1684
|
...indexed,
|
|
1685
1685
|
recoveryAt: updated.recovery?.nextAttemptAtMillis ?? null
|
|
@@ -2042,6 +2042,217 @@ const MemoryThreadStoreLive = Layer.effect(ThreadStore, makeThreadStore);
|
|
|
2042
2042
|
*/
|
|
2043
2043
|
const MemoryStorageLive = MemoryThreadStoreLive;
|
|
2044
2044
|
//#endregion
|
|
2045
|
-
|
|
2045
|
+
//#region src/semantic-memory-index.ts
|
|
2046
|
+
const PositiveCapacity = Schema.Int.check(Schema.isBetween({
|
|
2047
|
+
minimum: 1,
|
|
2048
|
+
maximum: 65536
|
|
2049
|
+
}));
|
|
2050
|
+
const MaxStoredVectorComponents = 16777216;
|
|
2051
|
+
/**
|
|
2052
|
+
* Hard per-Layer bounds for disposable semantic index state. maxChunks times profile dimensions
|
|
2053
|
+
* must not exceed 16,777,216 vector components. maxSourceBytes bounds the aggregate UTF-8 JSON
|
|
2054
|
+
* of retained source identities and defaults to 16 MiB; it is not a general heap limit.
|
|
2055
|
+
*/
|
|
2056
|
+
var InMemorySemanticIndexCapacity = class extends Schema.Class("@effect-agent/storage-memory/InMemorySemanticIndexCapacity")({
|
|
2057
|
+
maxSources: PositiveCapacity,
|
|
2058
|
+
maxChunks: PositiveCapacity,
|
|
2059
|
+
maxSourceBytes: Schema.optionalKey(Schema.Int.check(Schema.isBetween({
|
|
2060
|
+
minimum: 1,
|
|
2061
|
+
maximum: 67108864
|
|
2062
|
+
})))
|
|
2063
|
+
}) {};
|
|
2064
|
+
const sameProfile = Schema.toEquivalence(SemanticMemoryProfile);
|
|
2065
|
+
const sameSource = Schema.toEquivalence(MemoryIndexSource.Wire);
|
|
2066
|
+
const error = (operation, reason) => MemoryIndexError.make({
|
|
2067
|
+
operation,
|
|
2068
|
+
reason
|
|
2069
|
+
});
|
|
2070
|
+
const keyString = (key) => JSON.stringify([key.namespace.address, key.id]);
|
|
2071
|
+
const sourceIdentityBytes = (source) => Encoding.encodeHex(JSON.stringify(source)).length / 2;
|
|
2072
|
+
const decodeBoundary = Effect.fn("InMemorySemanticIndex.decodeBoundary")(function* (schema, value, operation) {
|
|
2073
|
+
return yield* Schema.decodeUnknownEffect(schema)(value).pipe(Effect.flatMap((decoded) => Schema.encodeEffect(schema)(decoded).pipe(Effect.as(decoded))), Effect.mapError(() => error(operation, "invalid-input")));
|
|
2074
|
+
});
|
|
2075
|
+
const freezeSource = (source) => Object.freeze(MemoryIndexSource.make({
|
|
2076
|
+
key: Object.freeze(MemoryKey.make({
|
|
2077
|
+
...source.key,
|
|
2078
|
+
namespace: Object.freeze({ address: source.key.namespace.address })
|
|
2079
|
+
})),
|
|
2080
|
+
source: Object.freeze({ ...source.source }),
|
|
2081
|
+
sourceGeneration: source.sourceGeneration
|
|
2082
|
+
}));
|
|
2083
|
+
const freezeChunk = (chunk) => Object.freeze(SemanticMemoryChunk.make({
|
|
2084
|
+
...chunk,
|
|
2085
|
+
vector: Object.freeze([...chunk.vector])
|
|
2086
|
+
}));
|
|
2087
|
+
const sourceIsFenced = (source, existing) => source.sourceGeneration < existing.source.sourceGeneration || source.sourceGeneration === existing.source.sourceGeneration && !sameSource(source, existing.source);
|
|
2088
|
+
const squaredNorm = (vector) => {
|
|
2089
|
+
let sum = 0;
|
|
2090
|
+
for (const value of vector) {
|
|
2091
|
+
sum += value * value;
|
|
2092
|
+
if (!Number.isFinite(sum)) return null;
|
|
2093
|
+
}
|
|
2094
|
+
return sum > 0 ? sum : null;
|
|
2095
|
+
};
|
|
2096
|
+
const validVector = (vector, profile) => vector.length === profile.dimensions && squaredNorm(vector) !== null;
|
|
2097
|
+
const validateChunks = Effect.fn("InMemorySemanticIndex.validateChunks")(function* (chunks, profile, operation) {
|
|
2098
|
+
let nextByte = 0;
|
|
2099
|
+
const passageIds = /* @__PURE__ */ new Set();
|
|
2100
|
+
for (let index = 0; index < chunks.length; index++) {
|
|
2101
|
+
const chunk = chunks[index];
|
|
2102
|
+
const byteLength = Encoding.encodeHex(chunk.text).length / 2;
|
|
2103
|
+
if (chunk.ordinal !== index || chunk.startByte !== nextByte || chunk.endByte <= chunk.startByte || chunk.endByte - chunk.startByte !== byteLength || byteLength > profile.maxChunkBytes || passageIds.has(chunk.passageId) || !validVector(chunk.vector, profile)) return yield* error(operation, "invalid-input");
|
|
2104
|
+
passageIds.add(chunk.passageId);
|
|
2105
|
+
nextByte = chunk.endByte;
|
|
2106
|
+
}
|
|
2107
|
+
});
|
|
2108
|
+
const cosine = (left, right) => {
|
|
2109
|
+
const leftNorm = Math.sqrt(squaredNorm(left) ?? 1);
|
|
2110
|
+
const rightNorm = Math.sqrt(squaredNorm(right) ?? 1);
|
|
2111
|
+
let score = 0;
|
|
2112
|
+
for (let index = 0; index < left.length; index++) score += left[index] / leftNorm * (right[index] / rightNorm);
|
|
2113
|
+
const bounded = Math.max(-1, Math.min(1, score));
|
|
2114
|
+
return bounded === 0 ? 0 : bounded;
|
|
2115
|
+
};
|
|
2116
|
+
const compareText = (left, right) => left < right ? -1 : left > right ? 1 : 0;
|
|
2117
|
+
const makeIndex = Effect.fn("InMemorySemanticIndex.make")(function* (rawProfile, rawCapacity) {
|
|
2118
|
+
const profile = Object.freeze(SemanticMemoryProfile.make({ ...yield* decodeBoundary(SemanticMemoryProfile, rawProfile, "configure semantic memory index") }));
|
|
2119
|
+
const capacity = yield* decodeBoundary(InMemorySemanticIndexCapacity, rawCapacity, "configure semantic memory index");
|
|
2120
|
+
if (capacity.maxChunks * profile.dimensions > MaxStoredVectorComponents) return yield* error("configure semantic memory index", "invalid-input");
|
|
2121
|
+
const maxSourceBytes = capacity.maxSourceBytes ?? 16777216;
|
|
2122
|
+
const data = yield* Ref.make({
|
|
2123
|
+
closed: false,
|
|
2124
|
+
entries: /* @__PURE__ */ new Map(),
|
|
2125
|
+
sourceBytes: 0
|
|
2126
|
+
});
|
|
2127
|
+
yield* Effect.addFinalizer(() => Ref.set(data, {
|
|
2128
|
+
closed: true,
|
|
2129
|
+
entries: /* @__PURE__ */ new Map(),
|
|
2130
|
+
sourceBytes: 0
|
|
2131
|
+
}));
|
|
2132
|
+
const ensureOpen = Effect.fn("InMemorySemanticIndex.ensureOpen")(function* (operation) {
|
|
2133
|
+
if ((yield* Ref.get(data)).closed) return yield* error(operation, "unavailable");
|
|
2134
|
+
});
|
|
2135
|
+
const replace = Effect.fn("InMemorySemanticIndex.replace")(function* (rawRequest) {
|
|
2136
|
+
const operation = "replace semantic memory source";
|
|
2137
|
+
yield* ensureOpen(operation);
|
|
2138
|
+
const request = yield* decodeBoundary(MemoryIndexReplacement.Wire, rawRequest, operation);
|
|
2139
|
+
const source = freezeSource(request.source);
|
|
2140
|
+
const sourceBytes = sourceIdentityBytes(source);
|
|
2141
|
+
const chunks = Object.freeze(request.chunks.map(freezeChunk));
|
|
2142
|
+
if (source.source.id !== source.key.id) return yield* error(operation, "invalid-input");
|
|
2143
|
+
if (!sameProfile(request.profile, profile)) return yield* error(operation, "incompatible");
|
|
2144
|
+
yield* validateChunks(chunks, profile, operation);
|
|
2145
|
+
const indexedAt = yield* Clock.currentTimeMillis;
|
|
2146
|
+
const failure = yield* Ref.modify(data, (current) => {
|
|
2147
|
+
if (current.closed) return [error(operation, "unavailable"), current];
|
|
2148
|
+
const id = keyString(source.key);
|
|
2149
|
+
const existing = current.entries.get(id);
|
|
2150
|
+
if (existing !== void 0 && (existing._tag === "Withdrawn" || sourceIsFenced(source, existing))) return [error(operation, "fenced"), current];
|
|
2151
|
+
if (existing === void 0 && current.entries.size >= capacity.maxSources) return [error(operation, "budget"), current];
|
|
2152
|
+
const nextSourceBytes = current.sourceBytes - (existing?.sourceBytes ?? 0) + sourceBytes;
|
|
2153
|
+
if (nextSourceBytes > maxSourceBytes) return [error(operation, "budget"), current];
|
|
2154
|
+
let count = chunks.length;
|
|
2155
|
+
for (const [entryId, entry] of current.entries) if (entryId !== id && entry._tag === "Indexed") count += entry.chunks.length;
|
|
2156
|
+
if (count > capacity.maxChunks) return [error(operation, "budget"), current];
|
|
2157
|
+
const entries = new Map(current.entries);
|
|
2158
|
+
entries.set(id, {
|
|
2159
|
+
_tag: "Indexed",
|
|
2160
|
+
source,
|
|
2161
|
+
sourceBytes,
|
|
2162
|
+
chunks,
|
|
2163
|
+
indexedAt
|
|
2164
|
+
});
|
|
2165
|
+
return [void 0, {
|
|
2166
|
+
...current,
|
|
2167
|
+
entries,
|
|
2168
|
+
sourceBytes: nextSourceBytes
|
|
2169
|
+
}];
|
|
2170
|
+
});
|
|
2171
|
+
if (failure !== void 0) return yield* failure;
|
|
2172
|
+
});
|
|
2173
|
+
const withdraw = Effect.fn("InMemorySemanticIndex.withdraw")(function* (rawSource) {
|
|
2174
|
+
const operation = "withdraw semantic memory source";
|
|
2175
|
+
yield* ensureOpen(operation);
|
|
2176
|
+
const source = freezeSource(yield* decodeBoundary(MemoryIndexSource.Wire, rawSource, operation));
|
|
2177
|
+
const sourceBytes = sourceIdentityBytes(source);
|
|
2178
|
+
if (source.source.id !== source.key.id) return yield* error(operation, "invalid-input");
|
|
2179
|
+
const failure = yield* Ref.modify(data, (current) => {
|
|
2180
|
+
if (current.closed) return [error(operation, "unavailable"), current];
|
|
2181
|
+
const id = keyString(source.key);
|
|
2182
|
+
const existing = current.entries.get(id);
|
|
2183
|
+
if (existing !== void 0) {
|
|
2184
|
+
if (existing._tag === "Withdrawn") return [sameSource(source, existing.source) ? void 0 : error(operation, "fenced"), current];
|
|
2185
|
+
if (sourceIsFenced(source, existing)) return [error(operation, "fenced"), current];
|
|
2186
|
+
} else if (current.entries.size >= capacity.maxSources) return [error(operation, "budget"), current];
|
|
2187
|
+
const nextSourceBytes = current.sourceBytes - (existing?.sourceBytes ?? 0) + sourceBytes;
|
|
2188
|
+
if (nextSourceBytes > maxSourceBytes) return [error(operation, "budget"), current];
|
|
2189
|
+
const entries = new Map(current.entries);
|
|
2190
|
+
entries.set(id, {
|
|
2191
|
+
_tag: "Withdrawn",
|
|
2192
|
+
source,
|
|
2193
|
+
sourceBytes
|
|
2194
|
+
});
|
|
2195
|
+
return [void 0, {
|
|
2196
|
+
...current,
|
|
2197
|
+
entries,
|
|
2198
|
+
sourceBytes: nextSourceBytes
|
|
2199
|
+
}];
|
|
2200
|
+
});
|
|
2201
|
+
if (failure !== void 0) return yield* failure;
|
|
2202
|
+
});
|
|
2203
|
+
const search = Effect.fn("InMemorySemanticIndex.search")(function* (rawQuery) {
|
|
2204
|
+
const operation = "search semantic memory index";
|
|
2205
|
+
yield* ensureOpen(operation);
|
|
2206
|
+
const query = yield* decodeBoundary(MemoryIndexQuery.Wire, rawQuery, operation);
|
|
2207
|
+
const vector = Object.freeze([...query.vector]);
|
|
2208
|
+
if (!validVector(vector, profile)) return yield* error(operation, "invalid-input");
|
|
2209
|
+
const current = yield* Ref.get(data);
|
|
2210
|
+
if (current.closed) return yield* error(operation, "unavailable");
|
|
2211
|
+
let scannedChunks = 0;
|
|
2212
|
+
let inspectedSources = 0;
|
|
2213
|
+
const candidates = [];
|
|
2214
|
+
for (const entry of current.entries.values()) {
|
|
2215
|
+
inspectedSources += 1;
|
|
2216
|
+
if (inspectedSources % 128 === 0) yield* Effect.yieldNow;
|
|
2217
|
+
if (entry.source.key.namespace.address !== query.namespace.address || entry._tag !== "Indexed") continue;
|
|
2218
|
+
scannedChunks += entry.chunks.length;
|
|
2219
|
+
if (scannedChunks > query.maxScannedChunks) return yield* error(operation, "budget");
|
|
2220
|
+
}
|
|
2221
|
+
for (const entry of current.entries.values()) {
|
|
2222
|
+
if (entry.source.key.namespace.address !== query.namespace.address || entry._tag !== "Indexed") continue;
|
|
2223
|
+
yield* Effect.yieldNow;
|
|
2224
|
+
for (const chunk of entry.chunks) {
|
|
2225
|
+
const score = cosine(vector, chunk.vector);
|
|
2226
|
+
if (score < query.minScore) continue;
|
|
2227
|
+
candidates.push(MemoryIndexCandidate.make({
|
|
2228
|
+
...entry.source,
|
|
2229
|
+
passageId: chunk.passageId,
|
|
2230
|
+
ordinal: chunk.ordinal,
|
|
2231
|
+
startByte: chunk.startByte,
|
|
2232
|
+
endByte: chunk.endByte,
|
|
2233
|
+
text: chunk.text,
|
|
2234
|
+
score,
|
|
2235
|
+
indexedAt: entry.indexedAt
|
|
2236
|
+
}));
|
|
2237
|
+
}
|
|
2238
|
+
}
|
|
2239
|
+
candidates.sort((left, right) => right.score - left.score || compareText(left.key.id, right.key.id) || compareText(left.source.revision, right.source.revision) || left.ordinal - right.ordinal);
|
|
2240
|
+
yield* ensureOpen(operation);
|
|
2241
|
+
return MemoryIndexSearch.make({
|
|
2242
|
+
candidates: candidates.slice(0, query.limit),
|
|
2243
|
+
scannedChunks
|
|
2244
|
+
});
|
|
2245
|
+
});
|
|
2246
|
+
return SemanticMemoryIndex.fromAdapter({
|
|
2247
|
+
profile,
|
|
2248
|
+
replace,
|
|
2249
|
+
withdraw,
|
|
2250
|
+
search
|
|
2251
|
+
});
|
|
2252
|
+
});
|
|
2253
|
+
/** Scoped disposable semantic index. No persistent build or recovery state is retained. */
|
|
2254
|
+
const inMemorySemanticIndexLayer = (profile, capacity) => Layer.effect(SemanticMemoryIndex, makeIndex(profile, capacity));
|
|
2255
|
+
//#endregion
|
|
2256
|
+
export { InMemorySemanticIndexCapacity, MemoryScheduleStoreLive, MemoryStorageLive, MemorySubmissionLedgerLive, MemoryThreadStoreLive, inMemorySemanticIndexLayer, memoryScheduleStoreLayer, memorySubmissionLedgerLayer, memorySubscriptionStoreLayer };
|
|
2046
2257
|
|
|
2047
2258
|
//# sourceMappingURL=index.mjs.map
|