@effect-agent/storage-memory 0.1.0-beta.39 → 0.1.0-beta.40

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 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
- export { MemoryScheduleStoreLive, MemoryStorageLive, MemorySubmissionLedgerLive, MemorySubmissionLedgerOptions, MemoryThreadStoreLive, memoryScheduleStoreLayer, memorySubmissionLedgerLayer, memorySubscriptionStoreLayer };
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
- export { MemoryScheduleStoreLive, MemoryStorageLive, MemorySubmissionLedgerLive, MemoryThreadStoreLive, memoryScheduleStoreLayer, memorySubmissionLedgerLayer, memorySubscriptionStoreLayer };
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